选项1
摘自Kernighan and Ritchie 2nd ed附录B.1.4
char *fgets(char *s,int n,FILE *stream)
fgets最多将接下来的n-1个字符读入数组s,如果换行符为,则停止。
遇到换行符包含在以'\ 0'结尾的数组中。 fgets
返回s,如果文件结尾或发生错误,则返回NULL。
在代码中用n
替换sizeof(char)*strlen(mystring)
选项#2
也来自Kernighan and Ritchie 2nd ed附录B.1.4
int fgetc(FILE *stream)
fgetc返回流的下一个字符作为无符号字符(转换为
int),如果出现文件末尾或错误,则返回EOF。
并以sizeof(char)*strlen(mystring)
作为限制手动进入for循环
,
如果我在scanf中输入,此代码可能会产生未定义的行为
输入大于数组大小的字符串。
是的
我如何“处理”此问题?
通过确保始终向scanf
传递一个指向适用于相应转换指令的类型的对象的指针。作为C程序员,始终是您的责任。对于s
和[
伪指令,“适当的”包括足够大以容纳所有可能的转换值。
当格式直接表示输入的最大大小(如示例中所示)或参数表示输入时,这样做很容易。格式由您控制。但是,如果您需要处理无限制大小的输入,那么scanf
并不能胜任该任务,至少不是靠它自己。在这种情况下,您需要实现一种变型,即猜测需要多少空间,如果结果还不够,则获取更多空间。除其他外,这意味着准备好阅读多个输入,并可能通过动态分配为其获取空间。
,
您的代码中存在多个问题:
-
mystring
初始化为指向2字节分配的块。从技术上讲,您应该测试内存分配失败。
-
转换格式"%10[^\n]s"
不正确:结尾的s
应该删除,字符类的语法以]
结尾。
-
数字10
表示在mystring
中最多存储10个字符和一个空终止符。如果需要存储多个字符,则该代码具有未定义的行为。
-
printf
的{{1}}转换说明符是size_t
,而不是%zu
。如果您的C库符合C99,请使用%d
,否则将最后2个参数设置为%zu
。
-
输出的大小与标签不符:第一个是分配的大小,第二个是字符串的长度。
-
如果文件为空或以换行符开头,(int)
将失败。您应该测试scanf()
的返回值,该返回值必须为scanf()
,以避免在输入无效的情况下出现不确定的行为。
-
1
根据定义是sizeof(char)
。
有很多方法可以实现您的目标:
在支持它的系统上,例如带有GNU lib C的linux,可以在1
转换的m
和%
之间使用[
前缀格式化并传递scanf()
的地址作为参数。 char *
将分配一个scanf()
足够大的数组以接收转换后的输入。
这是Linux的修改版本:
malloc()
在POSIX系统上,您可以使用#include <stdio.h>
#include <stdlib.h>
int main() {
char *mystring = NULL;
if (scanf("%m[^\n]",&mystring) == 1) {
printf("Value: %s\n"
"Length of string: %zu\n"
"Allocated space: %zu\n",mystring,strlen(mystring),malloc_usable_size(mystring));
free(mystring);
}
return 0;
}
将行读入分配的数组中。
在其他系统上,只要没有换行符或文件末尾,就需要编写一个函数来读取输入流并重新分配目标数组。
一个常见的折衷办法是假设输入的最大长度:
getline()
您还可以使用#include <stdio.h>
#include <stdlib.h>
int main() {
char buf[1024];
if (scanf("%1023[^\n]",buf) == 1) {
char *mystring = strdup(buf);
if (mystring) {
printf("Value: %s\n"
"Length of string: %d\n","Minimum allocated size: %d\n",(int)strlen(mystring),(int)strlen(mystring) + 1);
free(mystring);
}
}
return 0;
}
从输入流中读取一行并剥离换行符(如果有)。这种方法的优点是不会在空行上失败。
这是fgets()
的简单实现,应满足您的需求:
getline()
本文链接:https://www.f2er.com/2325386.html