我需要阅读有限但无限长的字符串。
我们只学习了scanf
所以我想我不能使用fgets
。
无论如何,我已经在长度大于5的输入上运行了这段代码。
char arr[5];
scanf("%s", arr);
char *s = arr;
while (*s != '\0')
printf("%c", *s++);
scanf
继续扫描和写入溢出的部分,但它似乎是一个黑客。这是一个好习惯吗?如果没有,我该怎么读呢?
注意:我们了解了alloc
函数系列。
答案 0 :(得分:1)
scanf
是这项工作的错误工具(就像大多数工作一样)。如果您需要使用此功能,请一次使用char
阅读一个scanf("%c", &c)
。
您编码误用scanf()
:您正在传递arr
,指向char
的指针数组的地址,而不是char
的数组。
您应该使用char
分配一个malloc
数组,在其中读取字符,并在它太小时使用realloc
进行扩展,直到获得'\n'
或EOF
。
如果您可以回放stdin
,您可以先计算要使用scanf("%*s%n", &n);
读取的字符数,然后将目标数组分配到n+1
个字节,rewind(stdin);
并重新设置 - 使用scanf("%s", buf);
将字符串读入缓冲区。
这是一项有风险的业务,因为某些流如控制台输入无法重新启动。
例如:
fpos_t pos;
int n = 0;
char *buf;
fgetpos(stdin, &pos);
scanf("%*[^\n]%n", &n);
fsetpos(stdin, &pos);
buf = calloc(n+1, 1);
scanf("%[^\n]", buf);
由于你应该只知道一些基本的C
,我怀疑这个解决方案是你所期望的,但我想不出用标准C一步读取无界字符串的任何其他方法。 / p>
如果您正在使用glibc并且可以使用扩展程序,则可以执行以下操作:
scanf("%a[^\n]", &buf);
PS:故意忽略所有错误检查和处理,但应在实际分配中处理。
答案 1 :(得分:1)
%as
或%ms
(POSIX)可以用于此目的如果你使用gcc和glibc。(不是C标准)
#include <stdio.h>
#include <stdlib.h>
int main(void){
char *s;
scanf("%as", &s);
printf("%s\n", s);
free(s);
return 0;
}
答案 2 :(得分:1)
缓冲区溢出是一个瘟疫,是最着名但最难以捉摸的错误。所以你绝对不应该依赖。
由于您已经了解了malloc()
和朋友,我想您应该使用它们。
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
// Array growing step size
#define CHUNK_SIZE 8
int main(void) {
size_t arrSize = CHUNK_SIZE;
char *arr = malloc(arrSize);
if(!arr) {
fprintf(stderr, "Initial allocation failed.\n");
goto failure;
}
// One past the end of the array
// (next insertion position)
size_t arrEnd = 0u;
for(char c = '\0'; c != '\n';) {
if(scanf("%c", &c) != 1) {
fprintf(stderr, "Reading character %zu failed.\n", arrEnd);
goto failure;
}
// No more room, grow the array
// (-1) takes into account the
// nul terminator.
if(arrEnd == arrSize - 1) {
arrSize += CHUNK_SIZE;
char *newArr = realloc(arr, arrSize);
if(!newArr) {
fprintf(stderr, "Reallocation failed.\n");
goto failure;
}
arr = newArr;
// Debug output
arr[arrEnd] = '\0';
printf("> %s\n", arr);
// Debug output
}
// Append the character and
// advance the end index
arr[arrEnd++] = c;
}
// Nul-terminate the array
arr[arrEnd++] = '\0';
// Done !
printf("%s", arr);
free(arr);
return 0;
failure:
free(arr);
return 1;
}
答案 3 :(得分:0)
尝试限制接受的字符数量:
scanf("%4s", arr);
答案 4 :(得分:0)
只是你在arr[5]
以外写作。 &#34;希望&#34;你是否继续写下过程的已分配内存,但是如果你超越了你,最终会得到segmentation fault。
答案 5 :(得分:0)
考虑
1)malloc()
在许多系统上只分配内存,而不是使用它。在分配内存之前,不会发生下划线物理内存使用情况。见Why is malloc not "using up" the memory on my computer?
2)无限制的用户输入是不现实的。鉴于应该使用一些上限来防止黑客和恶意用户,简单地使用大缓冲区。
如果您的系统可以使用这两个想法:
char *buf = malloc(1000000);
if (buf == NULL) return NULL; // Out_of_memory
if (scanf("%999999s", buf) != 1) { free(buf); return NULL; } //EOF
// Now right-size buffer
size_t size = strlen(buf) + 1;
char *tmp = realloc(buf, size);
if (tmp == NULL) { free(buf); return NULL; } // Out_of_memory
return tmp;
修正了每@chqrlie条评论。