gpt4 book ai didi

c - 在 C 中实现和使用动态数组

转载 作者:太空宇宙 更新时间:2023-11-04 03:19:08 25 4
gpt4 key购买 nike

我正在尝试创建一个学生列表,这些学生使用动态分配的数组存储结构。为此,我有以下结构:

typedef struct s_student 
{
char name[64];
int matrikelNummer;
} student;

typedef struct s_studentList
{
student* students;
int numberOfStudents;
} studentList;

到目前为止,这是我使用它们的方式:

int main(int argc, char** argv) {

studentList* list = NULL;
list = (studentList*) malloc(sizeof(studentList));

list->numberOfStudents =1;
//list->students->matrikelNummer = 1;
//strcpy(list->students->name , "karim");

printf("numberOfStudents : %d\n" , list->numberOfStudents );
//printf("matrikelNummer : %d\n" , list->students->matrikelNummer);
//printf("name : %d\n" , list->students->name);

free(list);

return 0;
}

这似乎没有问题。但是,当我尝试按照注释行中的概述将数据分配给学生(matrikelNummername)时,我收到了段错误。

我做错了什么?

最佳答案

未分配指针

问题是你这样做:

// list points to null after that line
studentList* list = NULL;

// allocate memory for the list struct
list = (studentList*) malloc(sizeof(studentList));

// set field inside list struct
list->numberOfStudents =1;

// list->students is a pointer, but pointers should point to something valid
// So the question is: Was list->students set to NULL?
// Or was it mallocated?
list->students->matrikelNummer = 1;

所以你访问list->students是一个指针。
列表本身是通过 malloc 分配的,所以没问题。
但是 malloc 仅为您想要的列表对象保留空间。它不会分配任何其他内容。

所以 list->students 是一个未分配的指针 - 这就是我们得到段错误的原因。

这个问题的解决方案非常简单——我们不仅要分配一个列表,还要分配我们使用的所有指针(在本例中是它的 students 成员):

// That was earlier there:
studentList* list = NULL;
list = (studentList*) malloc(sizeof(studentList));

// After allocating place for list also allocate place for list->students:
list->students = (student*) malloc(sizeof(student));

无效内存使用检测

如果您遇到段错误或内存泄漏,最好知道有很多工具可以帮助程序员检测此类严重错误。

其中之一是 Valgrind

Valgrind 可用于 Linux(也可能用于 Windows,但有缺陷且未经测试)。

这是很棒的工具,可以遍历您的程序并通知您任何泄漏、无效释放和禁止内存地址的使用。

Valgrind 的使用示例:

# Compile your code
gcc list.c -o list
# Use Valgrind
valgrind --tool=memcheck ./list

以及 valgrind 显示的内容:

==26761== Memcheck, a memory error detector
==26761== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==26761== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==26761== Command: ./list
==26761==
==26761== Use of uninitialised value of size 8
==26761== at 0x4006A1: main (in /home/students/inf/p/ps386038/stack/list)
==26761==
==26761== Invalid write of size 4
==26761== at 0x4006A1: main (in /home/students/inf/p/ps386038/stack/list)
==26761== Address 0x40 is not stack'd, malloc'd or (recently) free'd
==26761==
==26761==
==26761== Process terminating with default action of signal 11 (SIGSEGV)
==26761== Access not within mapped region at address 0x40
==26761== at 0x4006A1: main (in /home/students/inf/p/ps386038/stack/list)
==26761== If you believe this happened as a result of a stack
==26761== overflow in your program's main thread (unlikely but
==26761== possible), you can try to increase the size of the
==26761== main thread stack using the --main-stacksize= flag.
==26761== The main thread stack size used in this run was 8388608.
==26761==
==26761== HEAP SUMMARY:
==26761== in use at exit: 16 bytes in 1 blocks
==26761== total heap usage: 1 allocs, 0 frees, 16 bytes allocated
==26761==
==26761== LEAK SUMMARY:
==26761== definitely lost: 0 bytes in 0 blocks
==26761== indirectly lost: 0 bytes in 0 blocks
==26761== possibly lost: 0 bytes in 0 blocks
==26761== still reachable: 16 bytes in 1 blocks
==26761== suppressed: 0 bytes in 0 blocks
==26761== Rerun with --leak-check=full to see details of leaked memory
==26761==
==26761== For counts of detected and suppressed errors, rerun with: -v
==26761== Use --track-origins=yes to see where uninitialised values come from
==26761== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

