【问题标题】:Segmentation fault when trying to access properly allocated array尝试访问正确分配的数组时出现分段错误
【发布时间】:2021-12-29 16:48:28
【问题描述】:

我正在尝试读取一个 CSV 文件并编写一个函数来将一行数据解析为一个字符串数组,该函数会动态更改数组的大小并相应地更新 sizestr_size。我编写了一个名为find_key() 的正常工作函数来定位相关行的fseek() 位置。我遇到了一个我认为与字符串数组的分配有关的问题:我在 while 循环底部的行上遇到了分段错误,它读取为data[data_count][str_pos] = curr。当我尝试访问data[0][0] 时程序中断,尽管据我所知我已经正确分配了内存。任何帮助将不胜感激!

/**
 * @brief Get a row from the provided CSV file by first item. Dynamically
 *        allocated memory to data array
 * 
 * @param file
 * @param key First item of row
 * @param data Array of strings containing data
 * @param size Size of array
 * @param str_size Size of strings in array
 * @return 0 if successful, -1 if the row cannot be found, or 1 otherwise
 */
int csv_get_row(FILE *file, char *key, char **data, size_t *size, size_t *str_size) {
    if(!file || !key) return 1;

    /* Get the position of the beginning of the line starting with the key */
    long pos = find_key(file, key);
    if(pos == -1) return -1;
    fseek(file, pos, SEEK_SET);

    /* If these parameters aren't useful values, assign default values */
    if(*size < 1) *size = DEFAULT_ARRAY_SIZE;
    if(*str_size < 1) *str_size = DEFAULT_BUFFER_SIZE;

    /* If the memory for the array hasn't been allocated, do so now */
    if(!data) data = (char**) malloc(*size * *str_size);

    /* Get characters one-by-one, keeping track of the current amount of elements and the current buffer position */
    size_t data_count = 0;
    size_t str_pos = 0;
    char curr;
    while(fscanf(file, "%c", &curr)) {
        if(data_count >= *size) data = (char**) realloc(data, (*size *= 2) * *str_size);
        if(str_pos >= *str_size) data = (char**) realloc(data, *size * (*str_size *= 2));

        if(curr == ',') {
            data[data_count][str_pos] = '\0';
            data_count++;
            str_pos = 0;
            continue;
        }

        if(curr == '\n') {
            data[data_count][str_pos] = '\0';
            data_count++;
            break;
        }

        data[data_count][str_pos] = curr;
        str_pos++;
    }

    /* Resize the array to fit */
    *size = data_count;
    data = (char**) realloc(data, *size * *str_size);
    return 0;
}

【问题讨论】:

  • while(fscanf(file, "%c", &amp;curr)) 会导致无限循环,因为EOF 是一个非零(即真)值。循环应该是while(fscanf(file, "%c", &amp;curr) == 1)
  • 至于内存分配,我们需要看看你如何调用那个函数。见minimal reproducible example
  • 不确定这是否是您的问题的原因,但请注意,您对函数中的data 双指针所做的任何更改都将永远丢失返回。该指针按值从调用模块传递给函数,并且您的函数所做的更改将不会传递回调用者。
  • IMO,您的代码 waaaay 过于复杂,无法从 CSV 文件中读取一行并将其拆分为多个字段。首先让您的代码读取行。然后使用单独的函数将每行拆分为字段。然后获取这些字段并填写您的数组。您可以轻松地测试每个步骤并让它们正常工作。你所写的是将所有这些混搭成一个,它太复杂而无法工作,而且不可能一步一步地测试。而且因为您正在阅读 char-by-char 并涉及 fseek(),所以它也是 S-L-O-W

标签: c malloc c-strings


【解决方案1】:

假设 *size 从 1 开始。您将 data_count 设置为 0。然后,在第一次迭代中, 你没有data_count &gt;= *size,所以你没有realloc()。你增加data_count 不过,到 1,所以在下一次迭代中,您将 data 缓冲区增加到 2。

所以,此时,data 的长度为 2,data_count 的长度为 1。

假设我们不进入第一个if 语句,而是进入第二个语句。 在那里,您将data_count 增加到两个。然后您访问data[data_count],这是一个 过去最后一个元素。这是个问题。

这可能是您在while-loop 结束时看到的问题,但它远非 唯一的问题。每当您 malloc()realloc() data 时,您都会使调用者的指针无效 有,因为您可能正在释放原始位置的内存。你从来不给他 指向新数据的指针;所有新分配的数据都会在你的时候泄露 从函数返回,调用者必须永远在调用后访问data,以免 他想要一个段错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多