C编程:即使在双指针的内容上完成,指针的分配也会丢失
C programming: allocation of pointer lost even when done on the contents of a double pointer
所以,我一直在努力解决这个问题,在深夜费尽心机之后,我决定看看你们是否都想尝试一下。
总而言之,我试图通过将分配代码移交给 main 之外的另一个函数来设置一个动态分配的结构以供在程序中使用。我知道有两种方法可以做到这一点:一种是让函数 return 指向分配的结构的指针,例如:
typeStruct *someFunction()
或者两个,传入一个指向结构的双指针,取消引用它,并在内部指针上分配内存。喜欢:
void someFunction(typeStruct **ptr)
我正在尝试执行后者,因为我想将 return 值用于 char 标志而不是结构本身。
不幸的是,对指针的引用所做的更改似乎没有超出函数的范围。我设法用一个更简单的示例程序复制了我的问题。这是代码:
test.c:
#include "testheader.h"
int main() {
char success = 0;
test *t;
printf("\nBefore setup (in Main), Test: %d", t);
success = setupTest(&t);
printf("\nAfter setup (in Main), Test: %d", t);
free(t->numbers);
free(t);
return success;
}
testheader.c:
#include "testheader.h"
const int NUM_NUMBERS = 100;
char setupTest(test **ptr) {
printf("\nBefore deference, Test: %d", *ptr);
char flag = 0;
test *t = *ptr;
printf("\nBefore malloc, Test: %d", t);
t = malloc(sizeof(test));
printf("\nAfter malloc, Test: %d", t);
if(t != NULL) {
t->numbers = malloc(sizeof(int) * NUM_NUMBERS);
if(t->numbers != NULL) {
for(int i = 0; i < NUM_NUMBERS; ++i) t->numbers[i] = i;
} else flag = 1;
} else flag = 1;
printf("\nEnd of setup, Test: %d", t);
return flag;
}
testheader.h:
#ifndef TESTHEADER_H
#define TESTHEADER_H
#include <stdlib.h>
#include <stdio.h>
typedef struct test_t {
int *numbers;
} test;
char setupTest(test **);
#endif
我是这样编译的:gcc test.c testheader.c -o test.exe
我正在使用 gcc 5.1.0 在 git bash 和 Windows 10 的控制台中编译到 运行。
这是 运行ning test.exe 的输出:
Console debugging
然后它崩溃了。正如您所看到的,函数内部的行为符合预期,尽管它外部的代码并未反映内部所做的分配,就好像我只是传递了指针本身,而不是使用双指针通过引用传递。
这里有我遗漏的东西吗?
诊断:
线条
test *t = *ptr;
t = malloc(sizeof(test));
只影响局部变量t,不影响**ptr的内容
解决方案:
malloc 在 **ptr 的内容而不是局部变量上,这样分配就不会超出 return 的范围。并交换两条线。
*ptr = malloc(sizeof(test));
test *t = *ptr;
test *t = *ptr;
我不知道你是否认为这是在 t
和 ptr
之间建立某种持久的 link(比如C++ 参考),但事实并非如此。它只是将后者分配给前者,当您到达时,这将变得毫无意义:
t = malloc(sizeof(test));
其中 t
被覆盖。
在那之后你缺少的是某种形式的返回 **ptr
的赋值,这意味着它保留了输入时的任何值。当然,这就是您所看到的。
您需要做的是获取t
的值并用它填充传入的变量:
*ptr = t;
您还可以稍微清理一下您的函数,确保它是原子的——要么一切都应该完成,要么什么都不做 (特别是在内存分配方面)。 Thius 包括对您在地址中传递的指针的任何更改:
int setupTest(test **ptr) {
// Allocate a test structure. If fail, return indication.
test *t = malloc(sizeof(test));
if (t == NULL) {
return 0;
}
// Allocate a numbers sub-structure. If fail,
// free test structure and return indication.
t->numbers = malloc(sizeof(int) * NUM_NUMBERS);
if (t->numbers == NULL) {
free(t);
return 0;
}
// Have both structures, populate and return success.
for (int i = 0; i < NUM_NUMBERS; ++i) {
t->numbers[i] = i;
}
*ptr = t;
return 1;
}
你可以这样考虑:
因为 test *p
=> p = malloc()
所以 test **p
=> *p = malloc()
它应该 malloc 到 *ptr 而不是 ptr。
char setupTest(test **ptr) {
printf("\nBefore deference, Test: %d", *ptr);
char flag = 0;
test **t = ptr;
printf("\nBefore malloc, Test: %d", *t);
*t = malloc(sizeof(test));
printf("\nAfter malloc, Test: %d", *t);
if(t != NULL) {
(*t)->numbers = malloc(sizeof(int) * NUM_NUMBERS);
if((*t)->numbers != NULL) {
for(int i = 0; i < NUM_NUMBERS; ++i) (*t)->numbers[i] = i;
} else flag = 1;
} else flag = 1;
printf("\nEnd of setup, Test: %d", *t);
return flag;
}
或者,直接 malloc 到 *ptr
char setupTest(test **ptr) {
printf("\nBefore deference, Test: %d", *ptr);
char flag = 0;
printf("\nBefore malloc, Test: %d", *ptr);
*ptr = malloc(sizeof(test));
printf("\nAfter malloc, Test: %d", *ptr);
if(*ptr != NULL) {
(*ptr)->numbers = malloc(sizeof(int) * NUM_NUMBERS);
if((*ptr)->numbers != NULL) {
for(int i = 0; i < NUM_NUMBERS; ++i) (*ptr)->numbers[i] = i;
} else flag = 1;
} else flag = 1;
printf("\nEnd of setup, Test: %d", *ptr);
return flag;
}
所以,我一直在努力解决这个问题,在深夜费尽心机之后,我决定看看你们是否都想尝试一下。
总而言之,我试图通过将分配代码移交给 main 之外的另一个函数来设置一个动态分配的结构以供在程序中使用。我知道有两种方法可以做到这一点:一种是让函数 return 指向分配的结构的指针,例如:
typeStruct *someFunction()
或者两个,传入一个指向结构的双指针,取消引用它,并在内部指针上分配内存。喜欢:
void someFunction(typeStruct **ptr)
我正在尝试执行后者,因为我想将 return 值用于 char 标志而不是结构本身。
不幸的是,对指针的引用所做的更改似乎没有超出函数的范围。我设法用一个更简单的示例程序复制了我的问题。这是代码:
test.c:
#include "testheader.h"
int main() {
char success = 0;
test *t;
printf("\nBefore setup (in Main), Test: %d", t);
success = setupTest(&t);
printf("\nAfter setup (in Main), Test: %d", t);
free(t->numbers);
free(t);
return success;
}
testheader.c:
#include "testheader.h"
const int NUM_NUMBERS = 100;
char setupTest(test **ptr) {
printf("\nBefore deference, Test: %d", *ptr);
char flag = 0;
test *t = *ptr;
printf("\nBefore malloc, Test: %d", t);
t = malloc(sizeof(test));
printf("\nAfter malloc, Test: %d", t);
if(t != NULL) {
t->numbers = malloc(sizeof(int) * NUM_NUMBERS);
if(t->numbers != NULL) {
for(int i = 0; i < NUM_NUMBERS; ++i) t->numbers[i] = i;
} else flag = 1;
} else flag = 1;
printf("\nEnd of setup, Test: %d", t);
return flag;
}
testheader.h:
#ifndef TESTHEADER_H
#define TESTHEADER_H
#include <stdlib.h>
#include <stdio.h>
typedef struct test_t {
int *numbers;
} test;
char setupTest(test **);
#endif
我是这样编译的:gcc test.c testheader.c -o test.exe
我正在使用 gcc 5.1.0 在 git bash 和 Windows 10 的控制台中编译到 运行。
这是 运行ning test.exe 的输出: Console debugging
然后它崩溃了。正如您所看到的,函数内部的行为符合预期,尽管它外部的代码并未反映内部所做的分配,就好像我只是传递了指针本身,而不是使用双指针通过引用传递。
这里有我遗漏的东西吗?
诊断:
线条
test *t = *ptr;
t = malloc(sizeof(test));
只影响局部变量t,不影响**ptr的内容
解决方案:
malloc 在 **ptr 的内容而不是局部变量上,这样分配就不会超出 return 的范围。并交换两条线。
*ptr = malloc(sizeof(test));
test *t = *ptr;
test *t = *ptr;
我不知道你是否认为这是在 t
和 ptr
之间建立某种持久的 link(比如C++ 参考),但事实并非如此。它只是将后者分配给前者,当您到达时,这将变得毫无意义:
t = malloc(sizeof(test));
其中 t
被覆盖。
在那之后你缺少的是某种形式的返回 **ptr
的赋值,这意味着它保留了输入时的任何值。当然,这就是您所看到的。
您需要做的是获取t
的值并用它填充传入的变量:
*ptr = t;
您还可以稍微清理一下您的函数,确保它是原子的——要么一切都应该完成,要么什么都不做 (特别是在内存分配方面)。 Thius 包括对您在地址中传递的指针的任何更改:
int setupTest(test **ptr) {
// Allocate a test structure. If fail, return indication.
test *t = malloc(sizeof(test));
if (t == NULL) {
return 0;
}
// Allocate a numbers sub-structure. If fail,
// free test structure and return indication.
t->numbers = malloc(sizeof(int) * NUM_NUMBERS);
if (t->numbers == NULL) {
free(t);
return 0;
}
// Have both structures, populate and return success.
for (int i = 0; i < NUM_NUMBERS; ++i) {
t->numbers[i] = i;
}
*ptr = t;
return 1;
}
你可以这样考虑:
因为 test *p
=> p = malloc()
所以 test **p
=> *p = malloc()
它应该 malloc 到 *ptr 而不是 ptr。
char setupTest(test **ptr) {
printf("\nBefore deference, Test: %d", *ptr);
char flag = 0;
test **t = ptr;
printf("\nBefore malloc, Test: %d", *t);
*t = malloc(sizeof(test));
printf("\nAfter malloc, Test: %d", *t);
if(t != NULL) {
(*t)->numbers = malloc(sizeof(int) * NUM_NUMBERS);
if((*t)->numbers != NULL) {
for(int i = 0; i < NUM_NUMBERS; ++i) (*t)->numbers[i] = i;
} else flag = 1;
} else flag = 1;
printf("\nEnd of setup, Test: %d", *t);
return flag;
}
或者,直接 malloc 到 *ptr
char setupTest(test **ptr) {
printf("\nBefore deference, Test: %d", *ptr);
char flag = 0;
printf("\nBefore malloc, Test: %d", *ptr);
*ptr = malloc(sizeof(test));
printf("\nAfter malloc, Test: %d", *ptr);
if(*ptr != NULL) {
(*ptr)->numbers = malloc(sizeof(int) * NUM_NUMBERS);
if((*ptr)->numbers != NULL) {
for(int i = 0; i < NUM_NUMBERS; ++i) (*ptr)->numbers[i] = i;
} else flag = 1;
} else flag = 1;
printf("\nEnd of setup, Test: %d", *ptr);
return flag;
}