Search code examples
carrayssegmentation-faultsizedynamic-allocation

c- Segmentation fault after increasing array size and try to reach


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

void print(int **array,int row,int col){
    int i,j;
    for(i=0;i<row;++i){
        for(j=0;j<col;++j){
            printf("%d ",array[i][j]);
        }
        printf("\n");
    }

}
int **take(int *row,int *col){
    int i; int **array;
    printf("Enter the row number for array \n");
    scanf("%d",row);
    printf("Enter the column number for the array \n");
    scanf("%d",col);

    array=(int**)malloc(sizeof(int*)*(*row));
    for(i=0;i<(*row);++i){
        array[i]=(int*)malloc(sizeof(int)*(*col));
    }
    return array;
}
void assign(int **array,int row,int col){
    int i,j;
    srand(time(NULL));

    for(i=0;i<row;++i){
        for(j=0;j<col;++j){
            array[i][j]=rand()%50;
        }
    }
}
int **increase(int **array,int *row,int *col){

int **temp;int trow=*row;int tcol=*col;
    temp=take(row,col);  
    memcpy(temp,array,sizeof(int)*trow*tcol);
    free(array);
    return temp;

}


int main(){
    int **array=NULL; int row,col;

    array=take(&row,&col); 

    assign(array,row,col);

    print(array,row,col);

    array=increase(array,&row,&col);
    array[2][0] = 1;
    free(array);
    return 0;
}

First ı am making 2 by 3 matrix and print it then increase it 3 by 4 and when trying to reach array[2][0], I am taking segmentation fault What is the problem.I checked it many times but I could not find anything


Solution

  • Rather than memcpy, realloc could be used to increase the size of array. Check the return of realloc and malloc as they can fail.
    The return of scanf should also be checked as it can fail as well.
    Instead of scanf, this uses fgets for input and parses the input with strtol in the get_int_range function.
    Using realloc allows the take and increase functions to be combined. Since the take function now has knowledge of the old and new sizes, the operation of the assign function can also be included.
    takeaway handles freeing the allocated memory.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <time.h>
    #include <errno.h>
    #include <limits.h>
    
    //inputs
    // char *line : pointer to text to be parsed
    // char **next : pointer to pointer to allow modification of caller's pointer
    // char *delim : pointer to characters to be considered terminators
    // int *value : pointer to int to allow modification of caller's int
    // int min : minimum value of range
    // int max : maximum value of range
    // returns : 0 failure or 1 success
    int get_int_range ( char *line, char **next, char *delim, int *value, int min, int max)
    {
        long int input = 0;
        char *end = NULL;//will point to end of parsed value
    
        if ( line == NULL) {
            return 0;
        }
        errno = 0;
        input = strtol ( line, &end, 10);//get the integer from the line. end will point to the end of the parsed value
        if ( ( errno == ERANGE && ( input == LONG_MAX || input == LONG_MIN))
        || ( errno != 0 && input == 0)){// parsing error from strtol
            perror ( "input");
            return 0;
        }
        if ( end == line) {// nothing was parsed. no digits
            line[strcspn ( line, "\n")] = '\0';//remove newline
            printf ( "input [%s] MUST be a number\n", line);
            return 0;// return failure
        }
        // *end is the character that end points to
        if ( *end != '\0' && !( delim && strchr ( delim, *end))) {// is *end '\0' or is *end in the set of term characters
            line[strcspn ( line, "\n")] = '\0';//remove newline
            printf ( "problem with input: [%s] \n", line);
            return 0;
        }
        if ( input < min || input > max) {// parsed value is outside of range
            printf ( "input out of range %d to %d\n", min, max);
            return 0;
        }
    
        if ( next != NULL) {// if next is NULL, caller did not want pointer to end of parsed value
            *next = end;// *next allows modification to caller's pointer
        }
        if ( value == NULL) {
            return 0;
        }
        *value = input;// *value allows modification to callers int
        return 1;// success
    }
    
    void print(int **array,int row,int col){
        int i,j;
    
        for(i=0;i<row;++i){
            for(j=0;j<col;++j){
                printf("%d ",array[i][j]);
            }
            printf("\n");
        }
    }
    
    int **take(int **array, int *row, int *col){
        char line[256] = "";
        int i;
        int each = 0;
        int newrow = 0;
        int newcol = 0;
        int valid = 0;
        int **temp = 0;
        int *temprow = 0;
    
        do {
            printf("Enter the row number for array \n");
            fgets ( line, sizeof ( line), stdin);//read a line
            valid = get_int_range ( line, NULL, "\n", &newrow, (*row) + 1, INT_MAX);// call to parse a value
        } while ( !valid);
        do {
            printf("Enter the column number for the array \n");
            fgets ( line, sizeof ( line), stdin);//read a line
            valid = get_int_range ( line, NULL, "\n", &newcol, (*col) + 1, INT_MAX);// call to parse a value
        } while ( !valid);
    
        if ( ( temp = realloc ( array, sizeof( int*) * ( newrow))) == NULL) {
            fprintf ( stderr, "problem reallocating\n");
            return array;
        }
        array = temp;
    
        for(i=0;i<(*row);++i){//realloc existing rows 
            if ( ( temprow = realloc ( array[i], sizeof ( int) * ( newcol))) == NULL) {
                fprintf ( stderr, "problem reallocating row \n");
                return array;
            }
            array[i] = temprow;
            for ( each = *col; each < newcol; each++) {
                array[i][each] = rand ( ) % 50;
            }
        }
        for(i=(*row);i<newrow;++i){// malloc new rows
            if ( ( array[i] = malloc ( sizeof ( int) * ( newcol))) == NULL) {
                fprintf ( stderr, "problem allocating row \n");
                return array;
            }
            for ( each = 0; each < newcol; each++) {
                array[i][each] = rand ( ) % 50;
            }
        }
        *row = newrow;
        *col = newcol;
        return array;
    }
    
    int **takeaway ( int **array, int *row, int *col) {//free allocated memory
        *col = 0;
        while ( *row){
            *row -= 1;
            free ( array[*row]);
        }
        free ( array);
        return NULL;
    }
    
    int main(){
        int **array=NULL;//so realloc will work on the first call
        int row = 0;
        int col = 0;
    
        srand(time(NULL));//call srand once early in the program
    
        array=take(array,&row,&col);
        print(array,row,col);
        array=take(array,&row,&col);
        array[2][0] = 1;
        print(array,row,col);
        array = takeaway ( array, &row, &col);
        return 0;
    }