c - 为什么我使用指向指针的指针会出现内存访问冲突错误
问题描述
我在 C 中创建了一个小程序来测试指向指针的指针。
当我使用函数(第 39 行)打印列表数据时,将项目添加到列表后出现错误 3221225477。但是,当我评论第 39 行并从第 59 行删除评论时,程序正常工作。
如果程序从上到下运行,为什么我会从操作系统(在本例中为 Windows)收到 ACCESS_VIOLATION 错误?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
struct employee{
int id;
char name[50];
char street[50];
};
typedef struct element* List;
struct element{
struct employee data;
struct element *next;
};
typedef struct element Elem;
List* list_create();
void list_print(List* list);
int list_is_empty(List* list);
int list_add(List* list, struct employee a);
int main(){
List* list = list_create();
struct employee a1;
a1.id = 10;
strcpy(a1.name, "John");
strcpy(a1.street, "Address XYZ");
list_add(list, a1);
//Sleep(5000); small pause, I thinking it might have something to do with thread.
//list_print(list); // *****line--39 *****;
return 0;
}
List* list_create(){
List* li = (List *) malloc(sizeof(List));
if(li != NULL)
*li = NULL;
return li;
}
int list_add(List* list, struct employee emp){
Elem* n1 = (Elem *) malloc(sizeof(Elem));
n1->data = emp;
n1->next = *list;
list = &n1;
list_print(list); // *****line--59 *****;
}
void list_print(List* list){
Elem aux = **list;
printf(" **lista Id: %d\n", aux.data.id);
printf(" **lista name: %s\n", aux.data.name);
printf(" **lista name: %s\n", aux.data.street);
}
解决方案
C 是按值传递,而不是按引用传递。因此,List* list
函数中list_add
的 in 和List* list
inmain
指的是内存中的两个不同位置(它们最初指向 开头的同一个位置list_add
,但它们是两个不同的指针,最初具有相同的值,而不是相同的指针):修改值变量insidelist
的list_add
值不影响list
in的值main
。
再具体一点:
list = &n1
inlist_add
仅修改list
该函数内的值,即在list_add
调用时复制到 的堆栈帧中的参数值。但是,当您尝试在第 59 行打印它时,仍然在 内list_add
,可以看到更改的值,因此是打印的指针,按您的预期工作。
另一方面,当您尝试list
在第 39 行打印时,函数中的变量在第39 行 in 之前的赋值并未更改其值,因为这仅更改了该函数范围内的副本的值。因此在这种情况下尝试打印空列表的元素(因为 的值仍然是返回的值,它是指向指针的指针,因此取消引用,然后尝试取消引用指针),从而导致无效的内存访问。main
list
main
list = &n1
list_add
list_print
list
list_create
NULL
Elem aux = **list
list
NULL
因此,此代码中的问题不是列表打印的位置,而是list_add
没有正确更新列表。在解决这个问题时,您需要考虑到它只能通过修改它作为参数接收的引用值所指向的内容来修改列表结构,而不是尝试修改指针本身。如果您确实想从函数内部修改list
指向 in的地址(例如该行似乎试图执行的操作),则需要将指针传递给into ,而不仅仅是指针本身。main
list_add
list = &n1
list
list_add
list
代码本身似乎还有其他问题(list_print
例如,仅打印一个元素并且没有处理打印空列表,这就是导致此处错误成为实际无效内存访问的原因,而不是仅仅在之后错误地将列表留空调用list_add
),但上述问题是导致此特定问题的原因。
推荐阅读
- javascript - Bootstrap Multiselect - 通过onclick取消选择
- c# - 在服务器端处理中两次加载实体框架,数据表抛出错误
- python - 将两个列表添加到字典中并允许合并具有相似标题的值
- php - 在 Laravel 我得到错误 errno: 150 "Foreign key constraint is wrongly forms"
- angular - Angular Observables 链接调用和设置子对象数据
- ios - Cell内的TableView动态高度问题
- react-styleguidist - 如何更改文档内容的宽度?
- .net - 使用 Microsoft.Win32.TaskScheduler.dll 触发应用程序
- sql - 如何处理 Hive 上 SQL 中的数据倾斜?
- maven - IntelliJ 无法从 org.springframework.security.oauth2.core.ClientAuthenticationMethod 解析符号核心