这个问题在这里已有答案:
我试图从stdin读取一些数据。它将是由空格分隔的数字(任何数字#)。问题是我事先不知道长度。我希望能够从stdin中读取并使用它来操作某些东西,这会重复直到按下^ d。
#include <stdio.h>
#include <stdlib.h>
int
main(){
char input[] = scanf("%s", &input);
for(int i=0; i<sizeof(&input);i++){
//Do something
}
}
这不起作用,但是如何更改它以使其工作?
他的一个例子。你需要添加malloc和realloc结果检查(我不是为了简单起见)
#include <stdio.h>
#include <stdlib.h>
#define CHUNK 32
char *readline(void)
{
size_t csize = CHUNK;
size_t cpos = 0;
char *str = malloc(CHUNK);
int ch;
while((ch = fgetc(stdin)) != '\n' && ch != '\r')
{
str[cpos++] = ch;
if(cpos == csize)
{
csize += CHUNK;
str = realloc(str, csize);
}
}
str[cpos] = 0;
return str;
}
然后你有你可以sscanf的字符串。使用后释放内存
并将其转换为整数数组(因为您不知道结果数组的大小):
int *tointegers(char *str, char *delimiters, size_t *size)
{
int *array = malloc(CHUNK * sizeof(*array));
char *ptr;
*size = 0;
ptr = strtok (str, delimiters);
while (ptr != NULL)
{
array[(*size)++] = atoi(ptr);
if(*size == CHUNK)
{
array = malloc((*size + CHUNK) * sizeof(*array));
}
ptr = strtok (NULL, delimiters);
}
return array;
}
关于malloc&realloc结果检查和内存释放的相同评论
这里的主要问题是你事先不知道元素的数量,在那些情况下你需要保留空间来存储使用动态内存的元素,你可以使用队列或者你可以使用realloc
,也避免在这里使用scanf
总是限制字符串的长度:
char str[100];
scanf("%99s", str); /* buffer overflow protection */
并始终检查结果:
if (scanf("%99s", str) != 1) {
/* something went wrong */
}
使用fgets
(作为scanf
的替代品)和strtol
的示例,将数据存储在队列中:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
struct node {
struct node *next;
int data;
};
void *enqueue(struct node **root, int data)
{
struct node *node;
node = malloc(sizeof *node);
if (node == NULL) {
return NULL;
}
if (*root == NULL) {
node->next = node;
} else {
node->next = (*root)->next;
(*root)->next = node;
}
node->data = data;
*root = node;
return node;
}
int dequeue(struct node **root)
{
struct node *node;
int data = 0;
node = *root;
if (node != NULL) {
node = node->next;
data = node->data;
if (*root == node) {
*root = NULL;
} else {
(*root)->next = node->next;
}
free(node);
}
return data;
}
int main(void)
{
struct node *node = NULL;
char str[512];
char *ptr;
int data;
ptr = fgets(str, sizeof str, stdin);
if (ptr != NULL) {
while (*ptr) {
data = (int)strtol(ptr, &ptr, 10);
if (!isspace(*ptr)) { // If we don't have a blank space
break; // exit the loop
}
enqueue(&node, data);
ptr++;
}
}
while (node != NULL) {
data = dequeue(&node);
printf("%d\n", data);
}
return 0;
}
输入
123 456 -789
产量
123
456
-789
要从stdin
读取(并存储)未知数量的字符,您有两个基本选项:
getline()
将所有字符读入缓冲区(getline
将根据需要重新分配内存以存储整行输入,包括* nul-terminating字符),或者malloc
和realloc
。正如您所发现的那样,动态内存分配起初可能有点令人生畏,但它确实没有任何理由。在任何情况下,您只需分配一些初始大小的内存块,将起始地址分配给指针,在块中存储您需要的任何内容,以跟踪所使用的内存。当使用的内存等于可用内存时(即当你填满你分配的内存块时),你只需使用临时指针重新分配更多内存,验证你对realloc
的调用成功,然后分配重新分配的块的开始内存到你的原始指针,每次你填满你的内存块时继续前进并重复这个过程。
有许多方法可以使用像getchar()
这样的面向字符的输入函数来处理读取,或者使用一些固定大小的缓冲区和fgets
来一次读取固定数量的字符。这完全取决于你。避免scanf
为单个字符,没有必要。底层读取由文件系统缓冲,因此无论您选择哪种,都不会有性能损失。 (Linux提供了一个8192字节的读取缓冲区,其大小为IO_BUFSIZ
(现在为BUFSIZ
,请参阅glibc/libio/stdio.h - #define BUFSIZ 8192和_IO_BUFSIZ
更改为BUFSIZ
glibc commit 9964a14579e5eef9),并且Windows证明了类似的512字节缓冲区)
关键是要逐步采用它,验证每个分配,并根据需要处理错误。你使用realloc
的临时指针,因为如果realloc
失败,它返回NULL
,如果你将realloc
的返回值分配给原始指针,你将用NULL
覆盖原始内存块的地址,从而造成内存泄漏。通过使用临时指针,如果realloc
失败,仍可通过原始指针访问现有数据。
例如,要将当前分配大小为buffer
的当前分配的buffersize
的大小加倍,您可以天真地做:
buffer = realloc (buffer, 2 * buffersize); /* wrong - potential memory leak */
if (buffer == NULL) { /* validate reallocation */
perror ("realloc-buffer"); /* output error message */
/* handle error */
}
buffersize *= 2; /* increment buffersize */
相反,你会做:
void *tmp = realloc (buffer, 2 * buffersize); /* use a temporary pointer */
if (tmp == NULL) { /* validate reallocation */
perror ("realloc-buffer"); /* output error message */
/* handle error, buffer still points to original block */
}
buf = tmp;
buffersize *= 2;
消化它如何工作的方法是通过一个简单的简单例子。以下将使用便携式stdin
,getchar()
和malloc
从realloc
读取未知大小的行,使用重新分配方案,每次填充缓冲区时,简单地将缓冲区的大小加倍。 (您可以随意增加任何额外的数量,但避免重新分配每个读取的字符 - 效率低,缓冲区大小加倍或类似的增加可以最大限度地减少重新分配的次数)
#include <stdio.h>
#include <stdlib.h>
#define NCHR 8 /* initial number of characters to allocate */
int main (void) {
int c; /* char to read from stdin */
size_t ndx = 0, /* index/count of characters */
nchr = NCHR; /* number of characters allocated in buf */
char *buf = malloc (nchr); /* buffer allocated for nchr chars */
if (buf == NULL) { /* validate that allocation succeeds */
perror ("malloc-buf"); /* otherwise handle error */
return 1; /* bail */
}
/* read chars from stdin until '\n' or EOF */
while ((c = getchar()) != '\n' && c != EOF) {
if (ndx == nchr - 1) { /* check if reallocation is needed */
void *tmp = realloc (buf, 2 * nchr); /* double buf size */
if (tmp == NULL) { /* validate realloc succeeds */
perror ("realloc-buf"); /* handle error */
break; /* break don't bail, buf holds chars read */
}
buf = tmp; /* assign newly sized block of mem to buf */
nchr *= 2; /* update nchr to new allocation size */
}
buf[ndx++] = c; /* assign char to buf, increment index */
}
buf[ndx] = 0; /* nul-terminate buffer */
if (c == EOF) /* if read stopped on EOF */
putchar ('\n'); /* tidy up outputting \n */
printf ("length : %zu\ncontent: %s\n", ndx, buf);
free (buf); /* don't forget to free what you allocate */
}
(注意:检查EOF
将由Ctrl + d(或Windows上的Ctrl + z)生成,并在遇到时输出额外的'\n'
,否则您的下一个输出将在当前输入结束时开始。另请注意nchr - 1
在if (ndx == nchr - 1)
中,确保在循环退出后始终存在1个字符用于存储nul-termination。)
示例使用/输出
$ ./bin/getchar_dyn
1234 5678 9012 3456 7890
length : 24
content: 1234 5678 9012 3456 7890
内存使用/错误检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块都有2个职责:(1)始终保留指向内存块起始地址的指针,因此,(2)当它为no时可以释放它需要更久。
您必须使用内存错误检查程序,以确保您不会尝试访问内存或写入超出/超出已分配块的范围,尝试读取或基于未初始化值的条件跳转,最后,确认你释放了你分配的所有内存。
对于Linux,valgrind
是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。
$ valgrind ./bin/getchar_dyn
==28053== Memcheck, a memory error detector
==28053== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28053== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==28053== Command: ./bin/getchar_dyn
==28053==
1234 5678 9012 3456 7890
length : 24
content: 1234 5678 9012 3456 7890
==28053==
==28053== HEAP SUMMARY:
==28053== in use at exit: 0 bytes in 0 blocks
==28053== total heap usage: 3 allocs, 3 frees, 56 bytes allocated
==28053==
==28053== All heap blocks were freed -- no leaks are possible
==28053==
==28053== For counts of detected and suppressed errors, rerun with: -v
==28053== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放已分配的所有内存并且没有内存错误。
仔细看看,如果您有其他问题,请告诉我。
尝试先读取一行,然后读取行中的整数
char *x ,*s ;
int d ;
while (fgets(input, sizeof(input), stdin)) {
x = input;
for (x = input; ; x = s) {
d = strtol(x, &s, 10);
if (x == s)
break;
}
}