当第一个早期定义的字符串数组的字符串为null时,scanf()不读取输入字符串

时间:2013-07-01 19:10:15

标签: c c-strings

我为字符串定义了一个数组。如果我以第一个元素不是空字符串的方式定义它,它工作正常。当它是一个空字符串时,另一个字符串的下一个scanf()停止读取输入字符串,程序停止执行。

现在我不明白如何定义字符串数组会影响scanf()对输入的读取。

  char *str_arr[] = {"","abc","","","b","c","","",""}; // if first element is "abc" instead of "" then works fine

  int size = sizeof(str_arr)/sizeof(str_arr[0]);

  int i;

  printf("give string to be found %d\n",size);


  char *str;
  scanf("%s",str);
  printf("OK\n");

3 个答案:

答案 0 :(得分:1)

声明指针不会在内存中为它分配缓冲区并且不会对其进行初始化,因此您尝试取消引用未初始化的指针(str),这会导致未定义的行为。

请注意,如果在读取字符串时未小心使用,scanf将导致潜在的缓冲区溢出。我建议您阅读this page,了解如何避免它的一些想法。

答案 1 :(得分:1)

实际上,你的错误是我的兄弟。 str_arr的初始化不会影响scanf()的工作,但是您可能会喜欢它但实际上并非如此。如其他答案中所述,这称为未定义的行为。 C本身中的未定义行为的定义非常模糊

C FAQ定义了“未定义的行为”,如下所示:

  

任何事情都可能发生;标准没有要求。该   程序可能无法编译,或者可能执行不正确(或者   崩溃或静默生成不正确的结果),或者它可能   偶然地做了程序员想要的。

它基本上意味着任何事情都可能发生。当你这样做时:

char *str;
  scanf("%s",str);

它是一个UB。有时你会得到你不应该得到的结果,你认为它的工作。这就是调试器派上用场的地方。几乎每次都使用它们,特别是在开始时。其他建议w.r.t您的计划:

  • 而不是scanf()使用fgets()来读取字符串。如果你想使用scanf,那就像scanf("%ws",name);一样使用它,其中name是字符数组,w是字段宽度。
  • 使用 -Wall 选项进行编译以获取所有警告,如果您已使用它,则可能已获得warning that you are using str uninitialized

继续阅读THIS ARTICLE,它有足够的信息来消除您的疑虑。

答案 2 :(得分:0)

您正在向scanf传递未初始化为任何特定内容的指针,因此scanf将尝试将用户提供的字符写入某个随机内存位置;这是否会导致崩溃或其他原因主要取决于运气(以及编译器如何决定设置堆栈,我们也可能将其视为“运气”)。从技术上讲,这被称为“未定义的行为” - 即就C标准而言,任何事情都可能发生。

要解决您的问题,您必须将scanf一个足够大的缓冲区传递给您计划接收的字符串:

char str[101];
scanf("%100s",str); /* the "100" bit tells to scanf to avoid reading more than 100  chars, which would result in a buffer overflow */
printf("OK\n");

请记住,C中的char * 相当于其他语言中的string - char *只是指向char的指针,对分配一无所知。