首页 > 解决方案 > 为什么外循环中的malocs数量为10 * sizeof,内循环中为2 * sizeof?

问题描述

我不明白为什么我必须在外循环中使用 10 * sizeof 在内循环中使用 2 * sizeof?首先,我在两者上都使用了 1 * sizof(实际上只是 sizeof),但后来我在 valgrind(810)中出现了很多关于 8 等大小的错误。所以我玩了一些尺寸,发现 10 和 2是正确的尺寸。我怎样才能在未来计算出正确的尺寸而不是猜测?

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

const int LOCATIONS = 9;
const int NUMBERS = 9;

typedef struct location {
    int column;
    int row;
    int zone;
} location;

typedef struct Number {
    int number;
    struct location *lockNum[];
} Number;

int main(void) {
            
    // Declare pointer to array structures Number.
    struct Number * numbers[NUMBERS];
    
    int i, j;

    // Memory allocation for each structure Number of array.
    for (i = 0; i < NUMBERS; ++i) {
        // It happens to have 10 * sizeof to make it work without 0 errors in valgrind but why?
        numbers[i] = (struct Number *) malloc (10 * sizeof(struct Number *));
        
        // Initialize members of structure Number.
        numbers[i]->number = 9;
        
        // Allocate memory for each location whithin structure Number of array.
        for (j = 0; j < LOCATIONS; ++j) {
            // Same here but why 2 *?
            numbers[i]->lockNum[j] = (struct location *) malloc (2 * sizeof(struct location *));
            
            // Initialize members of structure location
            numbers[i]->lockNum[j]->column = 0;
            numbers[i]->lockNum[j]->row = 0;
            numbers[i]->lockNum[j]->zone = 0;
        }   
    }

    // Do something...

    // Print content of allocated spaces.
    for (i = 0; i < NUMBERS; ++i) {
        printf("\nThere are %d possible locations for number %d\n\n", numbers[i]->number, i + 1);
        for (j = 0; j < LOCATIONS; ++j) {
            printf("location %d at row %d column %d in zone %d\n", j + 1, numbers[i]->lockNum[j]->row, numbers[i]->lockNum[j]->column, numbers[i]->lockNum[j]->zone);
        }
    }
    
    // Free memory after usage.
    for (i = 0; i < NUMBERS; ++i) {
        for (j = 0; j < LOCATIONS; ++j) {
            free(numbers[i]->lockNum[j]);
        }
        free(numbers[i]);
    }
    return 0;
}

标签: arrayscstruct

解决方案


这些mallocs的大小是一个刺。数据应基于底层类型的实际大小。唯一棘手的是允许 a 的灵活数组成员Number

灵活的数组成员通常使用结构的大小 + N * 数组元素类型的大小来分配。这可能会留下一些填充/松弛,但仍受支持。所以...

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

const int LOCATIONS = 9;
const int NUMBERS = 9;

typedef struct location {
    int column;
    int row;
    int zone;
} location;

typedef struct Number {
    int number;
    struct location *lockNum[];
} Number;

int main()
{
    struct Number *numbers[NUMBERS];

    for (int i=0; i<NUMBERS; ++i)
    {
        numbers[i] = malloc(sizeof **numbers + (LOCATIONS * sizeof(location*)));

        // Allocate memory for each location whithin structure Number of array.
        numbers[i]->number = LOCATIONS;
        for (int j = 0; j < numbers[i]->number; ++j) {
            numbers[i]->lockNum[j] = malloc ( sizeof(location) );
            
            // Initialize members of structure location
            numbers[i]->lockNum[j]->column = j;
            numbers[i]->lockNum[j]->row = i;
            numbers[i]->lockNum[j]->zone = 42;
        }           
    }

    // print the results
    for (int i=0; i<NUMBERS; ++i)
    {
        for (int j=0; j<numbers[i]->number; ++j)
        {
            printf("{%d %d %d} ", 
                numbers[i]->lockNum[j]->row,
                numbers[i]->lockNum[j]->column,
                numbers[i]->lockNum[j]->zone);
        }
        fputc('\n', stdout);
    }

    // free allocated spaces
    for (int i=0; i<NUMBERS; ++i)
    {
        for (int j=0; j<numbers[i]->number; ++j)
            free(numbers[i]->lockNum[j]);
        free(numbers[i]);
    }
}

输出

