2012-09-15 52 views
5

我必须使用以下代码块来完成学校作业,严格地说,没有任何修改。指向结构的动态指针数组

typedef struct 
{ 
    char* firstName; 
    char* lastName; 
    int id; 
    float mark; 
}* pStudentRecord; 

pStudentRecord* g_ppRecords; 
int g_numRecords =0; 

这里g_ppRecords应该是指向结构体的指针数组。什么我完全不理解的是,如何才能声明pStudentRecords *g_ppRecords;意味着g_ppRecords是一个数组,因为数组应该被定义为

type arrayname[size]; 

我试图分配内存动态g_ppRecords,但是这没有帮助。

g_ppRecords = (pStudentRecord*) malloc(sizeof(pStudentRecord*)*(g_numRecords+1)); 
+0

指针只是指向一个地址。您可以根据需要从该地址开始保留尽可能多的内存(直到空间用完为止)。 – chris

+0

我认为这是一个很差的问题,你明白可以用这种方式定义数组,因为你尝试为它分配一个空间,所以你在问什么?,仅仅为指针分配一个空间是不够的结构,这是btw pStudentRecord而不是pSt ... ord *,为了使用它,你还需要为struct it自己分配一个地方! – Michael

回答

1

观察到pStudentRecord是typedef'd作为指向结构的指针。 C中的指针只是指向一个内存块的开始,无论该块是否包含1个元素(一个普通的“标量”指针)或10个元素(一个“数组”指针)。因此,例如,下面的

char c = 'x'; 
char *pc = &c; 

使得pc指向一块内存以字符'x'开始,虽然以下

char *s = "abcd"; 

使得s指向一块内存,与开始"abcd"(后跟一个空字节)。类型是相同的,但它们可能用于不同的目的。

因此,一旦分配,我可以通过例如访问g_ppRecords的元素。 g_ppRecords[1]->firstName

现在,分配这个数组:你想使用g_ppRecords = malloc(sizeof(pStudentRecord)*(g_numRecords+1));(尽管注意sizeof(pStudentRecord*)sizeof(pStudentRecord)是相等的,因为两者都是指针类型)。这使得未初始化的结构数组指针。对于数组中的每个结构指针,你需要通过分配一个新的结构来给它赋值。问题的关键是,你会如何分配的单一结构,即

g_ppRecords[1] = malloc(/* what goes here? */); 

幸运的是,你实际上可以取消引用指针在sizeof

g_ppRecords[1] = malloc(sizeof(*g_ppRecords[1])); 

注意sizeof是一个编译器结构。即使g_ppRecords[1]不是有效的指针,类型仍然有效,因此编译器将计算正确的大小。

+0

g_ppRecords [1] =(pStudentRecord *)malloc(sizeof(char *)* 2 + sizeof(int)+ sizeof(float)); ? –

+0

增加了一个更好的解决方案。这实际上并不是一个明显的解决方案,可以想一想。 – nneonneo

+0

+1教我几个新的技巧... –

0

数组通常用指向其第一个元素的指针引用。如果你为malloc足够的空间存放10个学生记录,然后在g_ppRecords中存储一个指向该空间开始的指针,g_ppRecords [9]将向前计数9个记录指针长度并取消引用那里的内容。如果你正确地管理你的空间,那里的东西将是你的数组中的最后一条记录,因为你保留足够的空间,10

总之,你已经分配的空间,但是和你想你可以把它如果它是正确的长度,包括作为一个数组。

我不知道为什么你的g_numRecords + 1点的记录分配空间。除非g_numRecords被混淆命名,否则这是数组中超出需要的空间。

-1

这里g_ppRecords应该是指向结构体的指针数组。我完全不明白的是,如何声明* pStudentRecords g_ppRecords;意味着g_ppRecords是一个数组。作为数组应该定义为

type arrayname [size];

type arrayname[size]; UMM是许多方式中C.

定义数组

此静态定义的阵列,其中大部分的值被存储取决于它的位置在堆栈上单程定义,在编译时必须知道数组的大小,尽管在一些现代编译器中这可能不再是这种情况。

