仅在阵列中有足够的空间时才如何保存scanf输入?如何重新分配数组以使scanf输入适合?

#include <stdio.h>

int main() {

    char *mystring = calloc(2,sizeof(char));

    scanf("%10[^\n]s",mystring);

    printf("\nValue: %s\nSize of array: %d\nAllocated space: %d\n",mystring,2 * sizeof(char),sizeof(char) * strlen(mystring));

    free(mystring);
}

输出:

$ ./"dyn_mem" 
laaaaaaaaaaa

Value: laaaaaaaaa
Size of array: 2
Allocated space: 10

如果我在scanf输入中输入大于数组大小的字符串,则此代码可能会产生未定义的行为。我怎么处理这个?

pcluckbird 回答:仅在阵列中有足够的空间时才如何保存scanf输入?如何重新分配数组以使scanf输入适合?

选项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

大家都在问