c - 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!
解决方案
你有几个问题。首先是您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分配了存储类型(例如,那么如果您需要更改存储量,例如您分配的内存块可以容纳的数量,那么您必须传递指针的地址,所以如果发生重新分配,并且您的内存块的起始地址发生更改,则该更改将在调用者(此处)中看到。在这种情况下,当您传递 的地址时,您的类型变为. (因为您已经采取了指针的地址而不是数组的地址)arrayToPass
main
struct node *arrayToPass = malloc (10 * sizeof *arrayToPass);
stuct node
readFunction()
main()
struct node *
struct node **
由于您的arrayToPass无法重新分配,并且存储在传递给之前是固定的,因此readFunction()
您不需要传递地址,您可以消除一级指针间接,只需将数组作为 type 传递struct node *
。这将您的函数中的访问简化arrayToFill[i].first_value = temp1;
为[..]
simple ,就像指针的取消引用一样->
。
您可能还想将返回类型从 to 更改unsigned char
为size_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
如果您还有其他问题,请仔细查看并告诉我。
推荐阅读
- c# - Cefsharp 从 html 按钮获取坐标
- azure-data-factory - 在数据工厂管道中构建 JSON 的适当方法是什么
- python - 为什么 gevent.sleep(0) 不产生,需要一个非零值才能这样做?
- php - 使用 FauxAPI 查询将用户添加到具有 PHP 功能的用户的 freeradius config xml 列表
- mysql - 带有 WHERE != TWICE 的 SQL 语句
- java - openjdk中的networkaddress.cache.ttl null
- numbers - 为传真号码编写正则表达式。和电话号码不一样
- python - 提取随机数并逐步排除生成随机数的函数
- azure - 是否可以在运行时从数据工厂中的 Azure 函数链接服务中读取参数?
- mysql - 恢复在 mysql 8 中使用 PASSWORD() 创建的密码