我想使用fgetc()
并将输入字符放在像char *ch
这样的数组中。但显然我不能将字符(如'M')放在数组中,它必须像“M”,我的意思是双引号就像一个字符串。
这是我的代码,在收到用户输入后我得到Segmentation fault (core dumped)
所以我想知道是否有任何办法或技巧可以做到这一点
提前致谢。 :)
void main(){
char *ch;
int i = 0;
while((ch[i] = fgetc(stdin)) != '\n'){
i++;
}
return;
}
答案 0 :(得分:2)
在char *ch
中,ch是一个指针,它的值应该是一个有效的内存位置,用于在该内存位置存储数据。在使用该指针之前,必须使用malloc()
或realloc()
(在最初ch指向NULL
时使用realloc)动态地将内存分配给ch。否则ch可能包含垃圾值,访问该内存位置会导致Segmentation fault
。我对您的程序进行了更改,它可能会对您有所帮助。
#include <stdio.h>
#include <stdlib.h>
int main(){
char *ch = NULL;
int i = 0;
ch = realloc(ch, i+1);
while((ch[i] = fgetc(stdin)) != '\n'){
ch = realloc(ch, i+1);
i++;
}
ch[i] = 0;
puts(ch);
free(ch);
return 0;
}
正如David C. Rankin在下面的评论中所说:
为每个读取的字符调用realloc是非常浪费的。 分配128,256,... 1024(或一些合理预期的数量 读取,直到达到限制,然后重新分配一些理智 额外的字符数,然后重复......
答案 1 :(得分:2)
虽然对于您阅读的每个字符都可以realloc
,但这是一种分配内存的非常低效的方式。与将字符赋值给数组元素相比,对malloc
的调用相对昂贵。最好分配一些合理预期的字符数,直到达到限制时读取,realloc
(更新限制),然后重复直到EOF
(或您选择的任何终止)。
实施是直截了当的,但有一些细微之处需要注意。重新分配时,请始终将realloc
的结果分配给临时指针,以便在继续之前验证 realloc
成功。为什么?如果realloc
失败,则返回NULL
。如果你只是盲目地将结果分配给原始数组,并且realloc
失败,(1)你刚刚丢失了指向原始数组的指针; (2)你刚刚创建了一个内存泄漏,因为原始块保持不变 - 它没有被释放或移动。
考虑到这一点,您可以将字符读入数组,根据需要重新分配,直到使用以下内容达到EOF
:
#include <stdio.h>
#include <stdlib.h>
#define NCHAR 1024 /* must be at least 1 */
int main (int argc, char **argv) {
int c;
size_t n = 0, nchar = NCHAR;
char *arr = malloc (sizeof *arr * nchar);
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
if (!arr) { /* validate memory allocation succeeded */
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
while ((c = fgetc (fp)) != EOF) { /* for each char in file */
arr[n++] = c; /* assign char to array */
if (n == nchar) { /* realloc preserving space for nul */
void *tmp = realloc (arr, nchar + NCHAR);
if (!tmp) { /* validate realloc succeeded */
fprintf (stderr, "realloc() error: memory exhausted.\n");
break; /* break read loop, using existing 'arr' */
}
arr = tmp; /* assign reallocated pointer to arr */
nchar += NCHAR; /* update the value of nchar */
}
}
arr[n] = 0; /* affirmatively nul-terminate */
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (size_t i = 0; i < n; i++) /* output arr */
putchar (arr[i]);
free (arr); /* free allocated memory */
return 0;
}
(注意:以上,失败时,退出读取循环,保留arr
中的所有字符,直到该时间点读取。)
最后,在您动态分配内存的任何代码中,对于分配的任何内存块,您有2个职责:(1)始终保留指向起始地址的指针对于内存块,(2)当不再需要时,它可以释放。
必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,尝试读取或基于未初始化的值跳转,最后确认您已释放所有内存你分配的记忆。 (对于Linux valgrind
是正常的选择。)
一个简单的示例(NCHAR
设置为2
以强制进行多次重新分配)将是:
$ valgrind ./bin/fgetc_realloc <../dat/captnjack.txt
==19710== Memcheck, a memory error detector
==19710== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==19710== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==19710== Command: ./bin/fgetc_realloc
==19710==
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
==19710==
==19710== HEAP SUMMARY:
==19710== in use at exit: 0 bytes in 0 blocks
==19710== total heap usage: 39 allocs, 39 frees, 1,560 bytes allocated
==19710==
==19710== All heap blocks were freed -- no leaks are possible
==19710==
==19710== For counts of detected and suppressed errors, rerun with: -v
==19710== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
你想找到所有堆块都被释放 - 没有泄漏可能和错误摘要:来自0个上下文的0个错误(注意:在某些操作系统上,valgrind会由于内存排除文件不完整而无法报告0