C 中的动态缓冲区 fgets
Dynamic buffer fgets in C
我一直在搜索如何使用 fgets
分配动态缓冲区,但我似乎无法在这个示例中找到它。该文件有两个未知长度的数字,由白色-space 分隔。对于每一行,它读取每个字符,直到 ' '
和 \n
并打印出来。
char *ptr;
char line[MAX];
while(fgets(line, sizeof line , fp) != NULL){
ptr = line;
for(i=0; i<2; i++){
while(*ptr && (*ptr) != ' '){
if(*ptr == ' ')
break;
k = (*ptr) - '0';
if(k != -38) // wont print '\n'
printf("%d", k);
ptr++;
}
while(*ptr && (*ptr) != '\n') {
if(*ptr == ' '){
ptr++;
continue;
}
k = (*ptr) - '0';
printf("%d", k);
ptr++;
}
}
}
Can someone give me an idea on how to make line
dynamic while still using ptr
that way?
您不能在 C 中的 运行 时间内更改数组的大小。这是非法的。这是因为数组是从栈中分配的。要使大小是动态的,您必须声明一个指针,并为其动态分配内存。此数据是从堆中分配的。
您可以使用 realloc
更改分配的内存大小。
int lineLen = 80;
char *line;
line = (char *)malloc(sizeof(char) * 80);
if (line == NULL) {
// Something went horribly wrong
exit(1);
}
while (fgets(line, lineLen, fp)) {
// Do something to find the size
line = (char *)realloc(line, sizeof(char) * newLen);
if (line == NULL) {
// Something went horribly wrong
exit(1);
}
}
但是,分配和重新分配内存是一项相当昂贵的操作。因此,如果可以安全地选择大缓冲区大小,您可能会更有效。如果你有一个短循环,那么它可能不足以担心,但不断改变你的缓冲区大小可能是不可取的。
我想你想要的是这样的:
size_t linelen = 80;
char *line = malloc(linelen);
while(magic_reallocating_fgets(&line, &linelen, fp) != NULL) {
/* ... do whatever you want with line ... */
}
但是,当然,64,000 美元的问题是,magic_reallocating_fgets
是什么样子的?是这样的:
char *magic_reallocating_fgets(char **bufp, size_t *sizep, FILE *fp) {
size_t len;
if(fgets(*bufp, *sizep, fp) == NULL) return NULL;
len = strlen(*bufp);
while(strchr(*bufp, '\n') == NULL) {
*sizep += 100;
*bufp = realloc(*bufp, *sizep);
if(fgets(*bufp + len, *sizep - len, fp) == NULL) return *bufp;
len += strlen(*bufp + len);
}
return *bufp;
}
那不是真正完整的代码,几乎是伪代码。我留了两件事给你作为练习:
它没有对 malloc
和 realloc
调用进行错误检查。
它的效率有点低,因为它在读取的每一行上都进行了两次额外的传递:计算字符数,然后再次寻找 '\n'
。 (事实证明 fgets
的界面不适合此类工作。)
在支持 glibc >= 2.7 或 POSIX.1-2008 的系统上,我认为你想要的可以使用以下方法实现:
char *line;
while (fscanf(f, "%m[^\n]\n", &line) == 1) {
/* do stuff with line */
free(line);
}
这在我的 Linux 系统上运行良好,但在 Windows 世界中,Microsoft Visual C++ 既不支持 %m,也不支持我能找到的任何等效项。
我一直在搜索如何使用 fgets
分配动态缓冲区,但我似乎无法在这个示例中找到它。该文件有两个未知长度的数字,由白色-space 分隔。对于每一行,它读取每个字符,直到 ' '
和 \n
并打印出来。
char *ptr;
char line[MAX];
while(fgets(line, sizeof line , fp) != NULL){
ptr = line;
for(i=0; i<2; i++){
while(*ptr && (*ptr) != ' '){
if(*ptr == ' ')
break;
k = (*ptr) - '0';
if(k != -38) // wont print '\n'
printf("%d", k);
ptr++;
}
while(*ptr && (*ptr) != '\n') {
if(*ptr == ' '){
ptr++;
continue;
}
k = (*ptr) - '0';
printf("%d", k);
ptr++;
}
}
}
Can someone give me an idea on how to make
line
dynamic while still usingptr
that way?
您不能在 C 中的 运行 时间内更改数组的大小。这是非法的。这是因为数组是从栈中分配的。要使大小是动态的,您必须声明一个指针,并为其动态分配内存。此数据是从堆中分配的。
您可以使用 realloc
更改分配的内存大小。
int lineLen = 80;
char *line;
line = (char *)malloc(sizeof(char) * 80);
if (line == NULL) {
// Something went horribly wrong
exit(1);
}
while (fgets(line, lineLen, fp)) {
// Do something to find the size
line = (char *)realloc(line, sizeof(char) * newLen);
if (line == NULL) {
// Something went horribly wrong
exit(1);
}
}
但是,分配和重新分配内存是一项相当昂贵的操作。因此,如果可以安全地选择大缓冲区大小,您可能会更有效。如果你有一个短循环,那么它可能不足以担心,但不断改变你的缓冲区大小可能是不可取的。
我想你想要的是这样的:
size_t linelen = 80;
char *line = malloc(linelen);
while(magic_reallocating_fgets(&line, &linelen, fp) != NULL) {
/* ... do whatever you want with line ... */
}
但是,当然,64,000 美元的问题是,magic_reallocating_fgets
是什么样子的?是这样的:
char *magic_reallocating_fgets(char **bufp, size_t *sizep, FILE *fp) {
size_t len;
if(fgets(*bufp, *sizep, fp) == NULL) return NULL;
len = strlen(*bufp);
while(strchr(*bufp, '\n') == NULL) {
*sizep += 100;
*bufp = realloc(*bufp, *sizep);
if(fgets(*bufp + len, *sizep - len, fp) == NULL) return *bufp;
len += strlen(*bufp + len);
}
return *bufp;
}
那不是真正完整的代码,几乎是伪代码。我留了两件事给你作为练习:
它没有对 malloc
和 realloc
调用进行错误检查。
它的效率有点低,因为它在读取的每一行上都进行了两次额外的传递:计算字符数,然后再次寻找 '\n'
。 (事实证明 fgets
的界面不适合此类工作。)
在支持 glibc >= 2.7 或 POSIX.1-2008 的系统上,我认为你想要的可以使用以下方法实现:
char *line;
while (fscanf(f, "%m[^\n]\n", &line) == 1) {
/* do stuff with line */
free(line);
}
这在我的 Linux 系统上运行良好,但在 Windows 世界中,Microsoft Visual C++ 既不支持 %m,也不支持我能找到的任何等效项。