【问题标题】:Small Issue with C program to convert lowercase to uppercase for stdoutC程序将小写转换为大写以用于标准输出的小问题
【发布时间】:2019-10-04 03:43:40
【问题描述】:

我正在学习 linux 中的系统调用,我编写了一个快速程序来将标准输入复制到标准输出。

我想在写入之前将标准输入小写字母转换为大写字母。

我用指向数组的指针实现了一个函数来大写字符。它只大写写的第一个字母,我不明白为什么。据我了解,由于 read() 系统调用,我不需要 for 循环。

#include <unistd.h>
#define SIZE 512
char charToUpper(char *);

int main () {
    int nread;
    char buf[SIZE];
    while (nread = read(0, buf , SIZE)) {
        charToUpper(buf);
        write(1,buf,nread);
    }
    return 0;
}

char charToUpper(char *a){
    if ((*a > 96) && (*a <123)) {
        *a = *a-32;
        return *a;
    }
}

【问题讨论】:

    标签: c linux char buffer std


    【解决方案1】:

    您的charToUpper 收到一个指向char 的指针,然后您将它发送给buf,它衰减为指向char 的指针,该指针位于buf 中的第一个字符,因此是您的结果。

    请记住,在c 中,您不会免费获得要传递的数组的大小 - 您也必须传递它。考虑您在charToUpper 中的所有操作都在*a 上,它的类型为char,单个字符。因此,要解决此问题,请将声明更改为

    char charToUpper(char *, unsigned int size);
    

    所以知道你知道你实际阅读了多少个字符并且需要更改。现在尝试更改您的程序以适应这种情况。一个提示 - 例如,您的 return 可能必须移动。

    【讨论】:

      【解决方案2】:

      以下建议代码:

      1. 干净编译
      2. 正确终止输入的字符数组
      3. 正确地将所有小写字符更改为大写,使用工具:toupper() 来自头文件:ctype.h
      4. 执行所需的功能

      现在,建议的代码:

      #include <unistd.h>
      #include <ctype.h>   // toupper()
      
      #define SIZE 512
      
      void charToUpper(char *);
      
      int main ( void ) 
      {
          ssize_t nread;
          char buf[SIZE];
          while ( (nread = read(0, buf , SIZE) ) > 0) 
          {
              // NUL terminate the character string
              buf[nread] = '\0';
      
              // convert all characters to uppercase
              charToUpper(buf);
      
              // output the (all uppercase) string to stdout
              write(1,buf, (size_t)nread);
          }
          return 0;
      }
      
      
      void charToUpper( char buf[] )
      {
          for( size_t i = 0; buf[i]; i++ )
          {
              buf[i] = (char)toupper( buf[i] );
          }
      
      }
      

      【讨论】:

      • 如果您读取完整的缓冲区(例如,您从文件中读取,而不是从终端读取),此程序将出现缓冲区溢出 您将 \0 字符放在 @ 末尾仅一个字符987654325@。请更正这一点,因为这是一个错误。
      【解决方案3】:

      除了循环部分外,他的程序都很好。

      char* charToUpper(char *a){
          char *t=p;
          while(*a!='\0'){
          if ((*a > 96) && (*a <123)) 
              *a = *a-32;
          a++;
          }
          return t;
      }
      

      你没有增加循环。这样做你就会得到

      【讨论】:

      • 如果你使用read(),你不会得到一个空终止的字符串......所以你不能用while(*a != '\0')检查while循环你的样本是不正确的原因...... .请更正。您必须传递实际读取字节数并改为使用while (n--)
      【解决方案4】:

      好吧,通过自己缓冲输入数据,您的事情变得过于复杂,而您可以使用 getchar()putchar() 已经缓冲的函数。同样使用数字而不是字符文字,隐藏了代码的实际目标(转换为大写,反对在代码中添加减去奇怪的魔法值),并将其与 ASCII 字符代码环境联系起来:

      #include <stdio.h>
      
      int main()
      {
          int c;
          while((c = getchar()) != EOF) {
              if (c >= 'a' && c <= 'z')  /* char literals are your friends */
                  c += 'A' - 'a';        /* also here                      */
              putchar(c);
          }
          return 0;
      }
      

      这个 sn-p 代码将完全按照您的尝试执行,透明地缓冲输入和输出,并以一种可移植到具有不同字符编码的其他环境的方式。毫无疑问,更好的方法是:

      #include <stdio.h>
      #include <ctype.h>
      
      int main()
      {
          int c;
          while((c = getchar()) != EOF) {
              putchar(toupper(c));
          }
          return 0;
      }
      

      如果你用一个大文本文件测试这两个程序,你会发现这个程序的响应比你写的那个更好,因为标准库已经自动为你选择了最佳的读写缓冲区大小,基于在传递给它的文件描述符上,而不是您在程序中使用的固定缓冲区大小(512 字节)。

      在您的代码中,您将缓冲区指针传递给您的函数,它只会将其第一个字符大写...仅此而已,仅此而已,因此您只会获得每行的第一个字符(以防您的输入来自终端,因为输入在以规范模式从终端读取时在每一行结束)或每个 512 字节块的第一个字符,以防您从文件中读取。

      为了让你的函数工作,你应该传递缓冲区和它的大小,因为它里面的实际读取数据量是未知的,你需要在里面放一个for循环来处理每个字符。 .或者在函数外做循环,对缓冲区的每个字符位置调用函数,由read(2)填充。

      如果您想自己进行缓冲,如示例代码中所示,您必须输入实际读取字符的长度并转换例程中传递的数量,如下所示:

      #include <unistd.h>
      #include <stdio.h> /* for printing errors to stderr */
      #include <string.h> /* for strerror */
      #include <errno.h> /* for errno definition */
      
      #define SIZE 512
      
      void charToUpper(char *, size_t);
      
      int main () {
          ssize_t nread, nwritten;
          char buf[SIZE];
          while ((nread = read(0, buf , SIZE)) > 0) {
              charToUpper(buf, nread);
              nwritten = write(1, buf, nread);
              if (nwritten < 0) {  /* check for writing errors */
                  fprintf(stderr,
                      "Error: write: %s\n",
                      strerror(errno));
                  return 1;  /* write error */ 
              }
          }
          if (nread < 0) {  /* check for reading errors */
              fprintf(stderr,
                  "Error: read: %s\n",
                  strerror(errno));
              return 2; /* read error */
          }
          return 0; /* no error */
      }
      
      void charToUpper(char *a, size_t sz){  /* better declare it void, as we don't return anything */
      
          /* this code assumes uppercase chars and lower case are together in the
           * char map, and contiguous (this is false in EBCDIC mappings) so better
           * to use toupper(*a) in all cases */
          for(;sz--; a++) {  /* for every char in a, up to sz chars. */
              if ((*a >= 'a') && (*a <= 'z')) {  /* if *a is lower case letter */
                  *a += 'A' - 'a'; /* convert to uppercase */
                  /* better if you use *a = toupper(*a); */
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-21
        • 1970-01-01
        • 1970-01-01
        • 2010-11-15
        相关资源
        最近更新 更多