我正在研究以下问题:
编写定义名为 moduleStruct 的结构化类型的"C"代码 将模块名称存储为字符数组的成员,数量 学生将模块作为整数,学生的姓名采用 模块作为指向字符串数组的指针,学生的结果存储为浮点数数组。
我不确定如何在不知道学生编号的情况下在结构中包含浮点数组,所以我只是假设它们的意思是指向浮点数组的指针。
这是我做的:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct mS{
char name[50];
int studentNum;
char (*studentNames)[50];
float *studentGrades;
}moduleStruct;
void deleteModule(moduleStruct* ms);
void deleteModule(moduleStruct* ms){
free(ms->studentNames);
free(ms->studentGrades);
free(ms);
}
int main(int argc, char* argv[])
{ moduleStruct* m1 = malloc(sizeof(moduleStruct));
strcpy(m1->name, "Programming");
m1 -> studentNum = 5;
char students[][50] = {"Alan", "Bob", "Charles", "James", "Peter"};
m1 -> studentNames = malloc(sizeof(students));
memcpy(m1 -> studentNames, &students, sizeof(students));
float grades[5]= {1.1, 2.2, 3.3, 4.4, 5.5};
m1->studentGrades = malloc(sizeof(grades));
memcpy(m1->studentGrades, grades, sizeof(grades));
printf("%sn", m1->name);
printf("%dn", m1->studentNum);
printf("%sn", m1->studentNames[2]);
printf("%fn", m1->studentGrades[4]);
deleteModule(m1);
printf("%sn", m1->name);
return 0;
}
所以我有3个问题:
- 有没有办法在不知道学生编号的情况下直接使用浮点数组?
- 如何改进此解决方案?
- 有没有办法让我不必在学生姓名中预定义最大名称大小?
马上:
main.c: In function 'main':
main.c:32:14: warning: format '%f' expects argument of type 'double', but argument 2 has type 'float *' [-Wformat=]
32 | printf("%fn", m1->studentGrades);
| ~^ ~~~~~~~~~~~~~~~~~
| | |
| double float *
main.c:32:14: warning: format '%f' expects argument of type 'double', but argument 2 has type 'float *' [-Wformat=]
因此,让我们修复它以打印值。printf("%fn", *m1->studentGrades);
Programming
5
Alan
1.100000
那更好。
char* heapStudents = malloc(sizeof(students));
heapStudents = *students;
m1 -> studentNames = heapStudents;
这似乎不对。让我们看看发生了什么。
Breakpoint 2, main () at main.c:19
19 char students[][20] = {"Alan", "Bob", "Charles", "James", "Peter"};
(gdb) s
20 char* heapStudents = malloc(sizeof(students));
(gdb) p students
$5 = {"Alan", ' 00' <repeats 15 times>, "Bob", ' 00' <repeats 16 times>, "Charles", ' 00' <repeats 12 times>,
"James", ' 00' <repeats 14 times>, "Peter", ' 00' <repeats 14 times>}
(gdb) x students
0x22fdd0: 0x6e616c41
(gdb) s
21 heapStudents = *students;
(gdb) s
22 m1 -> studentNames = heapStudents;
(gdb) p *heapStudents
$8 = 65 'A'
(gdb) x heapStudents
0x22fdd0: 0x6e616c41
您可以在堆栈上分配字符数组数组(在 0x6e616c41 处(。然后,在堆上分配相同数量的内存,并将指向它的指针保存为*heapStudents
。然后,你用等于指向students
字符数组中第 0 个元素的衰减指针的值的"地址"覆盖指针,在此过程中泄漏malloc
内存。哎呀。
让我们解决这个问题。
m1->studentNames = malloc(sizeof(students));
memcpy(m1->studentNames, &students, sizeof(students));
现在我们分配内存,并在结构中分配m1
指向的*studentNames
指针,以指向malloc
返回的地址。然后我们将堆栈数组复制到堆上分配的内存中。我们没有泄露任何内存,因为我们以后可以打电话给free(m1->studentNames)
。
必须对studentGrades
应用相同的修复程序。但是,让我们尝试一些不同的东西;在堆上分配内存,而不先在堆栈上分配数组。
m1->studentGrades = malloc(sizeof(float[5]));
m1->studentGrades[0] = 1.1;
m1->studentGrades[1] = 2.2;
m1->studentGrades[2] = 3.3;
m1->studentGrades[3] = 4.4;
m1->studentGrades[4] = 5.5;
请注意,我们可以将数组索引与float* studentGrades
指针一起使用。
关于正确的问题:
有没有办法在不知道学生编号的情况下直接使用浮点数组?
在不知道最大学生数的情况下,您可以#define MAX_STUDENTS 100
初始化数组,然后使用m1->studentNum
进行迭代。或者,跳过堆栈上的分配,只使用malloc(m1->studentNum * sizeof(var))
/calloc(m1->studentNum, sizeof(var));
.
或者,在需要时使用realloc
。
如何访问第二个学生的名字?
更改结构定义,以便具有指向字符数组的指针数组。char* studentNames[20];
有 20 个指针,然后将数据存储在堆上的某个位置,并将指针保存在结构的数组成员中:
m1->studentNames[0] = strcpy(calloc(20, sizeof(char)), "Alan");
m1->studentNames[1] = strcpy(calloc(20, sizeof(char)), "Bob");
m1->studentNames[2] = strcpy(calloc(20, sizeof(char)), "Charles");
m1->studentNames[3] = strcpy(calloc(20, sizeof(char)), "James");
m1->studentNames[4] = strcpy(calloc(20, sizeof(char)), "Peter");
使用printf("%sn", m1->studentNames[1]);
打印"鲍勃"等。
或者,在结构中使用双指针,并使其指向堆上的指针数组。这种方式可以动态分配超过20个元素限制的内存。
如何正确设置指向浮点数组的指针并访问每个成员?
如果结构中有float studentGrades[20];
,则可以像这样制作指针
float *p = &m1->studentGrades[0];
printf("%f %fn", p[0], p[1]); // prints 1.100000 2.200000
完全:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct mS{
char name[50];
int studentNum;
char* studentNames[20];
float studentGrades[20];
} moduleStruct;
int main(void) {
moduleStruct *m1 = malloc(sizeof(moduleStruct));
strcpy(m1->name, "Programming");
m1->studentNum = 5;
//char students[][20] = {"Alan", "Bob", "Charles", "James", "Peter"};
m1->studentNames[0] = strcpy(calloc(20, sizeof(char)), "Alan");
m1->studentNames[1] = strcpy(calloc(20, sizeof(char)), "Bob");
m1->studentNames[2] = strcpy(calloc(20, sizeof(char)), "Charles");
m1->studentNames[3] = strcpy(calloc(20, sizeof(char)), "James");
m1->studentNames[4] = strcpy(calloc(20, sizeof(char)), "Peter");
/*float grades[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
m1->studentGrades = malloc(sizeof(grades));
memcpy(m1->studentGrades, &grades, sizeof(grades));*/
//m1->studentGrades[0] = malloc(sizeof(float[5]));
m1->studentGrades[0] = 1.1;
m1->studentGrades[1] = 2.2;
m1->studentGrades[2] = 3.3;
m1->studentGrades[3] = 4.4;
m1->studentGrades[4] = 5.5;
printf("%sn", m1->name);
printf("%dn", m1->studentNum);
printf("%sn", m1->studentNames[0]);
printf("%fn", m1->studentGrades[0]);
return 0;
}
编辑
所以我有两个问题:
(问题 0 到 2 也许,但我肯定看到 3!
有没有办法在不知道学生编号的情况下直接使用浮点数组?
见上文。
如何改进此解决方案?
除了去除implicit declaration of function 'deleteModule'
? 见下文。
有没有办法让我不必在学生姓名中预定义最大名称大小?
使结构包含指向指针数组的指针。 每次添加学生时realloc
此数组。分配数组中的一个指针指向malloc
个字符数组以存储学生姓名。
typedef struct mS{
// ...
char **studentNames;
}
// ...
char str[] = "Alan";
m1->studentNames = realloc(m1->studentNames, ++(m1->studentNum)*sizeof(*m1->studentNames);
m1->studentNames[m1->studentNum-1] = strcpy(calloc(strlen(str)+1, sizeof(char)), str);
分配5个字节来存储名称,并将指针的大小(可能是8B(添加到m1->studentNames
的空间中以存储名称的地址。
您将有 2 种方法:
- 要么假设模块将具有最大容量(非常现实,但可能不是练习所需的容量(
- 动态分配的阵列,您可以根据需要在其中进行分配
最大(固定(容量
#define moduleCapacity 200
#define moduleMaxName 50
struct moduleStruct {
char name[moduleMaxName];
unsigned int studentsCount;
const char *studentsName[moduleCapacity];
float studentsGrade[moduleCapacity];
};
void populateModule(
struct moduleStruct *target,
const char *moduleName,
const unsigned int studentsCount,
const char* studentsName[],
const float studentsGrade[]) {
strncpy(target->name, moduleName, moduleMaxName);
target->studentsCount = studentsCount;
for(unsigned int i = 0; i < studentsCount; ++i) {
if(i >= moduleCapacity) return; // student over the limit are thrown away, sorry first come first served basis
target->studentsName[i] = studentsName[i];
target->studentsGrade[i] = studentsGrade[i];
}
}
void printModule(struct moduleStruct *input) {
printf("name : %sn", input->name);
printf("students : %in", input->studentsCount);
for(unsigned int i = 0; i < input->studentsCount; ++i) {
printf("%u %s %fn", i+1, input->studentsName[i], input->studentsGrade[i]);
}
}
int main(int argc, char** argv) {
struct moduleStruct m1;
const char *names[] = {"Alan", "Bob", "Charles", "James", "Peter"};
const float grades[] = {1.1f, 2.2f, 3.3f, 4.4f, 5.5f};
populateModule(
&m1,
"Programming",
5,
names,
grades
);
printModule(&m1);
}
动态分配的数组
#define moduleMaxName 50
struct moduleStruct {
char name[moduleMaxName];
unsigned int studentsCount;
const char **studentsName;
float *studentsGrade;
};
void populateModule(
struct moduleStruct *target,
const char *moduleName,
const unsigned int studentsCount,
const char* studentsName[],
const float studentsGrade[]) {
strncpy(target->name, moduleName, moduleMaxName);
target->studentsCount = studentsCount;
// we have the student count, we can allocate an array that is sized just for the class size
target->studentsName = calloc(target->studentsCount, sizeof(char*));
target->studentsGrade = calloc(target->studentsCount, sizeof(float));
for(unsigned int i = 0; i < studentsCount; ++i) {
target->studentsName[i] = studentsName[i];
target->studentsGrade[i] = studentsGrade[i];
}
}
// printModule & main remain the same