我正在尝试做一件非常简单的事情 - 它正在读取一个文件,然后将其转换成一个将它分成行的字符。但是当我返回一个包含char **和size的结构时,我得到了Segmentation fault。我在这里读到:C segmentation fault before/during return statement它可能是“损坏的堆栈”。然而,我仍然不知道我做了什么来破坏它。这是我的代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "comp_words.h"
#define BLOCK 4096
struct sized_str {
char* str;
long size;
};
struct sized_arr {
char** content;
int size;
};
struct sized_str readfile(char* name) {
FILE *f;
long filesize;
char *buf;
struct sized_str res;
int r, p = 0;
f = fopen(name, "r");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
rewind(f);
buf = calloc(filesize + 1, sizeof(char));
while ((r = fread(buf + p, sizeof(char), BLOCK, f))) {
p += r;
}
res.str = buf;
res.size = filesize + 1;
return res;
}
struct sized_arr read_dict() {
struct sized_str file_content;
struct sized_arr result;
char *buf, *buf_cpy, *buf_cpy_point, *line, **res;
int i = 0, j, line_count = 0;
file_content = readfile("/var/tmp/twl06.txt");
buf = file_content.str;
buf_cpy = (char*)malloc(file_content.size * sizeof(char));
strcpy(buf_cpy, buf);
buf_cpy_point = buf_cpy;
while (strtok(buf_cpy_point, "\n\r")) {
line_count++;
buf_cpy_point = NULL;
}
res = (char**)malloc(sizeof(char*) * line_count);
while ((line = strtok(buf, "\n\r"))) {
res[i] = (char*)malloc(sizeof(char) * strlen(line));
j = 0;
while ((res[i][j] = tolower(line[j]))) {
j++;
}
buf = NULL;
}
free(buf_cpy);
result.size = line_count;
result.content = res;
return result;
}
// ...
int main (int argc, char** argv) {
struct sized_str input;
struct sized_arr dict;
dict = read_dict();
// ...
return 0;
从read_dict函数返回时代码段错误。
答案 0 :(得分:3)
至少乍一看,这似乎有几个问题。第一:
while ((line = strtok(buf, "\n\r"))) {
要使用strtok
,您通常会先在首先传递所有缓冲区,然后对第一个参数进行后续调用“NULL”,直到strtok
返回NULL(表示它已到达缓冲区的末尾)。 [编辑:进一步检查,显然这不是一个真正的错误 - 正如@Casablanca所指出的,他在循环中将buf
设置为NULL,因此第二次和后续迭代实际上做为第一个参数传递NULL - 所以当前代码有点难以理解,并且(至少可以说)有点脆弱,但实际上并不是错误的。]
其次,当您分配空间时,看起来您没有为终止NUL分配空间:
res[i] = (char*)malloc(sizeof(char) * strlen(line));
至少乍一看,它看起来应该是:
res[i] = malloc(strlen(line)+1);
[另外,sizeof(char)==1
并从malloc
转换回来可以掩盖未能#include <stdlib.h>
在范围内获得正确原型的错误。]
你的其他一些代码并不完全错误,但让我感觉不那么理想。例如:
j = 0;
while ((res[i][j] = tolower(line[j]))) {
j++;
}
这似乎是一种相当模糊的写作方式:
for (j=0; line[j] != '\0'; j++)
res[i][j] = tolower((unsigned char)line[j]);
另请注意,当您调用tolower
时,通常需要/想要将参数强制转换为unsigned char
(传递负值会给出未定义的行为,以及带有重音符号,变音符号等的相当多的字符在char
签名的典型情况下,通常会显示为负数。
你似乎也有内存泄漏 - read_dict
调用readfile
,它会分配一个缓冲区(calloc
- 为什么不malloc
?)并返回一个指向结构中该内存的指针。 read_dict
接收结构,但除非我遗漏了某些东西,否则结构会超出范围而不会释放它所指向的内存。
我没有试图找到并解决你所看到的问题,而是立即重新开始。在我看来,你已经使问题变得比实际上复杂得多。如果我这样做,我可能会开始使用一个函数来分配空间并在空间中读取一行,这个顺序是这样的:
// Warning: Untested code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *readline(FILE *file) {
char *buffer = NULL;
size_t current_size = 1;
char *temp;
const int block_size = 256;
do {
if (NULL == (temp = realloc(buffer, current_size+block_size)))
break;
buffer = temp;
buffer[current_size-1] = '\0';
if (fgets(buffer+current_size-1, block_size, file)==NULL)
return strlen(buffer) > 0 ? buffer : NULL;
current_size += block_size-1;
} while (strchr(buffer, '\n') == NULL);
strtok(buffer, "\n");
if (NULL != (temp = realloc(buffer, strlen(buffer)+1)))
buffer =temp;
return buffer;
}
一旦它正常工作,读取文件中的所有行并将它们转换为大写如下:
// Warning: more untested code.
while (res[i] = readline(file)) {
size_t j;
for (j=0; res[i][j]; j++)
res[i][j] = toupper((unsigned char)res[i][j]);
++i;
}
答案 1 :(得分:2)
在将每一行存储到结果数组中后,您似乎忘记增加i
,因此最终将所有行存储到res[0]
。但是你仍然在最后设置result.size = line_count
,所以除了第一个之外的所有数组元素都是未定义的。在此循环结束时i++
:while ((line = strtok(buf, "\n\r")))
应该修复它。