Почему я получаю ошибку нарушения доступа к памяти, используя указатель на указатель - PullRequest
0 голосов
/ 03 октября 2018

Я создал небольшую программу на C для проверки указателя на указатель.

Когда я использую функцию (строка 39) для печати данных списка, после добавления элемента в список я получаю ошибку 3221225477. Однако, когда я комментирую строку 39 и удаляю комментарий из строки 59, программа работает нормально.

Почему я получаю ошибку ACCESS_VIOLATION из операционной системы, в данном случае Windows, если программа запускается изсверху вниз?

#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);

}

1 Ответ

0 голосов
/ 03 октября 2018

C - передача по значению, а не передача по ссылке.Таким образом, List* list в функции list_add и List* list в main относятся к двум разным местам в памяти (они изначально указывают на одно и то же место в начале list_add, но они являются двумя разными указателямиизначально с одним и тем же значением, а не с тем же указателем): изменение значения переменной list в пределах list_add не влияет на значение list в main.

Конкретно:

list = &n1 в list_add изменяет только значение list внутри этой функции, то есть значение аргумента, которое было скопировано в кадр стека list_add при вызове.Однако, когда вы пытаетесь напечатать его в строке 59, все еще в пределах list_add, измененное значение будет видно и, таким образом, будет напечатан указатель, работая, как вы ожидаете.

Когда вы пытаетесь напечатать listв строке 39 в main, с другой стороны, переменная list в функции main не изменила свое значение с помощью присваивания list = &n1 непосредственно перед строкой 39 в list_add, поскольку она изменилась толькозначение копии в области действия этой функции.Таким образом, в этом случае list_print пытается распечатать элементы пустого списка (поскольку значение list все еще является только тем, что было возвращено list_create, который является указателем на указатель NULL, и поэтому Elem aux = **listтаким образом разыменовывает list, а затем пытается разыменовать указатель NULL) и, таким образом, приводит к недопустимому доступу к памяти.

В этом коде проблема не в размещении печати списка, а в том, чтоlist_add не обновляет список должным образом.Исправляя это, вы должны принять во внимание, что он может изменять структуру списка, только изменяя то, на что указывает ссылочное значение, полученное в качестве аргумента, а не пытаясь изменить сам указатель.Если вы хотите изменить адрес, на который указывает list в main из функции list_add (например, то, что, по-видимому, пытается сделать строка list = &n1), вам нужно будет передать указатель на list в list_add, а не просто указатель list.

В самом коде, похоже, есть другие проблемы (list_print печатает только один элемент и не обрабатывает печать пустых списков,например, именно это приводит к тому, что ошибка в данном случае является фактическим неверным доступом к памяти, а не просто неправильно оставляет список пустым после вызова list_add), но проблема, описанная выше, является причиной этой конкретной проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...