0

我正在学习 C 中的指针和动态数组,但我不清楚 C 中的指针。如果有人可以根据以下信息验证我对以下代码的理解,我将不胜感激:

/*Struct*/
typedef struct {
   int *pInt;    
}newStruct

/*Functions*/
newStruct *createMyStruct() {  
   //codes
}

void printNewStruct(newStruct *pStruct) {
   //codes
}

请验证:

  1. int *pInt:这是一个 int 类型的数组,位于结构中
  2. newStruct *createMyStruct: 一个名为createMyStruct. createMyStruct是一个指针,它指向newStruct并创建newStruct.
  3. newStruct *pStruct:pStructcreateMyStruct(?)一样

问题:
1)当我malloc在一个函数(例如createMyStruct上面代码中的函数)中使用来分配内存时,我必须在哪里释放这个内存?在函数内部还是在main? 如果在main,为什么在main?我认为内存在使用后必须立即释放。

如果我的上述陈述不清楚,我深表歉意......我仍然对指针和malloc. 请为新手简单地验证/解释。

4

4 回答 4

3

好的,让我们试着澄清一下:1)int *pInt是一个指向整数的指针。这可以指向数组的第一个值,但不是必须的。
2)newStruct *createMyStruct()是一个函数,它具有指向 newStruct 结构的指针的返回值。很可能你想malloc在这个函数中让它返回指针。
3)newStruct *pStruct表示此函数的输入参数是指向 newStruct 结构的指针,在本例中名为 pStruct(我假设您知道如何在 C 中处理参数)

至于您的问题:这取决于您何时不再需要分配的内存。如果你freecreateMyStruct()函数中使用它,你基本上会返回一个指向无效位置的指针(如果你试图取消引用它会导致未定义的行为)。通常,free只有当您完全确定不再需要您分配的任何内容时,您才应该分配您分配的内存。您可以在您的main或编写您自己调用的函数中执行此操作。

于 2013-10-28T14:43:16.703 回答
1

1 - if you malloc memory, you have to free it. It doesn't matter where. You should do it when you are no longer using the memory. It doesn't have to be immediately, but you should probably do it when you know you can, otherwise you have to remember to free it later.

You said

I thought the memory has to be freed right away after it has been used.

That's just advice. But it's very good advice. You could never free it, and keep using memory. You might run out of memory or your program might crash. C will not help you, the best thing you can do is stick to advice.

That's vague advice, but only you, the programmer, know the best place to do it. It's not easy, but memory management isn't easy.

2 - You need to remember how big the array is, because C will not check if you malloc(3) but access struct.pInt[4]. You could store this size as a variable in the struct.

于 2013-10-28T14:42:45.693 回答
1

好的,我不会给你一个一对一的指针指南(我不打算写一本书),但这里是基于你的假设/问题的快速指南:

  • int *pInt:这是结构中的 int 类型数组”

它可能pInt是一个指向整数的指针。它不必是一个数组。数组指针,但指针并不总是数组。没错,数组当然是数组,但是在 C 中访问它的方式是通过数组变量或指针。此处清楚地解释了
差异

基本上:一个数组是一个连续的内存块,一个数组变量经常(嗯,总是保存我上面链接到的页面上列出的 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!

为什么是这样?简单的。在这两种情况下,literall"Read only"都存储在只读存储器中。不同之处在于,通过将此字符串分配给指针(char *str),我们将只读内存地址分配给变量,因此我们无法更改它指向的内存(这就是只读的意思)。
在第二种情况下,字符串字面量存储在同一个只读内存中,但是因为我们将它分配给一个数组,所以它的值被复制到新分配的堆栈内存中,我们可以对其进行写入。

因此,指针指向内存中的一些数据块。该内存可以是可写的,也可以是不可写的,内存地址可以是数组的一部分的地址,也可以是单个 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一个指着。在内存中,这可能看起来像这样:

| 0x0f0 |   0x0f2  |  0x0f4   |  0x0f6   | //mem address
| *iPtr | iPtr + 1 | iPtr + 2 | iPtr + 3 | //access via pointer

这就是为什么指针可能很危险的原因。在上面的代码中,iPtr指向 3 个整数中的第一个(在arr数组中定义),但是如果我访问*(iPtr+4),我正在访问超出范围的内存。您正在访问未声明/初始化的内存,或由其他人拥有的内存。这可能并且可能导致意外的行为......但我已经看到这用于获得一些额外的随机化......

  • " newStruct *createMyStruct: 一个名为 createMyStruct 的函数。createMyStruct 是一个指向 newStruct 并创建 newStruct 副本的指针。"

你把我弄丢了,这是一个函数定义。该函数确实被调用createMyStruct了,它返回一个指向该类型的指针newStruct。就是这样,就像int some_function()一个返回 int 的函数

  • " newStruct *pStruct: pStruct 与 createMyStruct (?) 相同"

不,pStruct是指向 a 的指针newStruct,并且pStruct是函数参数,而不是函数createMyStruct

免费通话时:

free当您不再需要它们时,您可以调用存储在从堆分配的内存中的变量。如果它们超出范围,您将无法再释放它们,因此当您仍然有一个指向它的变量时,您必须释放内存,但您不应该释放您稍后在程序中可能需要的任何内容:

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,那么您必须调用freemain函数,因为它有一个指向已分配内存的指针。

就是这样,简而言之...

于 2013-10-28T14:51:57.097 回答
0
  1. int *pInt - it's just a pointer to some possibly existing array (there's no space to put data in, it could point later to some place in memory to be used as array of ints, if you set it)

  2. newStruct *createMyStruct: a function that's named createMyStruct. This is correct.

    createMyStruct is a pointer that points to newStruct and create a copy of the newStruct
    

    No, it's the pointer to the function (or the function name), but the function returns a pointer (newStruct*) to your structure, if you implement the function right you'll get allocated and initialized structure ready to use

  3. newStruct *pStruct - it's not the same as createMyStruct, pStruct will be uninitialized pointer,createMyStruct is your function

Here is how you would use your structure and methods:

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;
} 

If you're wondering where to put the free, look at the example main function... The pStruct is declared and initialized at the beginning of main and free'd at it's end. For the most of the time, it's sufficient to free the memory at the same level (function) you did originally allocate it.

于 2013-10-28T14:42:49.947 回答