另一种方式是在运行时动态创建一个数组,因此我们不必在编译时知道大小,这是指针进入的地方,它们是存储动态分配的内存块地址的变量。

一个简单的例子会是这样的type *array = malloc(sizeof(type) * number_of_items); malloc返回一个存储在array中的内存地址,注意我们不会为了安全原因而强制返回类型。

回到手头的问题。

typedef struct 
{ 
    char* firstName; 
    char* lastName; 
    int id; 
    float mark; 
}* pStudentRecord; 

pStudentRecord* g_ppRecords; 
int g_numRecords = 0; 

typedef是有点不同,最注意}*基本上它指向一个结构等等这样的:

pStudentRecord* g_ppRecords; 

居然是:

struct 
{ 
    char* firstName; 
    char* lastName; 
    int id; 
    float mark; 
}** pStudentRecord; 

它的一个指向指针,至于为什么他们会以这种方式定义typedef,它超越了我,我个人不推荐它,为什么?

好的一个问题是,我们如何通过名称获得结构体的大小?简单,我们不能!如果我们使用sizeof(pStudentRecord),我们将得到48,这取决于底层架构,因为这是一个指针,不知道结构的大小,我们不能使用它的typedef名称真正动态分配它,所以我们可以做什么,声明一个第二结构像这样:

typedef struct 
{ 
    char* firstName; 
    char* lastName; 
    int id; 
    float mark; 
} StudentRecord; 

g_ppRecords = malloc(sizeof(StudentRecord) * g_numRecords); 

无论哪种方式,你真的需要原谁创造了这个代码或人保持联系的人,并提高你的顾虑。

g_ppRecords=(pStudentRecord) malloc((sizeof(char*) + 
            sizeof(char*) + 
            sizeof(int) + 
            sizeof(float)) *(g_numRecords+1)); 

这可能看起来是一种可能的方式,不幸的是,有no guarantees约结构,因此它们实际上可以方含在构件之间的填充,从而该结构的总尺寸可以实际上更大然后其组合成员,而不是要提到的地址可能会有所不同。

编辑

显然,我们可以通过简单地推断出它的类型

因此得到了结构的大小:

pStudentRecord g_ppRecords = malloc(sizeof(*g_ppRecords) * g_numRecords); 

工作正常!

+0

给下来的选民照顾详细说明? –

+0

这是一种非常糟糕的方法,因为您对结构定义进行了硬编码(并忽略填充等),所以使用'malloc'。你说没有其他办法可以做到这一点是不正确的;看我的解决方案。所写的代码是完全有效且可用的,尽管有些不寻常。 – nneonneo

+0

我确实说**较差的方式,无论如何,我会删除它。 –

3

编辑:“大错误”部分更新。

C风格的快速教训(从C++不同!)类型定义,以及为什么它是怎么回事,以及如何使用它。

首先,一个基本的typedef把戏。

typedef int* int_pointer; 
int_pointer ip1; 
int *ip2; 
int a; // Just a variable 
ip1 = &a; // Sets the pointer to a 
ip2 = &a; // Sets the pointer to a 
*ip1 = 4; // Sets a to 4 
*ip2 = 4; // Sets a to 4 

IP1和IP2是相同的类型:一个指针到类型INT,即使你没有把一个* IP1的声明。这*代替了声明。

切换主题。 你说话声明数组作为

int array1[4]; 

要做到这一点在运行时动态,你可以这样做:

int *array2 = malloc(sizeof(int) * 4); 
int a = 4; 
array1[0] = a; 
array2[0] = a; // The [] implicitly dereferences the pointer 

现在,如果我们想要什么指针数组?它看起来像这样:

int *array1[4]; 
int a; 
array1[0] = &a; // Sets array[0] to point to variable a 
*array1[0] = 4; // Sets a to 4 

让我们动态地分配这个数组。

int **array2 = malloc(sizeof(int *) * 4); 
array2[0] = &a; // [] implicitly dereferences 
*array2[0] = 4; // Sets a to 4 

注意int **。这意味着指针指向int。如果我们选择,我们可以使用指针typedef。

