首页 > 解决方案 > 为什么我使用指向指针的指针会出现内存访问冲突错误

问题描述

我在 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);

}

标签: cpointersmemory-management

解决方案


C 是按值传递,而不是按引用传递。因此,List* list函数中list_add的 in 和List* listinmain指的是内存中的两个不同位置(它们最初指向 开头的同一个位置list_add,但它们是两个不同的指针,最初具有相同的值,而不是相同的指针):修改值变量insidelistlist_add值不影响listin的值main

再具体一点:

list = &n1inlist_add仅修改list该函数内的值,即在list_add调用时复制到 的堆栈帧中的参数值。但是,当您尝试在第 59 行打印它时,仍然在 内list_add,可以看到更改的值,因此是打印的指针,按您的预期工作。

另一方面,当您尝试list在第 39 行打印时,函数中的变量在第39 行 in 之前的赋值并未更改其值,因为这仅更改了该函数范围内的副本的值。因此在这种情况下尝试打印空列表的元素(因为 的值仍然是返回的值,它是指向指针的指针,因此取消引用,然后尝试取消引用指针),从而导致无效的内存访问。mainlistmainlist = &n1list_addlist_printlistlist_createNULLElem aux = **listlistNULL

因此,此代码中的问题不是列表打印的位置,而是list_add没有正确更新列表。在解决这个问题时,您需要考虑到它只能通过修改它作为参数接收的引用值所指向的内容来修改列表结构,而不是尝试修改指针本身。如果您确实想从函数内部修改list指向 in的地址(例如该行似乎试图执行的操作),则需要将指针传递给into ,而不仅仅是指针本身。mainlist_addlist = &n1listlist_addlist

代码本身似乎还有其他问题(list_print例如,仅打印一个元素并且没有处理打印空列表,这就是导致此处错误成为实际无效内存访问的原因,而不是仅仅在之后错误地将列表留空调用list_add),但上述问题是导致此特定问题的原因。


推荐阅读