我试图将最多 100 个字符的字符串保存到数组中,然后通过索引打印数组的指定字符,但我收到分段错误 11,这是代码:'
#include<stdio.h>
#include<stdlib.h>
int main()
{
char str1[100];
int index;
printf("Enter text of max 100 characters: n");
scanf("%s", str1);
printf("Enter the index to searchn");
scanf("%d", &index);
printf("your char is: %cn", str1[index]);
return(0);
}
' 有什么建议吗?
虽然用户输入通常可以通过使用fgets
读取输入,然后sscanf
简单地使用一对指针和"英寸蠕虫向下"(a/k/a "行走"(字符串测试每个字符并根据需要进行处理来更好地处理scanf
来处理用户输入,但始终值得一看详细说明您需要做什么才能成功将其用于用户输入。
虽然fgets
并非没有必要的验证,但在输入失败或匹配失败的不同情况下,scanf
和处理留在输入缓冲区中的字符所需的验证数量和类型为新的(和不太新的(C 程序员带来了许多额外的陷阱。
scanf
的两个主要问题是:(1(它读取到任何缓冲区(可能会溢出数组(的字符数没有默认限制;(2(它不会从输入缓冲区中删除尾随'n'
(或输入或匹配失败后的任何字符((例如stdin
(。由您来考虑输入缓冲区中的所有字符,并根据需要清空缓冲区。
使图片进一步复杂化的是不同的scanf
格式说明符处理前导空格的方式(数字转换通常会跳过前导空格,而字符转换不会( 另一个问题是处理包含的空格。"%s"
格式说明符最多只能读取遇到的第一个空格,因此无法使用单个%s
说明符读取"My dog has fleas"
。(您可以使用字符类来读取包含的空格 - 如下例所示(
scanf
还有许多其他微妙之处,因此值得花时间阅读和理解man scanf
。
从注释中,您现在知道如果您要求一串100
字符,您至少需要101
存储字符 - 我们将假设这是学习的。
当使用scanf
进行任何输入时,您必须始终验证返回以确保预期的转换次数确实发生了。例如,如果使用转换说明符"%d %s"
读取"5 dogs"
,则返回2
表示成功转换为整数和字符串。但是,您也知道,输入缓冲区中至少保留了一个'n'
(如果说,输入了更多字符,则可能"5 dogs and cats"
。在尝试使用scanf
读取更多输入之前,您可以删除'n'
和任何其他剩余的字符。
以下示例捕获了示例中的大部分陷阱,并提供了在处理用户输入时可以使用的几个工具。底线是学会使用fgets
,但也知道如何使用scanf
。您的目标是提供尽可能强大且防弹的输入例程。想想用户在提示输入时可能会做的所有愚蠢的事情(或者上帝保佑,一只猫走过键盘(总是可以添加更多验证。查看每个包含的验证,如果您有疑问,请告诉我:
#include <stdio.h>
#include <string.h>
#define MAXC 100 /* if you need a constant, declare one */
/* helper function to remove any chars left in input buffer */
void empty_stdin()
{
int c = getchar();
while (c != 'n' && c != EOF)
c = getchar();
}
int main (void) {
char str1[MAXC+1] = ""; /* initialize to all zero */
int index, rtn, len; /* index, return, length */
for (;;) { /* loop until valid input obtained */
printf ("Enter text of max 100 characters: ");
rtn = scanf ("%100[^n]", str1); /* read at most MAXC char */
if (rtn != 1) { /* validate scanf return */
if (rtn == EOF) { /* check if EOF, ctrl+d, ctrl+z (windoze) */
printf ("input canceled.n");
return 0;
}
if (!str1[0]) /* was a character entered? */
fprintf (stderr, "error: string is empty.n");
/* remove 'n' and any chars that remain in stdin */
empty_stdin();
}
else { /* all conditions met, good entry, empty stdin and break */
empty_stdin();
break;
}
}
len = (int)strlen (str1); /* get string length */
for (;;) { /* now do the same thing for integer */
printf ("Enter the index to search (0-%d): ", len - 1);
if ((rtn = scanf ("%d", &index)) != 1) {
if (rtn == EOF) {
printf ("input canceled.n");
return 0;
}
fprintf (stderr, "error: invalid input - not integer.n");
/* only need to strip if non-integer entered, because %d
* will skip leading whitespace, including 'n'.
*/
empty_stdin();
}
else if (index < 0 || len < index + 1) /* validate index value */
fprintf (stderr, "error: invalid index - out of range.n");
else
break;
}
printf ("your char is: %cn", str1[index]);
return 0;
}
示例使用/输出
$ ./bin/scanfstr1
Enter text of max 100 characters: 12345678901234567890
Enter the index to search (0-19): -1
error: invalid index - out of range.
Enter the index to search (0-19): 0
your char is: 1
$ ./bin/scanfstr1
Enter text of max 100 characters: 12345678901234567890
Enter the index to search (0-19): foo
error: invalid input - not integer.
Enter the index to search (0-19): 6
your char is: 7
$ ./bin/scanfstr1
Enter text of max 100 characters: My dog has fleas.
Enter the index to search (0-16): d
error: invalid input - not integer.
Enter the index to search (0-16): 3
your char is: d
$ ./bin/scanfstr1
Enter text of max 100 characters:
error: string is empty.
Enter text of max 100 characters: My cats are fine.
Enter the index to search (0-16): meow
error: invalid input - not integer.
Enter the index to search (0-16): input canceled.