【问题标题】:Function cannot find failed memory allocation函数找不到失败的内存分配
【发布时间】:2020-12-06 08:58:02
【问题描述】:

函数int load(const char *filename, int ***ptr, enum save_format_t format) 应该从二进制或文本文件(名称保存在filename 指针下)加载数据到ptr 指向矩阵的指针下的矩阵。文件扩展名取决于变量格式的值:0 或 1(在我展示的函数中,只有 format=0 的选项,主要用于文本文件,因为只有这个会造成麻烦)。文件中的正确数据如下所示:

10 20 30 40 50 60 70 -1

100 200 300 400 500 600 700 800 -1

对于与上述示例完全相同的数据,应按如下方式加载数据:

int A[] = {10, 20, 30, 40, 50, 60, 70, -1};

int B[] = {100, 200, 300, 400, 500, 600, 700, 800, -1};

int D[] = {A, B, C, NULL};

这意味着每一行都必须以'-1'结尾,(数据必须以'-1'加载到矩阵中)。指向最后一行之后的行的指针应该等于 NULL。

如果任何部分关闭函数分配失败,函数应该返回 4。

对扩展名为“.bin”且具有堆限制的文件执行的测试返回此错误:

函数应该返回 4,但它返回了 0。

我使用诸如 **ptr 之类的符号,因为我不允许使用方括号。

谁能帮助我如何让我的函数返回正确的整数。我的功能如下:

int load(const char *filename, int ***ptr, enum save_format_t format) {
    if (filename == NULL || ptr == NULL || format != 0 && format != 1) {
        return 1;
    }
    int val = 0;
    int **temp = NULL;
    FILE *fp, *pp;
    if (format == 0) {
        int i = 0, x = 0, h = 0, w = 0;
        fp = fopen(filename, "r");
        if (fp == NULL) {
            return 2;
        }
        pp = fopen(filename, "r");
        if (pp == NULL) {
            fclose(fp);
            return 2;
        }
        int val2 = 0;
        while (1) {
            if (fscanf(fp, "%d", &val2) != 1) {
                if (i == 0 || val != -1) {
                    fclose(fp);
                    fclose(pp);
                    return 3;
                }
                break;
            }
            val = val2;
            if (val == -1) {
                h++;
            }
            i++;
        }
        if (i == h) {
            fclose(fp);
            fclose(pp);
            return 3;
        }
        i = 0;
        fseek(fp, 0, SEEK_SET);
        temp = malloc(sizeof(temp) * (h + 1));
        if (temp == NULL) {
            fclose(fp);
            fclose(pp);
            return 4;
        }
        *(temp + h) = NULL;
        for (i = 0; i < h; i++) {
            val = 0, w = 0;
            while (val != -1) {
                if (fscanf(pp, "%d", &val) == EOF) {
                    break;
                }
                w++;
            }
            if (*(temp + i) != NULL) {
                *(temp + i) = (int *)malloc(sizeof(int) * w);
                if (*(temp + i) == NULL) {
                    for (int s = 0; s < i; s++) {
                        free(*(temp + s));
                    }
                    free(temp);
                    fclose(pp);
                    fclose(fp);
                    return 4;
                }
            } else {
                fclose(fp);
                fclose(pp);
                free(temp);
                return 0;
            }
            for (x = 0; x < w; x++) {
                fscanf(fp, "%d", *(temp + i) + x);
            }
        }
        fclose(fp);
        fclose(pp);
    }
    *ptr = temp;
    return 0;
}

