realloc 2 dim 数组的分段错误但输出正确?

segmentation fault by realloc 2 dim array but right output?

你好,我有一个问题,因为我不明白为什么我的 C 程序有段错误。我的程序创建了一个 2 dim int 数组,每一行都将按固定大小 5 分配,每行中都有随机数。但是如果他想重新分配我的行,用户可以选择是否要在一行中放置超过 5 个整数。每行长度都存储在数组大小中。所以输出很好:例如 1,6,3,4 8,6,5,3,2,1,6,8,9 1,4 8,9,6,4,2

但是在输出之后我的程序以分段错误结束但为什么呢?我的错误是在自由函数的某个地方还是在我的输出中?感谢您的回答,对不起我的英语不好 :)

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

void flushi(){// to flush the buffer 
char buff = ' ';
    while ((buff = getchar()) != '\n' &&buff !=EOF);
    return;
}
void freeall(int **arr,int zeilen){
    for (int i = 0; i < zeilen; i++) { 
        free(arr[i]);
    }
    free(arr);
}

int main(){
    int zeilen=4;
    int d,j;
    srand(time(0));
    int spalten=5;
    int size[spalten];
    int **arr=malloc(sizeof(int*)*4);
    for(int i=0;i<zeilen;i++){
        arr[i]=(int*)malloc(sizeof(int*)*spalten);// malloc first line
        j=0;
        while(1){
            printf("Wollen sie noch eine Zahl eingeben\n");
            printf("1...Ja      0...Nein\n");
            scanf("%i",&d);
            flushi();
            if(d==1){
                if(j>=spalten){// if user want more than 5 int in one line
                    spalten++;
                    arr[i]=realloc(arr[i],sizeof(int)*spalten);// realloc line
                }
                arr[i][j]= (rand()%10)+1;
                j++;
                printf("Sie haben schon %i Zahlen eingegeben\n",j);
            }
            else{
                break;
            }
        }
        size[i]=j;
    }
    printf("Your Numbers\n");
    for (int h=0;h<spalten;h++){
        printf("\n");
        for (int g=0;g<size[h];g++){
            printf("%i ",arr[h][g]);
        }
    }
    printf("\n");
    freeall(arr,zeilen);
    return EXIT_SUCCESS;
}

我觉得,问题出在

for (int h=0;h<spalten;h++)

在您的代码中,您只为 4 int * [int **arr=malloc(sizeof(int*)*4);] 分配了内存,但稍后在您的代码中,您增加了 spalten 并随后使用增加的值在印刷中。

您访问的内存越界导致了未定义的行为。

您应该将打印循环更改为

for (int h=0;h<4;h++)

P.S - 抱歉,我的母语也不是英语

There are several problems.
I have added comments about some of the problems to the original code

Please comment your code, for two major reasons
1) so in a few months you do not have to reverse engineer the code
2) so I do not have to reverse engineer your code 
   so that I can helpfully comment on what went wrong in the code

Note: getchar returns a int value, not a char value
      and '\n' on certain OSs is 2 characters
      and EOF is -1, not a char

The second code group is a suggested fix
In the second code group, there are certain improvements

that could be easily made,  
For instance, eliminate the spalen variable
allocate for the rows only once via:

if user enters 0,  
then use the default length, 
otherwise the user entered length


----Original code group with some comments----

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

void flushi()
{// to flush the buffer 
    char buff = ' ';

    while ((buff = getchar()) != '\n' &&buff !=EOF);
} // end function: flushi


void freeall(int **arr,int zeilen)
{
    for (int i = 0; i < zeilen; i++)
    { 
        free(arr[i]);
    }
    free(arr);
} // end function: freeall


