将带有getchar的char*输出到printf

将带有getchar的char*输出到printf,c,printf,getchar,cc,C,Printf,Getchar,Cc,我正在为即将到来的一堂课扫除我的C技能,在使用getchar构建字符串之后,我在printf中遇到了这个奇怪的输出。具体来说,我试图输出的任何字符串都会在每个字母后面附加相同的字符序列foo使用cc编译,使用Apple LLVM 5.0(Xcode>)编译,变成“f?8{o?8{o?8}?”。下面是说明问题的示例代码: char * input_buffer = malloc( sizeof( char ) ); char c; while ( ( c = getchar() ) != '\n

我正在为即将到来的一堂课扫除我的C技能,在使用
getchar
构建字符串之后,我在
printf
中遇到了这个奇怪的输出。具体来说,我试图输出的任何字符串都会在每个字母后面附加相同的字符序列
foo
使用
cc
编译,使用
Apple LLVM 5.0
(Xcode>)编译,变成
“f?8{o?8{o?8}?”
。下面是说明问题的示例代码:

char * input_buffer = malloc( sizeof( char ) );

char c;
while ( ( c = getchar() ) != '\n' ) {
    strcat(input_buffer, &c);
}

// problem output
printf( "\n%s\n", input_buffer );
// foo -> f¿:¿o¿:¿0¿:¿

// weird side effect is the 4 is required to get a proper len
printf("\ncharacters: %lu\n", strlen( input_buffer ) / 4 );
我到处都搜索过,但在其他任何地方都看不到,但这似乎有点像边缘情况。这是我没有考虑的某种编码问题吗?

  • 您只为一个
    char
    分配空间给
    input\u buffer
  • strcat(input_buffer,&c);
    错误。您正在将字符(不是以null结尾的)与字符串连接起来
  • getchar
    返回
    int
    类型,但您声明
    c
    属于
    char
    类型
      • 您只为一个
        char
        分配空间给
        input\u buffer
      • strcat(input_buffer,&c);
        错误。您正在将字符(不是以null结尾的)与字符串连接起来
      • getchar
        返回
        int
        类型,但您声明
        c
        属于
        char
        类型

      您不能调用
      strcat(输入缓冲区,&c);

      传递给strcat的每个参数必须是一个有效的以null结尾的字符串

      &c
      之后的下一个字节为0的可能性非常小

      input\u buffer
      指向的第一个字节变为0的可能性也不是很高

      换句话说,
      strcat
      读取“垃圾”,直到它在两个参数中都遇到一个0字符,

      更改:

      while ( ( c = getchar() ) != '\n' ) {
          strcat(input_buffer, &c);
      }
      
      for (int i=0; 1; i++)
      {
          c = getchar();
          if (c == '\r' || c == '\n')
          {
              input_buffer[i] = 0;
              break;
          }
          input_buffer[i] = c;
      }
      
      至:

      while ( ( c = getchar() ) != '\n' ) {
          strcat(input_buffer, &c);
      }
      
      for (int i=0; 1; i++)
      {
          c = getchar();
          if (c == '\r' || c == '\n')
          {
              input_buffer[i] = 0;
              break;
          }
          input_buffer[i] = c;
      }
      

      不能调用strcat(输入缓冲区,&c)

      传递给strcat的每个参数必须是一个有效的以null结尾的字符串

      &c
      之后的下一个字节为0的可能性非常小

      input\u buffer
      指向的第一个字节变为0的可能性也不是很高

      换句话说,
      strcat
      读取“垃圾”,直到它在两个参数中都遇到一个0字符,

      更改:

      while ( ( c = getchar() ) != '\n' ) {
          strcat(input_buffer, &c);
      }
      
      for (int i=0; 1; i++)
      {
          c = getchar();
          if (c == '\r' || c == '\n')
          {
              input_buffer[i] = 0;
              break;
          }
          input_buffer[i] = c;
      }
      
      至:

      while ( ( c = getchar() ) != '\n' ) {
          strcat(input_buffer, &c);
      }
      
      for (int i=0; 1; i++)
      {
          c = getchar();
          if (c == '\r' || c == '\n')
          {
              input_buffer[i] = 0;
              break;
          }
          input_buffer[i] = c;
      }
      
      sizeof(char)
      定义为1。这为单个字符分配空间,并使
      input\u buffer
      指向它

      您也没有检查分配是否成功。
      malloc
      在失败时返回空指针;您应该始终检查该指针

      分配的
      char
      对象
      input\u buffer
      指向包含垃圾的对象

      char c;
      while ( ( c = getchar() ) != '\n' ) {
          strcat(input_buffer, &c);
      }
      
      getchar()
      返回一个
      int
      ,而不是
      char
      。您可以将结果分配给
      char
      对象,但这样做会使您失去检测和结束文件或错误条件的能力。
      getchar()
      在没有更多字符可读取时返回
      EOF
      ;您应该始终检查该值,这样做需要将结果存储在
      int
      中(
      EOF
      是一个不等于任何有效字符的整数值。)

      input\u buffer
      指向一个未初始化的
      char
      。您可以将其视为一个由单个
      char
      元素组成的数组。strcat的第一个参数必须已经包含一个有效的以null结尾的字符串,并且它必须有足够的空间容纳该字符串以及附加到它的任何内容

      c
      是一个单独的
      char
      对象,包含您刚刚使用
      getchar()读取的任何字符。
      strcat
      的第二个参数是一个
      char*
      ,因此您得到了正确的类型,但该
      char*`必须指向一个有效的以null结尾的字符串

      strcat
      将首先扫描
      input\u buffer
      指向的数组,以找到终止的
      '\0'
      字符,这样它就知道从何处开始追加,并且它可能会扫描到内存中,而该内存不是您声明或分配的任何对象的一部分,可能会使您的程序崩溃。如果没有爆炸,它就会崩溃将从
      c
      开始的字符复制到您不拥有的内存中。您有多种形式的未定义行为

      您不需要使用strcat将单个字符附加到字符串;您只需分配它即可

      下面是一个简单的例子:

      char input_buffer[100];
      int i = 0; /* index into input_buffer */
      int c;
      while ((c = getchar()) != '\n' && c != EOF) {
          input_buffer[i] = c;
          i ++;
      }
      input_buffer[i] = '\0'; /* ensure that it's properly null-terminated */
      
      为了简单起见,我分配了一个固定大小的缓冲区,而不是使用
      malloc

      此外,为了简单起见,我省略了任何检查,以确保输入不会超过输入缓冲区的结尾。如果输入超过了结尾,那么如果幸运的话,程序可能会崩溃;如果幸运的话,它可能只是在清除不属于您的内存时出现工作。如果输入行不太长,它就可以正常工作。在任何现实世界的程序中,您都希望这样做检查一下这个

      顺便说一句,使用
      fgets()

      sizeof(char)
      定义为1。这为单个字符分配空间,并使
      input\u buffer
      指向它

      您也没有检查分配是否成功。
      malloc
      在失败时返回空指针;您应该始终检查该指针

      分配的
      char
      对象
      input\u buffer
      指向包含垃圾的对象

      char c;
      while ( ( c = getchar() ) != '\n' ) {
          strcat(input_buffer, &c);
      }
      
      getchar()
      返回一个
      int
      ,而不是
      char
      。您可以将结果分配给
      char
      对象,但这样做会失去检测和结束文件或错误的能力