【问题讨论】:

  • 代码中发生了什么? temp 有什么意义? h? s?也许使用更具描述性的变量名称?也许添加一些cmets?为什么没有realloc?为什么要打开同一个文件两次?对于繁琐的错误处理,您可能只想将其重构为多个函数或使用 goto 错误管理。当if (*(temp + i) != NULL) { 为真时,您返回0,我认为*ptr 未设置。
  • 这一行if (*(temp + i) != NULL) { 肯定是错误的。 temp + i 指向的内存未初始化,因此读取它并测试它是否为 NULL 是没有意义的。
  • int D[] = {A, B, C, NULL}; 这是从哪里来的?示例文件没有这样的内容
  • 我会尽力纠正我的错误并迅速正确地描述一切
  • temp = malloc(sizeof(temp) * (h + 1)); 不正确:应该是temp = malloc(sizeof(*temp) * (h + 1));

标签: c memory multidimensional-array malloc dynamic-memory-allocation


【解决方案1】:

您的代码中存在多个问题:

  • if (i == h) 似乎不正确:如果文件包含带有 -1 终止符的单行,也就是一个空矩阵怎么办?
  • temp = malloc(sizeof(temp) * (h + 1)); 应该是 temp = malloc(sizeof(*temp) * (h + 1));
  • if (*(temp + i) != NULL) { 读取malloc() 分配的数组中未初始化的条目。应该删除测试,并且您应该始终分配行。

这是修改后的版本:

int load(const char *filename, int ***ptr, enum save_format_t format) {
    if (filename == NULL || ptr == NULL || format != 0 && format != 1) {
        return 1;
    }
    int **temp = NULL;
    FILE *fp, *pp;
    if (format == 0) {
        int i = 0, x = 0, h = 0, w = 0, val = 0;
        fp = fopen(filename, "r");
        if (fp == NULL) {
            return 2;
        }
        pp = fopen(filename, "r");
        if (pp == NULL) {
            fclose(fp);
            return 2;
        }
        // determine the number of rows
        val = 0;
        while (fscanf(fp, "%d", &val) == 1) {
            if (val == -1)
                h++;
        }
        if (val != -1) {
            // empty file or file does not end with -1
            fclose(fp);
            fclose(pp);
            return 3;
        }
        temp = malloc(sizeof(*temp) * (h + 1));
        if (temp == NULL) {
            fclose(fp);
            fclose(pp);
            return 4;
        }
        fseek(fp, 0, SEEK_SET);
        for (i = 0; i < h; i++) {
            w = 0;
            while (fscanf(pp, "%d", &val) == 1) {
                w++;
                if (val == -1)
                    break;
            }
            if (w == 0 || (*(temp + i) = malloc(sizeof(int) * w)) == NULL) {
                while (i-- > 0) {
                    free(*(temp + i));
                }
                free(temp);
                fclose(pp);
                fclose(fp);
                return 4;
            }
            for (x = 0; x < w; x++) {
                fscanf(fp, "%d", *(temp + i) + x);
            }
        }
        *(temp + h) = NULL;
        fclose(fp);
        fclose(pp);
    }
    *ptr = temp;
    return 0;
}

【讨论】:

    【解决方案2】:

    考虑读取一个字符串并使用strtol进行解析。
    当没有可用的 RAM 时,内存分配将返回 NULL。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <limits.h>
    #include <math.h>
    
    int load ( char const *filename, int ***ptr) {
        if ( filename == NULL || ptr == NULL) {
            return 1;
        }
        char entry[100] = "";
        char *end = NULL;
        int **temp = NULL;
        int *temprow = NULL;
        long int val = 0;
        int rows = 0;
        int cols = 0;
        int problem = 0;
        int result = 0;
        FILE* fp = NULL;
    
        fp = fopen ( filename, "r");
        if ( fp == NULL) {
            perror ( filename);
            return 2;
        }
    
        while ( 1 == ( result = fscanf ( fp, "%99s", entry))) {
            if ( -1 == val || ( 0 == rows && 0 == cols)) {
                if ( -1 == val) {
                    ++rows;
                }
                if ( NULL == ( temp = realloc ( *ptr, sizeof **ptr * ( rows + 2)))) {
                    fprintf ( stderr, "problem realloc *ptr\n");
                    problem = 4;
                    break;
                }
                *ptr = temp;
                *( ( *ptr) + rows) = NULL;
                *( ( *ptr) + rows + 1) = NULL;//sentinel
    
                cols = 0;
            }
            errno = 0;
            val = strtol ( entry, &end, 10);
            if ( entry == end) {//nothing could be parsed to int
                problem = 3;
                break;
            }
            else if ( 0 != *end) {//extra characters after int
                problem = 3;
                break;
            }
            if ( ( errno == ERANGE && ( val == LONG_MAX || val == LONG_MIN))
            || ( errno != 0 && val == 0)) {// parsing error from strtol
                perror ( "input error");
                problem = 3;
                break;
            }
            if ( val > INT_MAX || val < INT_MIN) {
                problem = 3;
                break;
            }
            if ( NULL == ( temprow = realloc ( *( ( *ptr) + rows), sizeof ***ptr * ( cols + 2)))) {
                fprintf ( stderr, "problem realloc *( (*ptr) + row)\n");
                problem = 4;
                break;
            }
            *( ( *ptr) + rows) = temprow;
            ++cols;
            *( *( ( *ptr) + rows)) = cols;//save cols in index 0
            *( *( ( *ptr) + rows) + cols) = val;
        }
        fclose(fp);
        if ( 0 == result) {
            problem = 3;
        }
        return problem;
    }
    
    int main ( void) {
        char const *filename = "ints.txt";
        int **array = NULL;
        int row = 0;
        int each = 0;
    
        load ( filename, &array);
    
        row = 0;
        while ( array && ( *(array + row))) {
            each = 0;
            while ( each <= *( *(array + row))) {
                printf ( "%d\n", *( *(array + row) + each));
                ++each;
            }
            ++row;
        }
    
        row = 0;
        while ( array && ( *(array + row))) {
            free ( *(array + row));
            ++row;
        }
        free ( array);
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-25
      • 2016-05-01
      • 2013-02-19
      • 2011-12-12
      • 2011-08-23
      相关资源
      最近更新 更多