我认为我总体上无法理解指针。 我似乎无法遵循此代码的逻辑:
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;
}
答案 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
必须成为指向struct
或union
类型的指针。由于 要知道S
是指针,因此将指针隐藏在typedef后面是没有意义的。同样,如果用户必须知道该类型的struct
- ness,则不应该隐藏struct
- 或者在typedef后面。
抽象是一种强大的工具,但像原始代码这样的部分(漏洞)抽象只会让每个人的生活更加混乱(正如你自己发现的那样)。
&LT; /咆哮&GT;
<小时/>
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 *
类型是完全合理的。实际上,类型 Stack
与struct StackRecord *
的类型完全相同,因此这正是代码实际上所做的。转换后的指针仍然指向同一个内存,当返回该指针时,返回值也指向同一个内存。