所以它表明您在函数 main 中访问了无效地址:

==26761== Invalid write of size 4
==26761== at 0x4006A1: main (in /home/students/inf/p/ps386038/stack/list)
==26761== Address 0x40 is not stack'd, malloc'd or (recently) free'd

并说出地址(甚至没有分配指针)!

正确的C列表实现

如果你想实现一个包含学生列表的指针结构那么一种常见的方法是将指向下一个学生(列表中的下一个)的指针放入 s_student 结构中。

以及指向学生列表中第一个和最后一个学生的指针。

一个工作示例是我自己编写的以下示例:

#include <stdio.h>
#include <stdlib.h>

typedef struct s_student student;

struct s_student
{
char name[64];
int matrikelNummer;
// This will point to the next student on the list
student* nextStudent;
};

typedef struct s_studentList
{
student* student;
// This will point to the last available student
student* lastStudent;
// This will point to the first available student
student* firstStudent;
int numberOfStudents;
} studentList;

// Allocates the list
void allocStudentsList(studentList** list) {
if(list == NULL) return;
*list = (studentList*) malloc(sizeof(studentList));
(*list)->lastStudent = NULL;
(*list)->firstStudent = NULL;
}

// To add the student to the list
void addStudentToList(studentList* list, student studentData) {

if(list == NULL) return;

// Allocate a place for the next student
student* st = (student*) malloc(sizeof(student));

// If it's first student in the list
if(list->lastStudent == NULL) {
list->lastStudent = st;
list->firstStudent = st;
} else {
// The next student after the current last student will be the newly created one
list->lastStudent->nextStudent = st;
}

// Fill the student data
*st = studentData;
st->nextStudent = NULL;

// Set the last available student to the one created
list->lastStudent = st;

}

// To recurisvely free the students
void freeStudent(student* stud) {
if(stud->nextStudent != NULL) {
// Free next student recursively
freeStudent(stud->nextStudent);
}
free(stud);
}

// To free the students list
void freeStudentsList(studentList* list) {
if(list != NULL) {
freeStudent(list->firstStudent);
free(list);
}
}

// Function that prints single student and returns next one (after him on the list)
student* printStudent(student* stud) {
if(stud == NULL) return NULL;
printf(" * Student { matrikelNummer = %d }\n", stud->matrikelNummer);
// Return next student
return stud->nextStudent;
}

// Function that prints students list
void printStudentsList(studentList* list) {
if(list == NULL) return;

printf("StudentsList [\n");

student* current_student = list->firstStudent;
while(current_student != NULL) {
current_student = printStudent(current_student);
}

printf("]\n");
}

int main(int argc, char** argv) {

studentList* list = NULL;
allocStudentsList(&list);

// Create some student data
student st1;
st1.matrikelNummer = 1;

// Another student...
student st2;
st2.matrikelNummer = 2;

// Put them into the list (allocates students and take care of everything)
addStudentToList(list, st1);
addStudentToList(list, st2);

// Print the list
printStudentsList(list);

// Free the list (recursively free's all students and take care of all the nasty stuff)
freeStudentsList(list);

return 0;
}

网上有很多关于如何编写 C 风格列表结构的教程。你可以自己找一个。

教程之一:Learn-c linked list tutorial

关于c - 在 C 中实现和使用动态数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48170652/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com