我正在尝试编写一个简单的 C 程序来读取用户输入,然后将其写回stdout
。我使用gets()
从stdin
获取输入行(这是我老师要求我做的)。我可以阅读线条,但我无法摆脱while循环。例如,如果我输入10行,当我运行程序时,我发现我的代码正在读取第11行,它是空的,并且不会退出循环。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_LINE_SIZE 100
#define INITIAL_BUFFER_SIZE 16
char** IncreaseBuffer(char** buffer, int* buffer_size);
void PrintLines(char** lines, int total_lines);
int MinLineIndex(char** buffer, int i, int j);
void SwapLines(char** buffer, int i, int j);
int main(){
char** buffer;
int* buffer_size;
int* line_size;
int s,t;
int i=0;
char* q;
s = INITIAL_BUFFER_SIZE;
buffer_size = &s;
t = MAX_LINE_SIZE;
line_size = &t;
printf("Get lines:" );
buffer = (char**)malloc(sizeof(char*)**buffer_size);`enter code here`
buffer[0] = malloc(sizeof(char)**line_size);
while(1){
q = gets(buffer[i]);
*buffer[i] = *q;
if(buffer[i] == NULL){
i = i - 1;
char null = '\0';
buffer[i+1] = &null;
*buffer[i+1] = '\0';
break;
}
i++;
buffer[i] = malloc(sizeof(char)**line_size);
printf("%d%s\n",i,buffer[i]);
}
}
我做错了什么?
答案 0 :(得分:1)
虽然您可以通过多种方式读取未知数量的行,但您的方法和对声明指针的坚持有点麻烦。无需声明buffer_size
或line_size
或q
作为指针。可以为s
和t
提供更具描述性的名称,以帮助提高可读性。
首先,请理解,您不是在下面创建二维数组。您正在使用指向指针指向的指针来声明一个指针数组,您要为其分配一个已分配的内存块的地址,并保存每一行。输入。您可以使用数组索引来访问每个单独的指针值(例如,第一个指针的buffer[0]
,依此类推)。
由于您要使用INITIAL_BUFFER_SIZE
声明buffer
个指针,如果您将s
重命名为ptrcount
,则可以使用ptrcount
跟踪分配的当前指针数,以及达到计数时的realloc
。使用t
,如果您没有重新分配每行的字符数,那么没有理由声明单独的变量来跟踪MAX_LINE_SIZE
,您可以简单地将其用作常量。
它通常很有用,特别是在你想要在为行分配存储空间之前检查从用户读取的内容的情况下,使用静态缓冲区进行初始读取,比如说:
char buf[MAX_LINE_SIZE] = {0};
这允许您检查空行,以及在'\n'
中分配空格并将字符串复制到其最终位置之前删除试验buffer[i]
。 (注意:strdup
可用于分配和复制到buffer[i]
)
如果您阅读的buffer
行超过INITIAL_BUFFER_SIZE
行,则可以完成#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { INITIAL_BUFFER_SIZE = 16, MAX_LINE_SIZE = 100 };
int main (void) {
char buf[MAX_LINE_SIZE] = {0};
char **buffer;
int ptrcount, nlines;
int i = 0;
ptrcount = INITIAL_BUFFER_SIZE;
printf ("Get lines:\n"); /* allocate ptrcount pointers */
if (!(buffer = malloc (sizeof *buffer * ptrcount))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
while (fgets (buf, MAX_LINE_SIZE, stdin)) {
size_t len = strlen (buf);
if (len < 2) continue; /* skip empty lines */
buf[len - 1] = 0; /* strip trailing '\n' */
buffer[i++] = strdup (buf); /* allocate/copy buf */
if (i == ptrcount) { /* pointer limit reached, realloc */
void *tmp = realloc (buffer, 2 * ptrcount * sizeof *buffer);
if (!tmp) {
fprintf (stderr, "error: virtual memory exhausted.\n");
break;
}
buffer = tmp; /* assign tmp to buffer */
ptrcount *= 2; /* increase limit count */
}
}
nlines = i;
for (i = 0; i < nlines; i++) /* print the array */
printf (" line[%2d] : %s\n", i, buffer[i]);
for (i = 0; i < nlines; i++) /* free allocated memory */
free (buffer[i]);
free (buffer);
return 0;
}
的填充(和释放)以及重新分配:
strdup
(注意:,因为NULL
分配内存,您应该检查其结果不是malloc
,就像使用realloc
或{{1}一样},留给你)
示例输入
$ cat data.txt
a quick brown fox jumps over the lazy dog.
my dog has fleas.
my cat does too.
and the fleas are colored.
red, white, and blue.
示例使用/输出
$ ./bin/chararray <data.txt
Get lines:
line[ 0] : a quick brown fox jumps over the lazy dog.
line[ 1] : my dog has fleas.
line[ 2] : my cat does too.
line[ 3] : and the fleas are colored.
line[ 4] : red, white, and blue.
内存/错误检查
如果您分配内存,则应始终使用valgrind
或类似的内存错误检查工具检查其使用情况。您应该确认已释放所有已分配的内存并且没有内存错误。它使用简单,所以没有理由不跳过这一步。
$ valgrind ./bin/chararray < data.txt
==21344== Memcheck, a memory error detector
==21344== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==21344== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==21344== Command: ./bin/chararray
==21344==
Get lines:
line[ 0] : a quick brown fox jumps over the lazy dog.
line[ 1] : my dog has fleas.
line[ 2] : my cat does too.
line[ 3] : and the fleas are colored.
line[ 4] : red, white, and blue.
==21344==
==21344== HEAP SUMMARY:
==21344== in use at exit: 0 bytes in 0 blocks
==21344== total heap usage: 6 allocs, 6 frees, 255 bytes allocated
==21344==
==21344== All heap blocks were freed -- no leaks are possible
==21344==
==21344== For counts of detected and suppressed errors, rerun with: -v
==21344== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
答案 1 :(得分:0)
首先,最好使用fgets
函数而不是gets
因为它的错误而被弃用。有关详细信息,请参阅this question
之后你必须使用EOF(ctrl + D)来停止循环,因为fgets读取只包含换行符的空行。在您的代码中使用*q
这是错误的,因为根据gets
手册:
gets()在成功时返回s,在出错时或在文件结束时没有读取任何字符时返回NULL。
因此无法取消引用q
。我将您的代码更改为以下代码,它在我的计算机上运行良好:
int main(){
char **buffer;
int *buffer_size;
int *line_size;
int s,t;
int i = 0;
char *q;
s = INITIAL_BUFFER_SIZE;
buffer_size = &s;
t = MAX_LINE_SIZE;
line_size = &t;
printf("Get lines:\n");
buffer = malloc(sizeof(char *) * *buffer_size);
buffer[0] = malloc(sizeof(char) * *line_size);
while (1) {
q = gets(buffer[i]);
if (q == NULL) {
i = i - 1;
*buffer[i + 1] = '\0';
break;
}
i++;
buffer[i] = malloc(sizeof(char)**line_size);
printf("%d%s\n", i, buffer[i]);
}
}