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

464 views Asked by At
#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

3

There are 3 answers

0
user3121023 On BEST ANSWER

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;
}
0
2501 On

Your two dimensional matrix is represented by pointers that point to one dimensional int arrays.

The array is not a contiguous two dimensional array. Using memcpy to copy the old array to the new one, in the function increase, won't work.

You will have to iterate through each pointer and then through the array the pointer is pointing to. Basically use two nested loops, just like you do when you print the arrays.


In the function increase the code doesn't free arrays the pointer array is pointing to:

free(array);

Only the arrays of pointers is freed, when it should also free each element of the array of pointers. This is obvious if you look at how the array is allocated:

array=(int**)malloc(sizeof(int*)*(*row));
for(i=0;i<(*row);++i){
    array[i]=(int*)malloc(sizeof(int)*(*col));
}
0
BLUEPIXY On

memcpy(temp,array,sizeof(int)*trow*tcol); is wrong.
array isn't continuous int.
array is as like follows.

[int*][int*][int*]...
 |   |
 |   +-→[int][int][int]...
 |
 +-→[int][int][int]...

fix like this

#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("%2d ", array[i][j]);
        }
        printf("\n");
    }
}

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

    array = malloc(sizeof(int*) * (*row));
    for(i = 0; i < (*row); ++i){
        array[i] = calloc(*col, sizeof(int));
    }
    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, trow = *row, tcol = *col;

    temp=take(row, col);
    if(*row < trow || *col < tcol){
        printf("Was decreased.\n");
        for(int i = 0; i < *row; ++i)
            free(temp[i]);
        free(temp);
        *row = trow; *col = tcol;
        return array;//not change
    }
    for(int i = 0; i < trow; ++i){
        memcpy(temp[i], array[i], sizeof(int) * tcol);
        free(array[i]);
    }
    free(array);
    return temp;
}

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

    array=take(&row, &col); 
    assign(array, row, col);
    print(array, row, col);

    array = increase(array, &row, &col);
    //test: 2, 3 --> 3, 4
    array[2][0] = 1;
    print(array, row, col);

    for(int i = 0; i < row; ++i)
        free(array[i]);
    free(array);

    return 0;
}