You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言二维数组重分配失效:第11个元素触发段错误

我来帮你搞定这个段错误的问题!你的代码里有几个关键的内存分配问题,直接导致了访问越界触发崩溃,下面我逐个给你分析并修正:

1. 内存分配时的sizeof用错了!

在vytvorPole和realokuj函数里,你分配每行内存的时候用了sizeof(*grid),但*grid是char**类型(指向指针的指针),它的大小是系统指针的长度(比如64位系统是8字节),而我们需要的是char类型的数组,应该用sizeof(char)或者更通用的sizeof(**grid)(因为**grid就是char类型)。

错误代码片段:

(*grid)[i]=(char *) malloc (ncols*sizeof(*grid));
// realokuj里同样的错误
(docasne)[i]=(char *) malloc (ncols*sizeof(*grid));

修正后:

(*grid)[i] = malloc(ncols * sizeof(**grid));
// 或者直接写sizeof(char),因为char的大小固定是1字节
(*grid)[i] = malloc(ncols * sizeof(char));

这个错误会导致每行分配的内存远大于实际需要的空间,虽然看起来不会直接崩溃,但后续如果输入的字符串长度超过预期,或者内存分配出现碎片,就容易触发越界访问。

2. realokuj没处理realloc失败的情况

realloc在内存不足时会返回NULL,如果直接把这个NULL赋值给*grid,会丢失原来的内存指针,而且后续访问docasne[i]时,相当于访问NULL的偏移,直接触发段错误。另外,分配新行内存时也没检查malloc是否成功,同样会有风险。

修正后的realokuj函数:

int realokuj(char ***grid, int nrows, int ncols) { // 把返回值改成int更合理,方便返回错误码
    char **docasne = realloc(*grid, nrows * sizeof(*grid));
    if (docasne == NULL) {
        printf("ERROR: 内存扩容失败\n");
        return 1;
    }
    // 给新增的行分配内存
    for(int i = nrows/2; i < nrows; i++) {
        docasne[i] = malloc(ncols * sizeof(**grid));
        if (docasne[i] == NULL) {
            printf("ERROR: 第%d行内存分配失败\n", i);
            // 回滚:释放已经分配的新行,避免内存泄漏
            for(int j = nrows/2; j < i; j++) {
                free(docasne[j]);
            }
            free(docasne);
            return 1;
        }
    }
    *grid = docasne;
    return 0;
}

3. vytvorPole的内存泄漏问题

原函数里如果某一行分配失败,已经分配的行内存没有被释放,会造成内存泄漏。而且返回值用char类型不太规范,建议改成int。

修正后的vytvorPole:

int vytvorPole(char ***grid, int nrows, int ncols) {
    *grid = malloc(nrows * sizeof(*grid));
    if (*grid == NULL) {
        printf("ERROR: 数组内存分配失败\n");
        return 1;
    }
    for(int i = 0; i < nrows; i++) {
        (*grid)[i] = malloc(ncols * sizeof(**grid));
        if ((*grid)[i] == NULL) {
            printf("ERROR: 第%d行内存分配失败\n", i);
            // 释放已经分配的所有行
            for(int j = 0; j < i; j++) {
                free((*grid)[j]);
            }
            free(*grid);
            *grid = NULL; // 避免野指针
            return 1;
        }
    }
    return 0;
}

4. getline读取的换行符可能导致越界

getline会把输入的换行符\n也读进字符串里,strlen(str)会包含这个换行符的长度。如果后续用strcpy复制到数组,当输入的字符串长度(不含换行)刚好等于cDiagonaly时,加上换行符就会超出分配的内存,触发段错误。

可以在读取后去掉换行符,并且分配内存时多留一个位置存字符串结束符\0:

