【问题标题】:Why is my C program not printing out the string?为什么我的 C 程序没有打印出字符串?
【发布时间】:2020-03-15 02:02:43
【问题描述】:

我正在制作一个程序,打印出用户输入的内容,需要用read_line()的方法完成(我的功课),所以我不能改变太多。

我不明白为什么它没有打印出用户输入的内容。

#include <stdlib.h>

char *read_line(char *buf, size_t sz) {
  char tempBuf[sz];
  char c;
  int pos = 0;

  printf("> ");

  while(1) {
    c = getchar();
    if (tempBuf[pos] == EOF || tempBuf[pos] == '\n') {
      buf = tempBuf;
      return buf;
    } else {
      tempBuf[pos] = c;
    }
    pos++;
  }
}

int main(int argc, char **argv) {
  char *buf;
  char *input = read_line(buf, 128);

  printf("Here: %s", input);
}

我是 C 的新手,我发现它很混乱,所以请用非常简单的术语解释一下。任何帮助将不胜感激。

【问题讨论】:

  • 尝试使用诊断标志编译代码:gcc -Wall -Wextra -Wpedantic yourfile.c 并尝试一一解决错误/警告。
  • 您的read_line 功能已损坏。您必须将getchar() 的返回值与EOF 进行比较。但是tempBuf 只包含getchar 在转换为char 之后的返回值,从而失去了与EOF 比较所需的精度。让我非常担心的是,您会收到一个作业,其中包括您可能无法更改的代码,这些代码是由不了解如何正确使用 getchar 的人编写的。

标签: c stack malloc


【解决方案1】:
char *buf;
char *input = read_line(buf, 128);

您的第一行创建了一个名为buf 的指针变量,但没有为其分配任何特定值。您的第二行将buf 的值传递给read_line - 但您从未为其分配任何特定值。所以你将垃圾传递给read_line 并告诉它使用垃圾作为缓冲区。

您可能想要char buf[128]; 而不是char *buf;,但这很难说。

另外,请参阅我关于您的 read_line 函数被破坏的评论,这表明编写它的人不了解如何使用 getchar。

【讨论】:

  • 另外stdio.h 不包括在内,使得EOF 和printf 未声明。
  • @Xatenev 取决于环境stdlib.h 包括stdio.h,所以无论如何它都会编译
  • @ChatterOne 不知道这一点,谢谢,我会留下它,尽管它可能对不是这种情况的人仍然有用。
  • 看看其他答案,比我想象的要糟糕得多。 read_line 函数被彻底破坏,返回垃圾。
【解决方案2】:

你的程序有很多错误。

对于初学者来说,您正在向函数传递一个未初始化的指针

char *buf;
char *input = read_line(buf, 128);

实际上传递函数中没有使用的指针值是没有意义的。

在函数中,变量 c 应该被声明为 int 类型。

int c;

否则,如果 char 类型表现为 unsigned char 类型(它取决于编译器选项),则它与 EOF 的比较将始终为 false。

在函数内,数组 tempBuf 未初始化。所以这个 if 语句

if (tempBuf[pos] == EOF || tempBuf[pos] == '\n') {

调用未定义的行为。

在 wjile llop 中,您必须检查 pos 的值是否小于 sz 的值。

函数返回一个指向局部数组的指针,使返回的指针无效。

  buf = tempBuf;
  return buf;

此外,数组甚至不包含字符串,因为终止的零没有附加到数组中。

该函数应动态分配内存并返回指向已分配内存的指针,该指针将包含一个以零结尾的字符串。

下面是一个演示程序,展示了如何编写函数。

#include <stdio.h>
#include <stdlib.h>

char * read_line( size_t n ) 
{
    char *s = malloc( n );

    if ( s != NULL )
    {
        int c;

        printf( "> " );

        size_t i = 0;

        for ( ; i + 1 < n && ( c = getchar() ) != EOF && c != '\n'; i++ )
        {
            s[i] = c;
        }

        s[i] = '\0';
    }

    return s;
}

int main(void) 
{
    size_t n = 128;

    char *input = read_line( n );

    if ( input != NULL ) printf( "Here: %s\n", input );

    free( input );

    return 0;
}

程序输出可能看起来像

> Hello Jake Jackson
Here: Hello Jake Jackson

【讨论】:

    【解决方案3】:

    read_line 的当前实现存在很大缺陷,因为它返回一个本地声明的缓冲区(在函数末尾被删除)。结果,您的指针指向垃圾值(这是非常危险的 - 我重复一遍 - 因为它会导致您的程序崩溃或更糟[即使使用它不拥有的内存也继续运行])。

    您应该做的是在堆上动态创建缓冲区(这样可以安全地返回 - 但必须手动删除)。

    因此,您的函数(以及其余代码)应更改为如下所示:

    #include <stdlib.h>
    
    char *read_line(size_t sz) {
      // create a new buffer on the heap - so it can easily be returned (note this will have to be deleted after use using free()).
      char *tempBuf = malloc(sz);
      int c;
      int pos = 0;
    
      // set all elements of tempBuf to nulls
      memset(arr, 0, sz); 
    
      printf("> ");
    
      while(1) {
        c = getchar();
        if (tempBuf[pos] == EOF || tempBuf[pos] == '\n') {
          return tempBuf;
        } else {
          tempBuf[pos] = (char) c;
        }
        pos++;
      }
    }
    
    int main(int argc, char **argv) {
      char *input = read_line(128);    
      printf("Here: %s", input);
    
      // free the memory since we are now done with it.
      free(input);
    }
    

    您可以阅读有关堆和堆栈的更多信息here。

    【讨论】:

    • @DavidSchwartz 这并不是真正必要的,因为在大多数实现中EOF 的值为-1,并且由于char 在许多系统上被表示为有符号的 8 位整数 - 它可以完美地存储-1的值。
    • @DavidSchwartz 因此您真的不必对我投反对票。一个都没有。
    • @chux-ReinstateMonica 嗯嗯好的。请修改我的答案。
    • @marvinIsSacul No. I read this: "EOF 扩展为一个整数常量表达式,类型为int 和一个负值,由多个函数返回以指示结束-文件,即不再有来自流的输入;" getchar() 返回 int 的原因是:EOF 不能由 char 值表示。您是否想争辩说(char) 255 应该等于EOF?因为当你说“作为 EOF 并不是真正必要的......它可以完美地存储 -1 的值”时,这就是你有效地做的事情
    • (cont) 当getchar() 读取具有十进制值255 或十六进制0xFF 的字符 时,getchar() 将int 值0x000000FF 返回给调用者(假设 32 位 int)。当getchar()遇到文件尾时,假设EOF定义为-1,getchar()返回int值0xFFFFFFFF。仅仅因为char 值0xFF 扩展为-1 作为int(假设签名char),这不会使char 的值0xFF 与EOF 相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 2014-02-21
    相关资源
    最近更新 更多