链表中常见的0xC0000005: 写入位置 0x00000000 时发生访问冲突

时间:2022-10-24 10:45:31

#include <iostream>
using namespace std;
typedef struct Node {
int data;
Node *next;
}relNode;
typedef relNode *LinkList;
void CreateListHead(LinkList *L, int n) {
LinkList p;
int i;
*L = (LinkList)malloc(sizeof(Node));//这里有问题。。。
(*L)->next = NULL;
for (i = 0; i < n; i++) {
p = (LinkList)malloc(sizeof(Node));
p->data = i;
p->next = (*L)->next;
(*L)->next = p;
}

}

int main() {
LinkList *L=NULL;
CreateListHead(L, 10);

}

提示说0xC0000005: 写入位置 0x00000000 时发生访问冲突。。。我当时不太明白书里面为什么*LinkList已经定义成指向relNode的指针了,还要把L定义成指向指针的指针,就把程序改成下面的样子,这下就没有报错了,但是我觉得作者的写法也没错啊?为什么会报错,该怎么改呢?

#include <iostream>
using namespace std;
typedef struct Node {
int data;
Node *next;
}relNode;
typedef relNode *LinkList;
void CreateListHead(LinkList L, int n) {
LinkList p;
int i;
L = (LinkList)malloc(sizeof(Node));//这里有问题。。。
L->next = NULL;
for (i = 0; i < n; i++) {
p = (LinkList)malloc(sizeof(Node));
p->data = i;
p->next = L->next;
L->next = p;
}

}

int main() {
LinkList L=NULL;
CreateListHead(L, 10);

}

6 个解决方案

#1


#include <iostream>
using namespace std;
typedef struct Node {
    int data;
    Node *next;
}relNode;
typedef relNode *LinkList;
void CreateListHead(LinkList *L, int n) {
    LinkList p;
    int i;
    (*L) = (LinkList)malloc(sizeof(Node));//这里有问题。。。
    (*L)->next = NULL;
    for (i = 0; i < n; i++) {
        p = (LinkList)malloc(sizeof(Node));
        p->data = i;
        p->next = (*L)->next;
        (*L)->next = p;
    }
 
}
 
int main() {
    LinkList L = NULL;
    CreateListHead(&L, 10);
return 0;
 
}

这么写才是对的,书上主函数内部分写的不对,没有必要定义二级指针,但传参数的时候要传二级指针,因为只有传二级指针才能改变一级指针,这跟只有传指针才能改变值是一个道理
你改的那个虽然没有报错,但L并没有被改变,也就是那个函数没起作用,也是不对的
如不明白欢迎追问

#2


因为你的L是NULL,而你又去使用*L去解引他自然出错啦

主函数中你要写成这样;

LinkList xx;
CreateListHead(&xx, 10);

#3


引用 1 楼 cyfcsd 的回复:
#include <iostream>
using namespace std;
typedef struct Node {
    int data;
    Node *next;
}relNode;
typedef relNode *LinkList;
void CreateListHead(LinkList *L, int n) {
    LinkList p;
    int i;
    (*L) = (LinkList)malloc(sizeof(Node));//这里有问题。。。
    (*L)->next = NULL;
    for (i = 0; i < n; i++) {
        p = (LinkList)malloc(sizeof(Node));
        p->data = i;
        p->next = (*L)->next;
        (*L)->next = p;
    }
 
}
 
int main() {
    LinkList L = NULL;
    CreateListHead(&L, 10);
return 0;
 
}

这么写才是对的,书上主函数内部分写的不对,没有必要定义二级指针,但传参数的时候要传二级指针,因为只有传二级指针才能改变一级指针,这跟只有传指针才能改变值是一个道理
你改的那个虽然没有报错,但L并没有被改变,也就是那个函数没起作用,也是不对的
如不明白欢迎追问


大神你好,这个问题我明白了,我还有一段程序,想请教您一下

void ListDelete(LinkList *L, int n) {
    int j;
    LinkList r, p;
    r = *L;
    j = 1;
    for (; r->next != NULL&&j < n; r = r->next, j++);
    if (!(r->next) || j > n)//这里我不太明白
        cout << "删除失败" << endl;
    else {
        p = r->next;
        r->next = p->next;
        free(p);
    }
}

1、j>n这是一种什么样的情况?上面循环条件不是已经确保了j<n吗?
2、!(r->next) 和 r->next == NULL是不是等价的呢?如果是等价的, if (!(r->next) || j > n)这句话的意思不就是“如果下一个元素的位置是空的,或者当前位置在指定位置之后”么?那是怎么把链表的最后一个元素删除的呢?

#4


1.上面的循环条件是r->next != NULL&&j < n
也就是说如果r->next是NULL了也会跳出循环,比如你输入了一个很小的n(比如是个负数),j > n就为真了

2.!(r->next) 和 r->next == NULL是等价的。怎么把链表的最后一个元素删除,楼主问这个问题说明程序并没有搞的很清楚。
它要删除的结点是r->next而不是r,搞清楚这点你就明白了

#5


