Ошибка сегментации при возврате структуры - PullRequest
2 голосов
/ 31 июля 2010

Я пытаюсь сделать довольно простую вещь - он читает файл, а затем превращает его в символ **, разбивая его на строки.Однако, когда я возвращаю структуру, содержащую символ ** и размер, я получаю ошибку сегментации.Я прочитал здесь: Ошибка сегментации C до / во время оператора возврата , что это, вероятно, "искаженный стек".Однако я до сих пор не знаю, что я сделал, чтобы исправить это.Это мой код:

#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.

Ответы [ 2 ]

3 голосов
/ 31 июля 2010

По крайней мере, на первый взгляд кажется, что у этого есть пара проблем. Во-первых:

while ((line = strtok(buf, "\n\r"))) {

Чтобы использовать strtok, вы обычно передаете буфер на first all, затем выполняете последующие вызовы, передавая "NULL" для первого параметра, пока strtok не вернет NULL (указывая, что он достиг конца буфера). [Редактировать: после дальнейшего изучения становится очевидным, что это не является ошибкой - как указал @Casablanca, он устанавливает buf в NULL в цикле, поэтому вторая и последующие итерации фактически делают pass 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;
}
2 голосов
/ 31 июля 2010

Похоже, вы забыли увеличить i после сохранения каждой строки в массиве результатов, так что в итоге вы сохраняете все строки в res[0].Но вы все равно устанавливаете result.size = line_count в конце, поэтому все элементы массива, кроме первого, не определены.i++ в конце этого цикла: while ((line = strtok(buf, "\n\r"))) должно исправить это.

...