{0 0 42} {0 1 42} {0 2 42} {0 3 42} {0 4 42} {0 5 42} {0 6 42} {0 7 42} {0 8 42} 
{1 0 42} {1 1 42} {1 2 42} {1 3 42} {1 4 42} {1 5 42} {1 6 42} {1 7 42} {1 8 42} 
{2 0 42} {2 1 42} {2 2 42} {2 3 42} {2 4 42} {2 5 42} {2 6 42} {2 7 42} {2 8 42} 
{3 0 42} {3 1 42} {3 2 42} {3 3 42} {3 4 42} {3 5 42} {3 6 42} {3 7 42} {3 8 42} 
{4 0 42} {4 1 42} {4 2 42} {4 3 42} {4 4 42} {4 5 42} {4 6 42} {4 7 42} {4 8 42} 
{5 0 42} {5 1 42} {5 2 42} {5 3 42} {5 4 42} {5 5 42} {5 6 42} {5 7 42} {5 8 42} 
{6 0 42} {6 1 42} {6 2 42} {6 3 42} {6 4 42} {6 5 42} {6 6 42} {6 7 42} {6 8 42} 
{7 0 42} {7 1 42} {7 2 42} {7 3 42} {7 4 42} {7 5 42} {7 6 42} {7 7 42} {7 8 42} 
{8 0 42} {8 1 42} {8 2 42} {8 3 42} {8 4 42} {8 5 42} {8 6 42} {8 7 42} {8 8 42} 

好的。这真的有效吗?修改原始代码以使用 5..10 中的随机数作为每个 Number 的位置数将是......有趣:

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

const int NUMBERS = 9;

typedef struct location {
    int column;
    int row;
    int zone;
} location;

typedef struct Number {
    int number;
    struct location *lockNum[];
} Number;

int main()
{
    struct Number *numbers[NUMBERS];

    srand((unsigned)time(NULL));

    for (int i=0; i<NUMBERS; ++i)
    {
        int n_locations =  5 + (rand() % 6);
        numbers[i] = malloc(sizeof **numbers + (n_locations * sizeof(location*)));

        // Allocate memory for each location within structure Number of array.
        numbers[i]->number = n_locations;
        for (int j = 0; j < numbers[i]->number; ++j) {
            numbers[i]->lockNum[j] = malloc ( sizeof(location) );
            
            // Initialize members of structure location
            numbers[i]->lockNum[j]->column = j;
            numbers[i]->lockNum[j]->row = i;
            numbers[i]->lockNum[j]->zone = 42;
        }           
    }

    // print the results
    for (int i=0; i<NUMBERS; ++i)
    {
        printf("%d : ", numbers[i]->number);
        for (int j=0; j<numbers[i]->number; ++j)
        {
            printf("{%d %d %d} ", 
                numbers[i]->lockNum[j]->row,
                numbers[i]->lockNum[j]->column,
                numbers[i]->lockNum[j]->zone);
        }
        fputc('\n', stdout);
    }

    // free allocated spaces
    for (int i=0; i<NUMBERS; ++i)
    {
        for (int j=0; j<numbers[i]->number; ++j)
            free(numbers[i]->lockNum[j]);
        free(numbers[i]);
    }
}

输出(显然不同)

7 : {0 0 42} {0 1 42} {0 2 42} {0 3 42} {0 4 42} {0 5 42} {0 6 42} 
5 : {1 0 42} {1 1 42} {1 2 42} {1 3 42} {1 4 42} 
7 : {2 0 42} {2 1 42} {2 2 42} {2 3 42} {2 4 42} {2 5 42} {2 6 42} 
5 : {3 0 42} {3 1 42} {3 2 42} {3 3 42} {3 4 42} 
6 : {4 0 42} {4 1 42} {4 2 42} {4 3 42} {4 4 42} {4 5 42} 
10 : {5 0 42} {5 1 42} {5 2 42} {5 3 42} {5 4 42} {5 5 42} {5 6 42} {5 7 42} {5 8 42} {5 9 42} 
9 : {6 0 42} {6 1 42} {6 2 42} {6 3 42} {6 4 42} {6 5 42} {6 6 42} {6 7 42} {6 8 42} 
5 : {7 0 42} {7 1 42} {7 2 42} {7 3 42} {7 4 42} 
10 : {8 0 42} {8 1 42} {8 2 42} {8 3 42} {8 4 42} {8 5 42} {8 6 42} {8 7 42} {8 8 42} {8 9 42} 

无论原作者在做什么,都涉及赌博。上面的例子应该为你做你想做的事情提供了一个更好的方法。


推荐阅读