typedef int* array_of_ints; 
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4); 
array3[0] = &a; // [] implicitly dereferences 
*array3[0] = 4; // Sets a to 4 

看看在最后的声明中只有一个*吗?这是因为其中之一是“在typedef”。与去年的声明,你现在有一个包含4个指向整数(INT *)大小为4的数组。

这里必须指出的运算符优先级是很重要的。解引用运算符[]优先于*之一。所以我们要做的就是:

*(array3[0]) = 4; 

现在,让我们将主题更改为structs和typedefs。

struct foo { int a; }; // Declares a struct named foo 
typedef struct { int a; } bar; // Typedefs an "ANONYMOUS STRUCTURE" referred to by 'bar' 

为什么你会输入一个匿名结构?那么,为了可读性!

struct foo a; // Declares a variable a of type struct foo 
bar b;  // Notice how you don't have to put 'struct' first 

声明函数...

funca(struct foo* arg1, bar *arg2); 

看看我们怎么没有把 '结构' 在arg2的前面?现在

,我们看到,你必须使用的代码定义的结构以这种方式:

typedef struct { } * foo_pointers; 

这类似于我们是怎么做的指针之前的数组:

typedef int* array_of_ints; 

比较并排

typedef struct { } * foo_pointers; 
typedef int* array_of_ints; 

唯一的区别是一个是struct {},另一个是int。

随着我们foo_pointers,我们可以声明数组的指针到foo这样:

foo_pointers fooptrs[4]; 

现在我们有了一个数组,商店4个指向一个匿名的结构,我们无法访问。

TOPIC SWITCH!

不适合你,你的老师犯了一个错误。如果查看上面的foo_pointers类型的sizeof(),会发现它返回指向该结构的指针的大小,而不是结构的大小。对于32位平台,这是4个字节,对于64位平台是8个字节。这是因为我们输入了一个指向结构的指针,而不是结构本身。 sizeof(pStudentRecord)将返回4.

因此,您不能以明显的方式为结构本身分配空间!然而,编译器允许这种愚蠢。 pStudentRecord不是可以用来有效分配内存的名称/类型,它是指向匿名“概念”结构的指针,但我们可以将其大小提供给编译器。

pStudnetRecord g_ppRecords [2]; pStudentRecord * record = malloc(sizeof(* g_ppRecords [1]));

一个更好的做法是做到这一点:

typedef struct { ... } StudentRecord; // Struct 
typedef StudentRecord* pStudentRecord; // Pointer-to struct 

现在,我们不得不做出结构StudentRecord的,以及指向他们pStudentRecord的,以明确的方式的能力。

虽然你不得不使用的方法是非常糟糕的做法,但目前这不是一个问题。让我们回到我们使用整数的简单示例。

如果我想要使typedef复杂化我的生活但解释这里发生的概念怎么办?让我们回到旧的int代码。

typedef int* array_of_ints; 
int *array1[4]; 
int **array2 = malloc(sizeof(int *) * 4); // Equivalent-ish to the line above 
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4); 
int a, b, c, d; 
*array1[0] = &a; *array1[1] = &b; *array1[2] = &c; *array1[3] = &d; 
*array2[0] = &a; *array2[1] = &b; *array2[2] = &c; *array2[3] = &d; 
*array3[0] = &a; *array3[1] = &b; *array3[2] = &c; *array3[3] = &d; 

正如你所看到的,我们可以用我们的pStudentRecord使用:

pStudentRecord array1[4]; 
pStudentRecord *array2 = malloc(sizeof(pStudentRecord) * 4); 

把一切融合在一起,它遵循逻辑上:

array1[0]->firstName = "Christopher"; 
*array2[0]->firstName = "Christopher"; 

是等价的。 (注意:不要像上面那样完成;如果你知道你已经有了足够的空间,那么在运行时将一个char *指针赋给一个字符串只是确定的)。

这只是真正带来了最后一点。我们如何处理所有这些我们malloc'd的内存?我们如何释放它?

free(array1); 
free(array2); 

还有一个关于指针,匿名结构的typedefs和其他东西的深夜课程的结束。

+0

感谢您的评论。这帮助我了! – Rachael