首页 > 解决方案 > Accessing data from an Array of Structs through a double pointer function variable

问题描述

I'm working on a function that works as part of a larger program. My C pointer skills are a bit rusty and so I need some help here.

I keep getting segmentation fault errors, and I feel like there is a very trivial solution to my question, and any explanation would help!

Essentially, I have an empty array of structs that I need to pass through to a function as a double pointer. That function will open and read a file saving the contents of the file in the array of structs.

I need to pass it as a double pointer.

This is what I have so far:

struct node{
    int first_value;
    int second_value;
};

unsigned char readFunction(char *fileName, int *limit, struct node **arrayToFill){ //Many more variables passed, but I removed it for the sake of simplicity
    FILE *input;
    input = fopen(fileName, "r");
    if (input == NULL) {
        printf("error: could not read the input file!\n");
    }
    int i=0;
    int temp1, temp2;
    for(i=0; i<(*limit); i++){
        fscanf(input, "(%d, %d)", &temp1, &temp2);
        (*(arrayToFill+i))->first_value = temp1;
        (*(arrayToFill+i))->second_value= temp2;
    }
    //More code
    return 0; //Actually returns another array but that's irrelevant.
} 

int main(){
    //NOTE: I just created these variables for the sake of showing it on StackOverflow, I still get a Segmentation Fault error when I run the program.
    char name[9] = {'t', 'e', 's', 't', '.', 't','x','t', '\0'};
    struct node arrayToPass[10];
    struct node *pointer = &arrayToPass;
    struct node **data = &pointer;
    unsigned char returnedVal;
    int limit = 10;

    returnedVal = readFunction(&name, &limit, data);

    return 0;
}

Thanks in advance!

标签: c

解决方案


你有几个问题。首先是您arrayToPass[10]错误地使用了指针,您只需要:

int main (void) {

    struct node arrayToPass[10];
    int limit = 10;

    printf ("return: %hhu\ncontent:\n", readFunction(NULL, &limit, &arrayToPass));
    for (int i = 0; i < limit; i++)
        printf ("%5d   %5d\n", 
                arrayToPass[i].first_value, arrayToPass[i].second_value);

}

struct node (*arrayToPass)[10]当您通过分配给不同的指针传递地址时,不要尝试围绕您的指针进行强制转换。当您获取您拥有的地址(指向 struct node [10] 数组的指针)时,您从类型struct node [10]struct node [10]数组)开始。它与(指向结构节点的指针的指针)是分开的和区的。struct node (*)[10]struct node **

然后您的函数采用类型struct node (*arrayToFill)[10],例如

unsigned char readFunction (char *fileName, int *limit, struct node (*arrayToFill)[10])
{ //Many more variables passed, but I removed it for the sake of simplicity
    FILE *input;
    input = fileName ? fopen (fileName, "r") : stdin;
    if (input == NULL) {
        printf("error: could not read the input file!\n");
    }
    int i=0;
    int temp1, temp2;
    while (i < *limit && fscanf(input, " (%d, %d)", &temp1, &temp2) == 2) {
        (*arrayToFill)[i].first_value = temp1;
        (*arrayToFill)[i].second_value = temp2;
        i++;
    }
    *limit = i;

    return 0; //Actually returns another array but that's irrelevant.
} 

注意:使用三元运算符允许NULL传递为fileName读取stdin- 这只是为了我的方便)

另请注意:由于您在 中声明struct node arrayToPass[10];了自动存储持续时间main(),因此您不需要传递指针的地址,如果地址可以在您的函数中更改,则只需要传递指针的地址 - 例如如果你打电话realloc给指针。另一个答案解决了这一点。)

struct node **需要传递或struct node (*)[10]简单地struct node *归结为如何为原始集合分配内存之间的区别。如果像您所做的那样,使用自动存储持续时间struct node arrayToPass[10];声明,阵列的存储是固定的。访问时,数组被转换为指针 ( ),您可以简单地将数组本身作为参数传递。(但你被限制在不超过最初声明的元素数量)main()struct node *

但是,如果您为in分配了存储类型(例如,那么如果您需要更改存储量,例如您分配的内存块可以容纳的数量,那么您必须传递指针的地址,所以如果发生重新分配,并且您的内存块的起始地址发生更改,则该更改将在调用者(此处)中看到。在这种情况下,当您传递 的地址时,您的类型变为. (因为您已经采取了指针的地址而不是数组的地址)arrayToPassmainstruct node *arrayToPass = malloc (10 * sizeof *arrayToPass);stuct nodereadFunction()main()struct node *struct node **

由于您的arrayToPass无法重新分配,并且存储在传递给之前是固定的,因此readFunction()您不需要传递地址,您可以消除一级指针间接,只需将数组作为 type 传递struct node *。这将您的函数中的访问简化arrayToFill[i].first_value = temp1;[..]simple ,就像指针的取消引用一样->

您可能还想将返回类型从 to 更改unsigned charsize_t并返回填充在您的结构中的元素数量(有意义的返回)——或者您可以limit像我一样更新指针——您的选择。

完整的例子是:

#include <stdio.h>

struct node {
    int first_value;
    int second_value;
};

unsigned char readFunction (char *fileName, int *limit, struct node (*arrayToFill)[10])
{ //Many more variables passed, but I removed it for the sake of simplicity
    FILE *input;
    input = fileName ? fopen (fileName, "r") : stdin;
    if (input == NULL) {
        printf("error: could not read the input file!\n");
    }
    int i=0;
    int temp1, temp2;
    while (i < *limit && fscanf(input, " (%d, %d)", &temp1, &temp2) == 2) {
        (*arrayToFill)[i].first_value = temp1;
        (*arrayToFill)[i].second_value = temp2;
        i++;
    }
    *limit = i;

    return 0; //Actually returns another array but that's irrelevant.
} 

int main (void) {

    struct node arrayToPass[10];
    int limit = 10;

    printf ("return: %hhu\ncontent:\n", readFunction(NULL, &limit, &arrayToPass));
    for (int i = 0; i < limit; i++)
        printf ("%5d   %5d\n", 
                arrayToPass[i].first_value, arrayToPass[i].second_value);

}

示例输入文件

$ cat dat/2x8rand.txt
(17987, 1576)
(12911, 4488)
(30688, 5875)
(25617, 16643)
(8999, 26249)
(29270, 31857)
(8954, 2094)
(21390, 27676)

fscanf 请注意格式字符串中的更改,包括' '在左括号之前的附加(空格)'('以使用'\n'(和任何前导空格)。除非您检查返回,否则您无法正确使用任何输入功能(例如fscanf(input, " (%d, %d)", &temp1, &temp2) == 2

示例使用/输出

$ ./bin/ptrtoarraystruct < dat/2x8rand.txt
return: 0
content:
17987    1576
12911    4488
30688    5875
25617   16643
 8999   26249
29270   31857
 8954    2094
21390   27676

如果您还有其他问题,请仔细查看并告诉我。


推荐阅读