while (getline(&str, &capacity, stdin) != -1) {
    size_t len = strlen(str);
    // 去掉换行符
    if (len > 0 && str[len-1] == '\n') {
        str[len-1] = '\0';
        len--;
    }
    // 空行就退出循环
    if (len == 0) break;

    if (first) {
        cDiagonaly = len;
        // 多分配1个字节存字符串结束符
        if (vytvorPole(&diagonaly, rDiagonaly, cDiagonaly + 1) != 0) {
            free(str);
            return 1;
        }
        first = 0;
    }

    if (nr == rDiagonaly) {
        rDiagonaly *= 2;
        if (realokuj(&diagonaly, rDiagonaly, cDiagonaly + 1) != 0) {
            free(str);
            // 清理已分配的内存
            for(int i=0; i<nr; i++) free(diagonaly[i]);
            free(diagonaly);
            return 1;
        }
    }

    // 用strncpy更安全,避免越界
    strncpy(diagonaly[nr], str, cDiagonaly);
    diagonaly[nr][cDiagonaly] = '\0'; // 手动添加结束符
    nr++;
}

完整修正后的代码

把所有修正整合起来,完整代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int vytvorPole(char ***grid, int nrows, int ncols) {
    *grid = malloc(nrows * sizeof(*grid));
    if (*grid == NULL) {
        printf("ERROR: 数组内存分配失败\n");
        return 1;
    }
    for(int i = 0; i < nrows; i++) {
        (*grid)[i] = malloc(ncols * sizeof(**grid));
        if ((*grid)[i] == NULL) {
            printf("ERROR: 第%d行内存分配失败\n", i);
            for(int j = 0; j < i; j++) {
                free((*grid)[j]);
            }
            free(*grid);
            *grid = NULL;
            return 1;
        }
    }
    return 0;
}

int realokuj(char ***grid, int nrows, int ncols) {
    char **docasne = realloc(*grid, nrows * sizeof(*grid));
    if (docasne == NULL) {
        printf("ERROR: 内存扩容失败\n");
        return 1;
    }
    for(int i = nrows/2; i < nrows; i++) {
        docasne[i] = malloc(ncols * sizeof(**grid));
        if (docasne[i] == NULL) {
            printf("ERROR: 第%d行内存分配失败\n", i);
            for(int j = nrows/2; j < i; j++) {
                free(docasne[j]);
            }
            free(docasne);
            return 1;
        }
    }
    *grid = docasne;
    return 0;
}

int main (void) {
    char **diagonaly = NULL;
    int rDiagonaly = 10;
    int cDiagonaly = -1;
    char *str = NULL;
    size_t capacity = 0;
    int first = 1;
    int nr = 0;

    printf("Vypln:\n");
    while (getline(&str, &capacity, stdin) != -1) {
        size_t len = strlen(str);
        if (len > 0 && str[len-1] == '\n') {
            str[len-1] = '\0';
            len--;
        }
        if (len == 0) break;

        if (first) {
            cDiagonaly = len;
            if (vytvorPole(&diagonaly, rDiagonaly, cDiagonaly + 1) != 0) {
                free(str);
                return 1;
            }
            first = 0;
        }

        if (nr == rDiagonaly) {
            rDiagonaly *= 2;
            if (realokuj(&diagonaly, rDiagonaly, cDiagonaly + 1) != 0) {
                free(str);
                for(int i=0; i<nr; i++) free(diagonaly[i]);
                free(diagonaly);
                return 1;
            }
        }

        strncpy(diagonaly[nr], str, cDiagonaly);
        diagonaly[nr][cDiagonaly] = '\0';
        nr++;
    }

    // 测试输出验证
    printf("\n你输入的内容:\n");
    for(int i=0; i<nr; i++) {
        printf("%s\n", diagonaly[i]);
        free(diagonaly[i]);
    }
    free(diagonaly);
    free(str);

    return 0;
}

总结

你遇到的段错误核心原因是内存分配时sizeof的错误使用,导致内存分配不符合预期,加上没有处理内存分配失败的情况,最终引发越界访问。修正这些问题后,代码就能正常实现二维数组的扩容功能了。

内容的提问来源于stack exchange,提问作者user14725090

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:55:42