int main()
{
    int zeilen=4;
    int d,j;

    srand(time(0)); // should be srand( time( NULL ) );

    int spalten=5;
    int size[spalten];

    int **arr=malloc(sizeof(int*)*4); // allocate room for 4 pointers to integers
       // should always test returned value from malloc to assure operation successful

    for(int i=0;i<zeilen;i++) // foreach of the 4 pointers to integers
    {
        arr[i]=(int*)malloc(sizeof(int*)*spalten);// ERROR: allocate room for 5 pointers to intege
             // should be: arr[i] = malloc( sizeof(int)*spalten); // allocate room for 5 integers
             // should always test returned value from malloc to assure operation successful

        j=0;

        while(1)
        {
            printf("Wollen sie noch eine Zahl eingeben\n");
            printf("1...Ja      0...Nein\n");
            scanf("%i",&d);
                // should always test returned value from scanf to assure operation successful

            flushi();

            if(d==1) // 
            {
                if(j>=spalten)
                {// if user want more than 5 int in one line
                    spalten++;
                    arr[i]=realloc(arr[i],sizeof(int)*spalten);// realloc line
                        // always test returned value from realloc before
                        // 1) to assure operation was successful
                        // 2) before using the new pointer
                        //    otherwise old allocation lost, resulting in a memory leak
                } // end if

                arr[i][j]= (rand()%10)+1;
                j++;
                printf("Sie haben schon %i Zahlen eingegeben\n",j);
            }

            else
            { // else, user did not enter 1 ????
                break;
            } // end if
        } // end while

        size[i]=j; // remember/ save meaningless number
    } // end for

    printf("Your Numbers\n");

    for (int h=0;h<spalten;h++) // foreach 0...4
    {
        printf("\n");

        for (int g=0;g<size[h];g++) // for each 0...meaningless value
        {
            printf("%i ",arr[h][g]);
        } // end if
    } // end for

    printf("\n");

    freeall(arr,zeilen);

    return EXIT_SUCCESS;
} // end function: main

----second code group which is a suggested fix----

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

void flushi()
{// to flush the buffer
    int buff;
    while ((buff = getchar()) != '\n' &&buff !=EOF);
} // end function: flushi


void freeall(int **arr,int rowCount)
{
    // free each row
    for (int i = 0; i < rowCount; i++)
    {
        free(arr[i]); // note: ok to call free() with null pointer
    }

    // free the array
    free(arr);
} // end function: freeall


#define MAX_ROWS (4)
#define DEFAULT_ROW_LEN (5)

// notice the removal of unneeded variables

// notice that most features are implemented 
// in separate code blocks

int main()
{
    int rowLength;  // new length (of integers) for each row
    int i, j;       // loop index/counters

    int spalten=DEFAULT_ROW_LEN;  // default length (of integers) for each row

    int size[MAX_ROWS] = {0};  // save area for final length of each row

    int **arr = NULL;
    if( NULL == (arr=malloc(sizeof(int*)*MAX_ROWS) ) ) // allocate room for MAX_ROWS pointers to integers
    { // then malloc failed
        perror( "malloc failed for number of rows" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful

    // clear first memory allocation (int pointers) to NULLs
    memset( arr, 0x00, MAX_ROWS*sizeof(int*) );

    for(i=0; i<MAX_ROWS; i++) // foreach of the rows
    {
        if( NULL == (arr[i]=malloc(sizeof(int)*spalten) ) )
        { // then, malloc failed
            perror( "malloc failed for row" );
            freeall( arr, MAX_ROWS ); // cleanup
            exit( EXIT_FAILURE );
        }

        // implied else, malloc successful

        size[i] = spalten;

    } // end for each row

    srand( time( NULL ) );

    for( i=0; i<MAX_ROWS; i++) // foreach row
    {
        printf("Wollen sie noch eine Zahl eingeben\n");
        printf("1...Ja      0...Nein\n");

        if( 1 != scanf("%i",&rowLength) )
        { // then scanf failed
            perror( "scanf failed for row length" );
            freeall( arr, MAX_ROWS ); // cleanup
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        flushi();

        if( rowLength > 0) // 0 means no change and negative numbers are ignored
        { // then, user wants a different length for this row

            if(rowLength != spalten)
            {
                size[i] = rowLength;
                int * temp;

                // if user want other than 5 int in one row
                if( NULL == (temp = realloc(arr[i],sizeof(int)*rowLength) ) )
                { // then, realloc failed
                    perror( "realloc failed for row length change" );
                    freeall( arr, MAX_ROWS ); // cleanup
                    exit( EXIT_FAILURE );
                }

                // implied else, realloc successful

                arr[i] = temp; // update the pointer in the array
            } // end if
        } // end if

        // fill in row of arr with random values
        for( j = 0; j<size[i]; j++ )
        {
            arr[i][j]= (rand()%10)+1;
        } // end if

        printf("Sie haben schon %i Zahlen eingegeben\n",j);
    } // end for

    printf("Your Numbers\n");


    for (int i=0;i<MAX_ROWS;i++) // foreach row
    {
        printf("\n");

        for (int j=0;j<size[i];j++)
        {
            printf("%i ",arr[i][j]);
        } // end if
    } // end for

    printf("\n");

    freeall(arr,MAX_ROWS); // cleanup

    return EXIT_SUCCESS;
} // end function: main