有什么简单的方法可以在C中读取可变长度的字符串吗?

u2nhd7ah  于 2023-01-29  发布在  其他
关注(0)|答案(4)|浏览(170)

我试着阅读使用:

char *input1, *input2;
scanf("%s[^\n]", input1);
scanf("%s[^\n]", input2);

很明显我做错了什么,因为第二个字符串被读为null。我知道不推荐使用scanf(),但我找不到任何其他简单的方法来做同样的事情。

vsaztqbk

vsaztqbk1#

声明:

char *input1, *input2;

为两个指向char的指针分配内存。注意这只为那些指针分配内存-它们没有初始化,也没有指向任何有意义的东西-而不是它们所指向的东西。
然后,对scanf()的调用尝试向内存写入超出界限的内容,并导致未定义的行为。
相反,您可以声明具有自动存储持续时间的固定大小的字符数组:

char input1[SIZE];

这将为数组分配内存,并且对scanf()的调用将有效。
或者,可以使用以下内存分配函数之一为指针动态分配内存:

char *input1 = malloc (size);

声明了一个指向char的指针,其内容不确定,但立即被一个指向size内存块的指针覆盖。注意,对malloc()的调用可能失败。它返回NULL作为错误代码,因此请检查它。
但是scanf()不应该用作用户输入接口,它不能防止缓冲区溢出,并且会在输入缓冲区中留下一个换行符(这会导致更多的问题)。
考虑用fgets代替,它将空终止缓冲区,并且最多读取size - 1个字符。
scanf()的调用可以替换为:

fgets (buf, sizeof buf, stdin);

然后可以使用sscanfstrtol等解析字符串。
注意,如果有空格,fgets()将保留尾随换行符。您可以使用以下一行程序删除它:

buf [strcspn (buf, "\n\r") = '\0`;

这也会处理返回托架(如果有)。
或者,如果您希望继续使用scanf()(我建议不要使用),请使用字段宽度来限制输入,并检查scanf()的返回值:

scanf ("%1023s", input1); /* Am using 1023 as a place holder */

也就是说,如果希望读取可变长度的行,则需要使用malloc()动态分配内存,然后根据需要使用realloc()调整其大小。
在符合POSIX的系统上,可以使用getline()读取任意长度的字符串,但请注意,它容易受到DOS攻击。

r1wp621o

r1wp621o2#

您可以使用m修饰符来格式化说明符。注意它不是标准C,而是标准POSIX扩展

char *a, *b;

scanf("%m[^\n] %m[^\n]", &a, &b);

// use a and b
printf("*%s*\n*%s*\n", a, b);

free(a);
free(b);
trnvg8h3

trnvg8h33#

有两种简单的方法可以从输入流中读取可变长度字符串:

  • 使用fgets()和一个足够大的数组来达到最大长度:
char input1[200];
    if (fgets(input1, sizeof input1, stdin)) {
        /* string was read. strip the newline if present */
        input1[strcspn(input1, "\n")] = '\0';
        ...
    } else {
        /* nothing was read: premature end of file? */
        ...
    }
  • 在符合POSIX的系统上,可以使用getline()将任意长度的字符串读入使用malloc()分配的数组:
char *input1 = NULL;
    size_t input1_size = 0;
    ssize_t input1_length = getline(&input1, &input1_size, stdin);

    if (input1_length >= 0) {
        /* string was read. length is input1_length */
        if (input1_length > 0 && input1[input1_length - 1] == '\n') {
            /* remove the newline if present */
            input1[--input1_length] = '\0';
        }
        ...
    } else {
        /* nothing was read: premature end of file? */
        ...
    }

不建议使用scanf,因为它很难正确使用,而且使用"%s""%[^\n]"阅读输入而不指定最大长度是有风险的,因为任何足够长的输入都将导致缓冲区溢出和未定义的行为。像您在发布的代码中所做的那样将未初始化的指针传递到scanf具有未定义的行为。

zzwlnbp8

zzwlnbp84#

有什么简单的方法可以在C中读取可变长度的字符串吗?
很遗憾,答案是
输入功能(例如scanffgets等)都要求调用者提供输入缓冲区。一旦输入缓冲区满了,函数将(如果使用正确)返回。因此,如果输入比提供的缓冲区的大小更长,函数只读取部分输入。2所以调用者必须添加代码来检查部分输入,并根据需要进行额外的函数调用。
Posix系统有getlinegetdelim函数可以做到这一点,所以如果你能接受将你的代码限制在符合Posix的系统上,那就是你想要使用的。
如果你需要可移植的、符合标准的代码,你需要编写自己的函数。为此,你需要研究reallocfgetsstrcpymemcpy等函数。这不是一项简单的任务,但也不是"火箭科学"。以前已经做过很多很多次了......如果你在网上搜索,您很可能会找到一个可以直接复制的开源实现(确保遵循复制规则)。

相关问题