C - 结构的指针

时间:2016-10-28 15:10:44

标签: c pointers struct

我认为我总体上无法理解指针。 我似乎无法遵循此代码的逻辑:

    typedef struct StackRecord
{
    int Capacity;
    int TopOfStack;
    int* Array;
}*Stack;

在以下结构中,声明 * Stack 接收 StackRecord 结构类型的地址,只需根据typedef声明 Stack

但是下面的代码返回另一个 StackRecord 结构类型的地址接收器。为什么不归还地址?而是将相同类型的指针返回给自己?

Stack CreateStack(int MaxElements)
{
    Stack S;

    if (MaxElements < MinStackSize)
    {
        printf("Error : Stack size is too small");
        return 0;
    }
    S = (Stack)malloc(sizeof(struct StackRecord));

    if (S == NULL)
    {
        printf("FatalError : Out of Space!!!");
        return 0;
    }

    S->Array = (int*)malloc(sizeof(char)* MaxElements);

    if (S->Array == NULL)
    {
        printf("FatalError : Out of Space!!!");
        return 0;
    }
    S->Capacity = MaxElements;
    MakeEmpty(S);

    return S;
}

3 个答案:

答案 0 :(得分:2)

在typedef中,类型标识符Stack是指向结构的指针。 CreateStack()的函数原型指定类型Stack的返回值,它是指向StackRecord结构的指针。 S在函数体中声明为Stack类型,因此该函数确实返回指向StackRecord结构的指针。

答案 1 :(得分:2)

摆脱typedef 可能让事情变得更清晰,信不信由你:

struct StackRecord
{
    int Capacity;
    int TopOfStack;
    int* Array;
};

/**
 * Return a pointer to a new, dynamically allocated instance
 * of struct StackRecord
 */
struct StackRecord *CreateStack(int MaxElements) 
{
    struct StackRecord *S;

    if (MaxElements < MinStackSize)
    {
        printf("Error : Stack size is too small");
        return 0;
    }
    S = malloc(sizeof *S); // no need for cast, sizeof *S is same as sizeof (struct StackRecord)

    if (S == NULL)
    {
        printf("FatalError : Out of Space!!!");
        return 0;
    }

    /**
     * Allocate the memory for the Array member of
     * the new stack record instance.
     */
    S->Array = malloc( sizeof *S->Array * MaxElements );

    if (S->Array == NULL)
    {
        printf("FatalError : Out of Space!!!");
        return 0;
    }
    S->Capacity = MaxElements;
    MakeEmpty(S);

    return S;
}

在您发布的代码中,Stack基本上是struct StackRecord *的同义词。该函数使用struct StackRecord创建malloc的新实例,初始化该记录的内容,并返回指向该新实例的指针。

关于malloc调用的注释 - 在C中,您不需要转换malloc的结果,这样做通常被认为是不好的做法 1 。此外,sizeof的操作数不必是类型名称 - 它可以是 类型的表达式。 IOW,给出了像

这样的声明
T *p;

sizeof (T)sizeof *p都做同样的事情 - 表达式 *p的类型为T。所以malloc调用的一般形式可以写成

T *p = malloc( sizeof *p * N );

T *p;
...
p = malloc( sizeof *p * N );

这比

更容易编写和维护
p = (T *) malloc( sizeof (T) * N );

&LT;咆哮&GT;

隐藏typedef后面的类型的指针是坏juju,尤其是当该类型的用户必须知道他或她正在处理指针类型。将malloc的结果分配给S意味着S 必须是指针类型。使用->访问S成员意味着S 必须成为指向structunion类型的指针。由于 要知道S是指针,因此将指针隐藏在typedef后面是没有意义的。同样,如果用户必须知道该类型的struct - ness,则不应该隐藏struct - 或者在typedef后面。

抽象是一种强大的工具,但像原始代码这样的部分(漏洞)抽象只会让每个人的生活更加混乱(正如你自己发现的那样)。

&LT; /咆哮&GT;

<小时/>

  1. 对于C ++,这是 true,因为C ++不允许在void *和其他指针类型之间以C的方式进行隐式转换。但是,如果你正在编写C ++,那么你不应该使用malloc

答案 2 :(得分:1)

在对@ DavidBowling的回答中,你表达了这种明显的误解:

  

Stack是指向StackRecord的指针,这意味着指针必须包含它指向的另一个地址。

typedef将标识符Stack声明为类型struct StackRecord *的别名。如果以这种完全相同的形式重写,那也许会更清楚:

struct StackRecord
{
    int Capacity;
    int TopOfStack;
    int* Array;
};

typedef struct StackRecord *Stack;

没有声明struct StackRecord类型的对象,只声明该类型本身并键入Stack

当函数CreateStack()struct StackRecord ...

分配足够的内存时
malloc(sizeof(struct StackRecord));

...将结果指针转换为struct StackRecord *类型是完全合理的。实际上,类型 Stackstruct StackRecord *的类型完全相同,因此这正是代码实际上所做的。转换后的指针仍然指向同一个内存,当返回该指针时,返回值也指向同一个内存。