C Passing Pointer to Pointer to a Function and Using malloc

两盒软妹~` 提交于 2021-02-05 08:32:16

问题


I'm trying to get std input to scan in two 2d parallel arrays (arrAtk, arrDef) of x rows (x<100), and y columns (y<1,000,000). But y is a variable length in each row.

The first line of input is x for the number of rows in each array. the second line is y for the number of columns in the first row. Following that is y integers to be read into the arrAtk array. Then another y integers to be read into the arrDef array. Directly following is an int y for the number of columns in the next two rows. And so on.

The parallel arrays will hold integers that will be sorted later, and each parallel element will be compared to see which of the rows had higher numbers.

Problem: So I'm trying to scan the input with a function call and dynamically allocate the correct amount of memory and scan the input for each row of the 2d arrays. This seems to work okay but then when I try to print the array values in main it crashes. The printf statements work in the scanIn function so I must not be passing values correctly. How can I get it to where I can use the dynamically created arrays outside of the function?

Thanks in advance

Example of std input:

2  //<- x num of rows 
2  //<- y num of cols
3 
6
5
2
3  //<- y num of cols
2
3
12
9
3
4

CODE:

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

int scanIn(int**,int**,int*);

int main(){
    int cases, *armies, **arrAtk, **arrDef;

    cases = scanIn(arrAtk,arrDef,armies);

    printf("%d\n",arrAtk[1][2]); // Should be 12 with above input
    printf("%d",arrDef[0][1]);   // Should be 2

    return 0;
}

int scanIn(int **arrAtk, int **arrDef, int *armies){
    int i, j, cases;

    scanf("%d",&cases);
    arrAtk = (int**)malloc(sizeof(int*)*cases);
    arrDef = (int**)malloc(sizeof(int*)*cases);
    armies = (int*)malloc(sizeof(int)*cases);

    for(i=0;i<cases;i++){
        scanf("%d",&armies[i]);
        arrAtk[i] = malloc(sizeof(int)*armies[i]);
        arrDef[i] = malloc(sizeof(int)*armies[i]);

        for(j=0;j<armies[i];j++){
            scanf("%d",&arrAtk[i][j]);
        }
        for(j=0;j<armies[i];j++){
            scanf("%d",&arrDef[i][j]);
        }
    }
    return (cases);
}

回答1:


While there are better ways of doing this, it can be done with the approach you have taken. The first thing to note is you were passing each pointer to your function instead of the address of the pointer. When that occurs, your function receives a copy of the pointer, containing the proper address for the values (if initialized), but with a very different address of its own.

So when you allocate storage for each of your arrays in the function, the pointers in main are completely unchanged. They still point to nothing. In order to have the allocations reflected in main you must pass the address of the pointer to your function, and dereference accordingly in your function, so that the allocations are available in main.

The short version is you need to call your function with scanIn (&arrAtk, &arrDef, &armies) and your prototype must be (int***, int***, int**). (not particularly attractive)

One other issue is that style in C generally avoids the use of caMelCase variables (leave that for C++). See: (section 2.2) NASA C Style Guide (Goddard Spaceflight Center 1994)

Below is an example of the additional level of indirection required to make the allocation work as you intended. (note: you should also free the memory you allocate):

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

int scan_in (int***, int***, int**);

int main (void) {

    int cases, *armies, **arr_atk, **arr_def;

    cases = scan_in (&arr_atk, &arr_def, &armies);

    printf ("\n cases         : %d\n", cases);
    printf (" arr_atk[1][2] : %d\n", arr_atk[1][2]);
    printf (" arr_def[0][1] : %d\n\n", arr_def[0][1]);

    return 0;
}

int scan_in (int ***arr_atk, int ***arr_def, int **armies)
{    
    int i, j, cases;

    scanf ("%d",&cases);
    *arr_atk = malloc (sizeof **arr_atk * cases);
    *arr_def = malloc (sizeof **arr_def * cases);
    *armies = malloc (sizeof *armies * cases);

    for (i = 0; i < cases; i++) {
        scanf ("%d", &(*armies)[i]);
        (*arr_atk)[i] = malloc (sizeof ***arr_atk * (*armies)[i]);
        (*arr_def)[i] = malloc (sizeof ***arr_def * (*armies)[i]);

        for (j = 0; j < (*armies)[i]; j++) {
            scanf ("%d", &(*arr_atk)[i][j]);
        }
        for (j = 0; j < (*armies)[i]; j++) {
            scanf ("%d", &(*arr_def)[i][j]);
        }
    }
    return (cases);
}

Input

$ cat ../dat/2dscan.txt
2
2
3
6
5
2
3
2
3
12
9
3
4

Output

$ ./bin/2dscanin < ../dat/2dscan.txt

 cases         : 2
 arr_atk[1][2] : 12
 arr_def[0][1] : 2

note: since you are new to C, there are a few more areas where you can improve your code: (1) always initialize your variables that are not explicitly assigned a value in your code; (2) always validate the return values from the functions you call; and (3) always keep track of, and free the memory you allocate when it is no longer needed. Taking that into consideration, your main and scan_in code would look like:

int main (void) {

    int i, cases = 0, *armies = NULL, **arr_atk = {NULL}, **arr_def = {NULL};

    if ((cases = scan_in (&arr_atk, &arr_def, &armies)) < 1) {
        fprintf (stderr, "error: invalid value for cases returned.\n");
        return 1;
    }

    printf ("\n cases         : %d\n", cases);
    printf (" arr_atk[1][2] : %d\n", arr_atk[1][2]);
    printf (" arr_def[0][1] : %d\n\n", arr_def[0][1]);

    for (i = 0; i < cases; i++) { /* free allocated memory */
        if (arr_atk[i]) free (arr_atk[i]);
        if (arr_def[i]) free (arr_def[i]);
    }
    if (arr_atk) free (arr_atk);
    if (arr_def) free (arr_def);
    if (armies)  free (armies);

    return 0;
}

int scan_in (int ***arr_atk, int ***arr_def, int **armies)
{    
    int i, j, cases;

    if (scanf ("%d",&cases) != 1) {
        fprintf (stderr, "scan_in() error: input failure.\n");
        return 0;
    }
    *arr_atk = malloc (sizeof **arr_atk * cases);
    *arr_def = malloc (sizeof **arr_def * cases);
    *armies = malloc (sizeof *armies * cases);

    for (i = 0; i < cases; i++) {
        if (scanf ("%d", &(*armies)[i]) != 1) {
            fprintf (stderr, "scan_in() error: input failure.\n");
            return 0;
        }
        (*arr_atk)[i] = malloc (sizeof ***arr_atk * (*armies)[i]);
        (*arr_def)[i] = malloc (sizeof ***arr_def * (*armies)[i]);

        for (j = 0; j < (*armies)[i]; j++) {
            if (scanf ("%d", &(*arr_atk)[i][j]) != 1) {
                fprintf (stderr, "scan_in() error: input failure.\n");
                return 0;
            }
        }
        for (j = 0; j < (*armies)[i]; j++) {
            if (scanf ("%d", &(*arr_def)[i][j]) != 1) {
                fprintf (stderr, "scan_in() error: input failure.\n");
                return 0;
            }
        }
    }
    return (cases);
}


来源:https://stackoverflow.com/questions/35853776/c-passing-pointer-to-pointer-to-a-function-and-using-malloc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!