我知道在C语言中,你可以像下面这样声明一个字符串和字符的数量:
char mystring[50];
数字'50'代表字符数。
然而,如果用户将通过scanf("%s", mystring);输入字符串的内容,那么正确的程序是什么呢?我应该保留原样吗,
char mystring[0];
由于我不知道用户会输入多少字符,因此将其保留为“0”?
还是我应该这样做,
char mystring[400];
让用户输入多达400个字符?
我知道在C语言中,你可以像下面这样声明一个字符串和字符的数量:
char mystring[50];
数字'50'代表字符数。
然而,如果用户将通过scanf("%s", mystring);输入字符串的内容,那么正确的程序是什么呢?我应该保留原样吗,
char mystring[0];
由于我不知道用户会输入多少字符,因此将其保留为“0”?
还是我应该这样做,
char mystring[400];
你遇到了scanf()和%s的确切问题——当你不知道输入有多少时会发生什么?
如果你尝试运行char mystring[0];
,你的程序将编译得很好。但你总是会出现段错误。你创建了一个大小为0的数组,所以当你试图把东西放入那个数组中时,你会立即超出字符串的边界(因为没有分配任何内存)——这就是段错误。
因此,第一点:你应该始终为你的字符串分配一个大小。我想不出有什么情况(好吧,没有)需要使用char mystring[0]
而不是char *mystring
。
接下来,在使用scanf时,你永远不要使用"%s"说明符——因为这不会对字符串的大小进行任何边界检查。所以即使你有:
char mystring[512];
scanf("%s", mystring);
如果用户输入超过511个字符(因为第512个是\0),您将超出数组的范围。解决方法如下:
scanf("%511s", mystring);
这就是说,C语言没有自动调整字符串大小的功能,如果输入超出了预期,你必须手动处理。
解决这个问题的一种方法是使用 fgets() 函数。
你可以这样写:
while (fgets(mystring, 512, stdin))
{
/* process input */
}
scanf("%50s", mystring);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ggets.h"
#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)
enum {OK = 0, NOMEM};
int fggets(char* *ln, FILE *f)
{
int cursize, ch, ix;
char *buffer, *temp;
*ln = NULL; /* default */
if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
cursize = INITSIZE;
ix = 0;
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
if (ix >= (cursize - 1)) { /* extend buffer */
cursize += DELTASIZE;
if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
/* ran out of memory, return partial line */
buffer[ix] = '\0';
*ln = buffer;
return NOMEM;
}
buffer = temp;
}
buffer[ix++] = ch;
}
if ((EOF == ch) && (0 == ix)) {
free(buffer);
return EOF;
}
buffer[ix] = '\0';
if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) {
*ln = buffer; /* without reducing it */
}
else *ln = temp;
return OK;
} /* fggets */
/* End of ggets.c */
int main(int argc, char **argv)
{
FILE *infile;
char *line;
int cnt;
//if (argc == 2)
//if ((infile = fopen(argv[1], "r"))) {
cnt = 0;
while (0 == fggets(&line, stdin)) {
fprintf(stderr, "%4d %4d\n", ++cnt, (int)strlen(line));
(void)puts(line);
free(line);
}
return 0;
//}
//(void)puts("Usage: tggets filetodisplay");
//return EXIT_FAILURE;
} /* main */
/* END file tggets.c */
我测试过了,它总是会给你想要的结果。
fgets()
到固定宽度数组,然后在该数组上运行sscanf()
。这样你就可以控制读入的行数了。