我正在学习C中的指针和动态数组,但我不清楚C中的指针。如果有人能根据以下信息验证我对以下代码的理解,我将不胜感激:
/*Struct*/
typedef struct {
int *pInt;
}newStruct
/*Functions*/
newStruct *createMyStruct() {
//codes
}
void printNewStruct(newStruct *pStruct) {
//codes
}
请确认:
int *pInt
:这是一个类型为int的数组,位于struct newStruct *createMyStruct
:一个名为createMyStruct
的函数。 createMyStruct
是指向newStruct
的指针,并创建newStruct
的副本。 newStruct *pStruct
:pStruct
与createMyStruct
相同(?)问题:
1)当我在函数中使用malloc
(例如上面代码中的createMyStruct
函数)来分配内存时,我必须在哪里释放这个内存?在函数本身内部或main
中?如果在main
中,为什么在main
?我认为记忆必须在使用后立即释放。
如果我的上述陈述不清楚,我道歉......我仍然对指针和malloc
感到困惑。请以简单的方式验证/解释新手。
答案 0 :(得分:3)
好的,我们试着澄清一下:
1)int *pInt
是指向整数的指针。这可能指向数组的第一个值,但它不必
2)newStruct *createMyStruct()
是一个函数,它具有指向newStruct结构的指针的返回值。很可能你想在这个函数中malloc
并让它返回指针
3)newStruct *pStruct
表示此函数的输入参数是指向newStruct结构的指针,在本例中名为pStruct(我假设您知道如何处理C中的参数)
至于你的问题:它有点取决于你何时不再需要分配的内存。如果您在free
函数中createMyStruct()
,则基本上会返回指向无效位置的指针(如果您尝试取消引用它,则会导致未定义的行为)。通常,只有当您完全确定不再需要分配的内容时,才应free
分配的内存。您可以在main
中执行此操作,也可以编写自己调用的函数。
答案 1 :(得分:1)
1 - 如果你malloc
记忆,你必须释放它。在哪里并不重要。当你不再使用内存时,你应该这样做。它不一定要立刻,但你应该在你知道可以的时候这样做,否则你必须记得以后再释放它。
你说
我认为记忆必须在使用后立即释放。
这只是建议。但这是非常好的建议。你永远不会释放它,并继续使用记忆。您可能内存不足或程序可能崩溃。 C不会帮助你,你能做的最好的事情就是坚持建议。
这个含糊的建议,但只有你这个程序员知道最好的地方。这并不容易,但内存管理并不容易。
2 - 您需要记住数组的大小,因为C不会检查您是malloc(3)
还是访问struct.pInt[4]
。您可以将此大小存储为结构中的变量。
答案 2 :(得分:1)
好的,我不打算给你1on1指针指南(我不打算写一本书),但这里是根据你的假设/问题的快速指南:
int *pInt
:这是一个类型为int的数组,位于结构” 可能是,pInt
是指向整数的指针。它不一定是一个数组。 数组是指针,但指针并不总是数组。是的,一个数组当然是一个数组,但你在C中访问它的方式是通过 数组变量或指针。
差异为clearly explained here
基本上:一个数组是一个连续的内存块,一个数组变量经常(好吧,总是保存在我上面链接的页面上列出的3个案例)衰变成一个指针。阅读原因和方法,以便清楚地了解指针和数组之间的差异和相似之处。
如果你理解为什么不允许下面的一个片段而另一个片段是,你就在那里:
char *str = "Read only";
printf("%c\n", str[2]);//prints a from (0=>r, 1=>e, 3=> a...)
str[2] = 'q';//ILLEGAL
//BUT:
char str[] = "Read only";
str[2] = 'q';//perfectly legal...
printf("%c\n", str[2]);//prints q!
这是为什么?简单。在这两种情况下,文字"Read only"
都存储在只读存储器中。不同之处在于,通过将此字符串分配给指针(char *str
),我们将只读mem地址分配给变量,因此我们无法更改它指向的内存(这就是读取的内容)只是意味着。)
在第二种情况下,字符串文字存储在同一个只读内存中,但由于我们将它分配给一个数组,它的值被复制到新分配的堆栈内存中,我们可以写那个。
因此,指针指向到内存中的某些数据块。这个内存可以写或不可写,内存地址可以是数组的一部分地址,也可以是单个int(就像你的情况一样),你甚至可以指向几个指针,每个指针这些指针本质上可以指向内存中的不同位置(即不是连续的块) 无论如何,考虑一下:
int i = 123;
int arr[3] = {1,2,3};//array
int *iPtr = &i;//iPtr contains the mem address of i
printf("%d\n", *iPtr);//prints 123
iPtr = arr;//iPtr points to the same as arr (note no & operator)
printf("%d\n", *iPtr);//prints 1
//now probably a mindfuck for you now, but:
printf("%d\n", *(iPtr+1));//prints 2!
最后一点只是为了显示指针是什么:它是内存中的一个位置,大到足以容纳int
,所以如果我在内存中占用那个空间,那么+1
,我m访问我的指针指向的那个内存块。在内存中,这可能看起来像这样:
| 0x0f0 | 0x0f2 | 0x0f4 | 0x0f6 | //mem address
| *iPtr | iPtr + 1 | iPtr + 2 | iPtr + 3 | //access via pointer
这就是为什么指针可以是危险的。在上面的代码中,iPtr
指向3个int中的第一个(在arr
数组中定义),但如果我访问*(iPtr+4)
,我将访问超出范围的内存。您正在访问未声明/初始化或由其他内容拥有的内存。这可能,并且可能将导致意外行为......但我已经看到过这种方法可以获得额外的随机化......
newStruct *createMyStruct
:一个名为createMyStruct的函数.createMyStruct是一个指向newStruct并创建newStruct副本的指针。” 你在这里迷了我,这是一个功能定义。该函数确实称为createMyStruct
,它返回指向newStruct
类型的指针。就是这样,就像int some_function()
是一个返回int
newStruct *pStruct
:pStruct与createMyStruct(?)”相同“ 不,pStruct
是指向newStruct
的指针,而pStruct
是函数参数,而不是函数createMyStruct
。
免费拨打电话:
当你不再需要它们时,你可以调用存储在从堆分配的内存中的变量的free
。如果它们超出范围,你就不能再释放它们了,所以当你还有一个指向它的变量时你必须释放内存,但是你不应该在程序中释放你可能需要的任何东西: / p>
char *str = calloc(11, sizeof(char));
free(str);
//I can't use str here anymore
可是:
int main()
{
void some_function();
some_function();
//I can't free str here, mem-leak immanent!
return 0;
}
void some_function()
{
char *str = calloc(11, sizeof(char));
//do stuff, but no calls to free
}
在这种情况下,free(str);
应该是some_function
中的最后一个语句。如果some_function
已成为char *some_function()
而我们已经写过:
int main()
{
char *return_val = NULL;
char *some_function();
return_val = some_function();
printf("%s was returned by some_function\n", return_val);
//the allocated memory is accessible here
//And it has to be freed before main returns, so:
free(return_val);//deallocate!
return 0;
}
char *some_function()
{
char *str = calloc(11, sizeof(char));
//do stuff, but no calls to free
return str;//return char pointer
}
以return str
结束,然后你必须在free
函数中调用main
,因为它有一个指向已分配内存的指针。
就是这样,简而言之......
答案 3 :(得分:0)
int * pInt - 它只是指向一些可能存在的数组的指针(没有空间可以放入数据,它可以稍后指向内存中的某个位置以用作整数数组,如果你设置它)
newStruct * createMyStruct:一个名为createMyStruct的函数。 这是正确的。
createMyStruct is a pointer that points to newStruct and create a copy of the newStruct
不,它是指向函数(或函数名)的指针,但函数会向您的结构返回一个指针(newStruct *),如果您实现了该函数,您将获得分配并初始化结构可供使用< / p>
newStruct * pStruct - 它与createMyStruct不同,pStruct将是未初始化的指针,createMyStruct是你的功能
以下是如何使用您的结构和方法:
int main()
{
newStruct *pStruct = NULL; // nothing there yet
pStruct = createMyStruct();
if(pStruct==NULL) { printf("error"); }
pStruct->pInt[0] = 123;
...
free(pStruct->pInt); // you have to free the array in your struct too
free(pStruct);
return 0;
}
如果您想知道将空闲放在哪里,请查看示例主函数... pStruct在main的开头声明并初始化,并在结束时自由。在大多数情况下,将内存释放到最初分配它的同一级别(函数)就足够了。