版主说的不错,j>n是为了防止出现给的位置过小的,比如链表有10个元素,那n的正常范围是1≤n≤10,如果给的n太小了,比如是0或者负数,则应该输出删除错误而不执行删除动作,如果不这样,那就会把第一个元素误删了!
!(r->next) 和 r->next == NULL是等价的,而且推荐第二种写法,可读性较强。至于怎么删除最后一个元素,这就是链表操作最基本的注意点了,删除元素时找到的一定是要删除元素的前一个位置,即r是指向要删除的前一个元素时循环停止,所以r初始化为*L,这个节点叫链表的头结点,它的data域为空,这就是为了方便这种操作用的
而且我感觉这种不会改变头指针的操作最好不要传头指针的地址,直接传头指针就好,即实参用LinkList L

#6


崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack即“调用堆栈”里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处, 看不懂时双击下一行,直到能看懂为止

#1


#include <iostream>
using namespace std;
typedef struct Node {
    int data;
    Node *next;
}relNode;
typedef relNode *LinkList;
void CreateListHead(LinkList *L, int n) {
    LinkList p;
    int i;
    (*L) = (LinkList)malloc(sizeof(Node));//这里有问题。。。
    (*L)->next = NULL;
    for (i = 0; i < n; i++) {
        p = (LinkList)malloc(sizeof(Node));
        p->data = i;
        p->next = (*L)->next;
        (*L)->next = p;
    }
 
}
 
int main() {
    LinkList L = NULL;
    CreateListHead(&L, 10);
return 0;
 
}

这么写才是对的,书上主函数内部分写的不对,没有必要定义二级指针,但传参数的时候要传二级指针,因为只有传二级指针才能改变一级指针,这跟只有传指针才能改变值是一个道理
你改的那个虽然没有报错,但L并没有被改变,也就是那个函数没起作用,也是不对的
如不明白欢迎追问

#2


因为你的L是NULL,而你又去使用*L去解引他自然出错啦

主函数中你要写成这样;

LinkList xx;
CreateListHead(&xx, 10);

#3


引用 1 楼 cyfcsd 的回复:
#include <iostream>
using namespace std;
typedef struct Node {
    int data;
    Node *next;
}relNode;
typedef relNode *LinkList;
void CreateListHead(LinkList *L, int n) {
    LinkList p;
    int i;
    (*L) = (LinkList)malloc(sizeof(Node));//这里有问题。。。
    (*L)->next = NULL;
    for (i = 0; i < n; i++) {
        p = (LinkList)malloc(sizeof(Node));
        p->data = i;
        p->next = (*L)->next;
        (*L)->next = p;
    }
 
}
 
int main() {
    LinkList L = NULL;
    CreateListHead(&L, 10);
return 0;
 
}

这么写才是对的,书上主函数内部分写的不对,没有必要定义二级指针,但传参数的时候要传二级指针,因为只有传二级指针才能改变一级指针,这跟只有传指针才能改变值是一个道理
你改的那个虽然没有报错,但L并没有被改变,也就是那个函数没起作用,也是不对的
如不明白欢迎追问


大神你好,这个问题我明白了,我还有一段程序,想请教您一下

void ListDelete(LinkList *L, int n) {
    int j;
    LinkList r, p;
    r = *L;
    j = 1;
    for (; r->next != NULL&&j < n; r = r->next, j++);
    if (!(r->next) || j > n)//这里我不太明白
        cout << "删除失败" << endl;
    else {
        p = r->next;
        r->next = p->next;
        free(p);
    }
}

1、j>n这是一种什么样的情况?上面循环条件不是已经确保了j<n吗?
2、!(r->next) 和 r->next == NULL是不是等价的呢?如果是等价的, if (!(r->next) || j > n)这句话的意思不就是“如果下一个元素的位置是空的,或者当前位置在指定位置之后”么?那是怎么把链表的最后一个元素删除的呢?

#4


1.上面的循环条件是r->next != NULL&&j < n
也就是说如果r->next是NULL了也会跳出循环,比如你输入了一个很小的n(比如是个负数),j > n就为真了

2.!(r->next) 和 r->next == NULL是等价的。怎么把链表的最后一个元素删除,楼主问这个问题说明程序并没有搞的很清楚。
它要删除的结点是r->next而不是r,搞清楚这点你就明白了

#5


版主说的不错,j>n是为了防止出现给的位置过小的,比如链表有10个元素,那n的正常范围是1≤n≤10,如果给的n太小了,比如是0或者负数,则应该输出删除错误而不执行删除动作,如果不这样,那就会把第一个元素误删了!
!(r->next) 和 r->next == NULL是等价的,而且推荐第二种写法,可读性较强。至于怎么删除最后一个元素,这就是链表操作最基本的注意点了,删除元素时找到的一定是要删除元素的前一个位置,即r是指向要删除的前一个元素时循环停止,所以r初始化为*L,这个节点叫链表的头结点,它的data域为空,这就是为了方便这种操作用的
而且我感觉这种不会改变头指针的操作最好不要传头指针的地址,直接传头指针就好,即实参用LinkList L

#6


崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack即“调用堆栈”里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处, 看不懂时双击下一行,直到能看懂为止