简体   繁体   中英

Reallocing nested array of structs in another struct in function

I'm trying to store table(stored in a file) into memory. I have here my edited code for simplicity. Im running into segmentation fault so I think it has to do something with that I try to store values without declaring the arrays actually. But I read it shouldn't be a problem as struct arrays are dynamic on their own? I don't really know. So in function addcelltoTable I tried some reallocating, but unsuccessfully. Can you help me understand memory allocating and maybe pointers a little more?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
typedef struct Cells
{
    bool selected;
    char *Content;
} cell;

typedef struct Rows
{
    int someint;
    cell cells[];
} row;
typedef struct Tables
{
    int NumberOfColumns;
    int NumberOfRows;
    row rows[];

} table;
void addCellToTable(table *dataTable, char *cellContent, int row, int column)
{
    if (row > dataTable->NumberOfRows)
    {
        dataTable->NumberOfRows = row;
    }
    if (column > dataTable->NumberOfColumns)
    {
        dataTable->NumberOfColumns = column;
    }
    *dataTable->rows[row].cells = (cell*)realloc(dataTable->rows[row].cells, column*sizeof(char*)+1);  //here I'm trying to realloc array of cells , error: incompatible types when assigning to type ‘cell’ {aka ‘struct Cells’} from type ‘cell *’ {aka ‘struct Cells *’}
    //*dataTable->rows = (row*)realloc(dataTable->rows, (sizeof(dataTable->rows)*sizeof(char*))); //realloc array of rows ?
    *dataTable->rows[row].cells[column].Content = *cellContent;
    printf("%d : %d : %lu : %s\n", row, column, strlen(dataTable->rows[row].cells[column].Content), dataTable->rows[row].cells[column].Content);
}
int main()
{
    char numberitoa[10];
    table dataTable;
    /*dataTable.NumberOfColumns=0;
    dataTable.NumberOfRows=0;
    dataTable.rows[0].someint=0;
    dataTable.rows[0].cells[0].selected=false;
    dataTable.rows[0].cells[0].Content="";*/
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            sprintf(numberitoa, "%d", rand());
            addCellToTable(&dataTable, numberitoa, i, j);
        }
    }
    for (int i = 0; i < dataTable.NumberOfColumns + 1; i++)
    {
        for (int j = 0; j < dataTable.NumberOfRows + 1; j++)
        {
            printf("main: %d, %d, %s\n", i, j, dataTable.rows[i].cells[j].Content);
        }
        printf("\n");
    }
    return 0;
}

An array declared with [] at the end of a structure is a flexible structure array, not a pointer to an array. Consequently you cannot reallocate it (instead you should reallocate the whole structure). Therefore it seems simpler to use a pointer to the allocated memory. This slightly changes the structures:

typedef struct Cell
{
    // You cannot use the same storage for each string as you did
    // instead we can use a fixed sized string (no allocation required)
    char Content[10]; 
    bool selected;

} cell;

typedef struct Rows
{
    int someint;
    cell * cells;
} row;
typedef struct Tables
{
    int NumberOfColumns;
    int NumberOfRows;
    row * rows;

} table;

There was a subtle issue in your allocation codes: when you allocate a row, the rows->cells array contains garbage, which makes any function called on it (including realloc) subject to crash. So these arrays must be set to NULL immediately after the rows have been allocated.

void addCellToTable(table *dataTable, char * cellContent, int row, int column)
{ 
    if (dataTable->NumberOfRows != row + 1) {
        dataTable->rows = realloc(dataTable->rows, (row + 1) * sizeof(struct Rows));
        for (int i=0; i <= row; i++) dataTable->rows[i].cells = NULL; //<== here
    }
    if (dataTable->NumberOfColumns != column + 1)
        dataTable->rows[row].cells = realloc(dataTable->rows[row].cells, (column + 1) * sizeof(struct Cell));
    
    // The fixed sized string must be set with memcpy
    memcpy(dataTable->rows[row].cells[column].Content, cellContent, strlen(cellContent) + 1);
    
    dataTable->NumberOfRows = row + 1;
    dataTable->NumberOfColumns = column + 1;
}

Finally your arrays are reallocated at each iteration so the print statement should be in the same loop than the allocations otherwise you cannot print all allocated cells.

int main()
{
    char numberitoa[10];
    table dataTable = {0};
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            sprintf(numberitoa, "%d", rand() % 1000);
            addCellToTable(&dataTable, numberitoa, i, j);

            printf("main: %d, %d, %s\n", i, j, dataTable.rows[i].cells[j].Content);
        }
    }
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM