如何修复';从0x4000000000000000读取内存失败(读取4个字节中的0个)';C中的错误
我在C上有一个简单的练习要做。但是当我用malloc初始化变量图时,它不能正确执行操作。这是我的密码:如何修复';从0x4000000000000000读取内存失败(读取4个字节中的0个)';C中的错误,c,malloc,C,Malloc,我在C上有一个简单的练习要做。但是当我用malloc初始化变量图时,它不能正确执行操作。这是我的密码: #include <stdio.h> #include <stdlib.h> #include <stdbool.h> typedef int Weight; typedef struct aux { int vDest; Weight weight; struct aux * next; } TypeEdge; typedef
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int Weight;
typedef struct aux {
int vDest;
Weight weight;
struct aux * next;
} TypeEdge;
typedef TypeEdge* TypePointer;
typedef struct {
TypePointer * listAdj;
int numVertices;
int numEdges;
} TypeGraph;
typedef int* TipoInt;
bool initializeGraph(TypeGraph *graph, int nv) {
if (nv < 0) {
return false;
}
graph->numVertices = nv;
graph->numEdges = 0;
int i;
for (i = 0; i < nv; i++) {
graph->listAdj = (TypePointer*) malloc(sizeof(TypePointer));
}
for (i = 0; i < nv; i++) {
graph->listAdj[i] = NULL;
}
return true;
}
void insertEdge(int v1, int v2, Weight weight, TypeGraph *graph) {
if (v1 < 0 || v1 > graph->numVertices || v2 < 0 || v2 > graph->numVertices) {
return;
}
TypePointer actual = graph->listAdj[v1];
while (actual->next) {
actual = actual->next;
}
TypePointer pNew = (TypePointer) malloc(sizeof(TypeEdge));
pNew->vDest = v2;
pNew->weight = weight;
pNew->next = NULL;
actual->next = pNew;
}
int main() {
TypeGraph graph;
bool result = initializeGraph(&graph, 100);
if (result) {
insertEdge(2, 3, 1, &graph);
}
return 0;
}
#包括
#包括
#包括
输入重量;
类型定义结构辅助{
int vDest;
重量;
结构辅助*下一步;
}字体边缘;
typedef TypeEdge*类型指针;
类型定义结构{
TypePointer*listaj;
智力;
国际努梅德斯;
}打字机;
typedef int*TipoInt;
布尔初始化图(类型图*图形,内部nv){
如果(nv<0){
返回false;
}
图形->数值=nv;
图形->numEdges=0;
int i;
对于(i=0;ilistAdj=(类型指针*)malloc(sizeof(类型指针));
}
对于(i=0;ilistAdj[i]=NULL;
}
返回true;
}
void insertEdge(int v1、int v2、权重、类型图*图形){
如果(v1<0 | | v1>图形->数值垂直度| | v2<0 | | v2>图形->数值垂直度){
返回;
}
类型指针实际值=图形->列表调整[v1];
while(实际->下一步){
实际=实际->下一步;
}
TypePointer pNew=(TypePointer)malloc(sizeof(TypeEdge));
pNew->vDest=v2;
pNew->weight=重量;
pNew->next=NULL;
实际->下一步=pNew;
}
int main(){
类型图;
bool结果=初始化图形(&graph,100);
如果(结果){
插入边缘(2、3、1和图形);
}
返回0;
}
问题是,它没有初始化大小为100 TypePointer的图形,而是只初始化大小为2的图形,并且不执行任何操作。当我尝试在Clion
上调试它时,它会显示以下错误消息:从0x4000000000000000读取内存失败(读取4个字节中的0个)
。如果我只是运行代码,它将返回代码11
拜托,有人能帮帮我吗?你的手上真是一团糟。这是由指针的
typedef
”造成的,但主要是因为您没有分配nv
指针,而是分配了相同的listaj
指针,然后立即用NULL
覆盖指针,造成100个内存泄漏
想想看:
for (i = 0; i < nv; i++) {
graph->listAdj = (TypePointer*) malloc(sizeof(TypePointer));
}
您只尝试分配一个graph->listAdj
(虽然分配了100次),而不是您想要的nv
指针。必须立即为nv
指针分配存储
现在,让我们从头开始,通过删除所有typedef
s,并简单地为bool
使用int
,来清理问题,例如
#include <stdio.h>
#include <stdlib.h>
typedef struct aux {
int vDest;
int weight;
struct aux *next;
} TypeEdge;
typedef struct {
TypeEdge **listAdj;
int numVertices;
int numEdges;
} TypeGraph;
接下来,当您insertEdge()
时,必须处理插入该顶点的第一条边的情况,或者是否需要迭代到列表的末尾并在那里插入。您还需要调整迭代到结尾的方式,以确保在actual
为NULL
时,不会尝试访问actual->next
。把这些放在一起,你可以做到:
TypeEdge *insertEdge (int v1, int v2, int weight, TypeGraph *graph)
{
if (v1 < 0 || v1 > graph->numVertices ||
v2 < 0 || v2 > graph->numVertices) {
return NULL;
}
TypeEdge *actual = graph->listAdj[v1];
while (actual && actual->next)
actual = actual->next;
TypeEdge *pNew = malloc(sizeof *pNew);
if (!pNew) {
perror ("malloc-pNew");
return NULL;
}
pNew->vDest = v2;
pNew->weight = weight;
pNew->next = NULL;
if (!actual)
graph->listAdj[v1] = pNew;
else
actual->next = pNew;
return (pNew);
}
如果您已经分配了内存,那么还需要能够释放该内存。类似的短函数集可以处理释放每个列表,例如
void freelist (TypeEdge *l)
{
while (l) {
TypeEdge *victim = l;
l = l->next;
free (victim);
}
}
void free_graphlists (TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
freelist (g->listAdj[i]);
free (g->listAdj);
}
总而言之,你可以做到:
#include <stdio.h>
#include <stdlib.h>
typedef struct aux {
int vDest;
int weight;
struct aux *next;
} TypeEdge;
typedef struct {
TypeEdge **listAdj;
int numVertices;
int numEdges;
} TypeGraph;
int initializeGraph (TypeGraph *graph, int nv)
{
if (nv < 0)
return 0;
graph->numVertices = nv;
graph->numEdges = 0;
int i;
if ((graph->listAdj = malloc(sizeof *graph->listAdj * nv)) == NULL) {
perror ("malloc-graph->listAdj");
return 0;
}
for (i = 0; i < nv; i++)
(graph->listAdj)[i] = NULL;
return 1;
}
TypeEdge *insertEdge (int v1, int v2, int weight, TypeGraph *graph)
{
if (v1 < 0 || v1 > graph->numVertices ||
v2 < 0 || v2 > graph->numVertices) {
return NULL;
}
TypeEdge *actual = graph->listAdj[v1];
while (actual && actual->next)
actual = actual->next;
TypeEdge *pNew = malloc(sizeof *pNew);
if (!pNew) {
perror ("malloc-pNew");
return NULL;
}
pNew->vDest = v2;
pNew->weight = weight;
pNew->next = NULL;
if (!actual)
graph->listAdj[v1] = pNew;
else
actual->next = pNew;
return (pNew);
}
void prnedge (const TypeEdge *e)
{
do
printf (" %3d %3d\n", e->vDest, e->weight);
while ((e = e->next));
}
void print_edge (const TypeEdge *e, int edge)
{
printf ("\nedge %d\n", edge);
prnedge (e);
}
void print_graph (const TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
print_edge (g->listAdj[i], i);
}
void freelist (TypeEdge *l)
{
while (l) {
TypeEdge *victim = l;
l = l->next;
free (victim);
}
}
void free_graphlists (TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
freelist (g->listAdj[i]);
free (g->listAdj);
}
int main (void) {
TypeGraph graph;
int result = initializeGraph (&graph, 100);
if (result) {
insertEdge (2, 3, 1, &graph);
insertEdge (2, 4, 1, &graph);
}
print_graph (&graph);
free_graphlists (&graph);
return 0;
}
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于所分配的任何内存块,您有两个责任:(1)始终保留指向内存块起始地址的指针,以便(2)在不再需要它时可以释放它
必须使用内存错误检查程序,以确保您不会试图访问内存或写入超出/超出分配的块的边界,尝试在未初始化的值上读取或建立条件跳转,最后确认释放所有已分配的内存
对于Linux,valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很容易使用,只需运行程序即可
$ valgrind ./bin/edgetype
==21679== Memcheck, a memory error detector
==21679== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==21679== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==21679== Command: ./bin/edgetype
==21679==
edge 2
3 1
4 1
==21679==
==21679== HEAP SUMMARY:
==21679== in use at exit: 0 bytes in 0 blocks
==21679== total heap usage: 3 allocs, 3 frees, 832 bytes allocated
==21679==
==21679== All heap blocks were freed -- no leaks are possible
==21679==
==21679== For counts of detected and suppressed errors, rerun with: -v
==21679== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放所有已分配的内存,并且没有内存错误
仔细检查一下,如果您还有其他问题,请告诉我。您的
初始化图和插入图中有一些错误。这个改变应该对你有用
bool initializeGraph(TypeGraph *graph, int nv)
{
if (nv < 0) {
return false;
}
graph->numVertices = nv;
graph->numEdges = 0;
/* call `calloc` to avoid using for-loop to zero memory */
graph->listAdj = calloc(nv, sizeof(TypePointer));
return true;
}
void insertEdge(int v1, int v2, Weight weight, TypeGraph *graph)
{
if (v1 < 0 || v1 > graph->numVertices || v2 < 0 || v2 > graph->numVertices) {
return;
}
/* just insert the node at the head of the adjList */
TypePointer pNew = malloc(sizeof(TypeEdge));
pNew->vDest = v2;
pNew->weight = weight;
pNew->next = graph->listAdj[v1];
graph->listAdj[v1] = pNew;
graph->numEdges++;
}
bool初始化图(TypeGraph*graph,int-nv)
{
如果(nv<0){
返回false;
}
图形->数值=nv;
图形->numEdges=0;
/*调用'calloc',以避免使用for循环将内存归零*/
graph->listAdj=calloc(nv,sizeof(TypePointer));
返回true;
}
void insertEdge(int v1、int v2、权重、类型图*图形)
{
如果(v1<0 | | v1>图形->数值垂直度| | v2<0 | | v2>图形->数值垂直度){
返回;
}
/*只需在adjList的开头插入节点*/
TypePointer pNew=malloc(sizeof(TypeEdge));
pNew->vDest=v2;
pNew->weight=重量;
pNew->next=graph->listAdj[v1];
图表->列表调整[v1]=pNew;
图形->numEdges++;
}
至于typedef,请阅读并自行决定是否使用。就我个人而言,除非必要,否则我会避免使用typedef
。避免typedef
”指针。它隐藏信息。查看:。初始化100次,每次都覆盖上一个指针。
int main (void) {
TypeGraph graph;
int result = initializeGraph (&graph, 100);
if (result) {
insertEdge (2, 3, 1, &graph);
insertEdge (2, 4, 1, &graph);
}
print_graph (&graph);
free_graphlists (&graph);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct aux {
int vDest;
int weight;
struct aux *next;
} TypeEdge;
typedef struct {
TypeEdge **listAdj;
int numVertices;
int numEdges;
} TypeGraph;
int initializeGraph (TypeGraph *graph, int nv)
{
if (nv < 0)
return 0;
graph->numVertices = nv;
graph->numEdges = 0;
int i;
if ((graph->listAdj = malloc(sizeof *graph->listAdj * nv)) == NULL) {
perror ("malloc-graph->listAdj");
return 0;
}
for (i = 0; i < nv; i++)
(graph->listAdj)[i] = NULL;
return 1;
}
TypeEdge *insertEdge (int v1, int v2, int weight, TypeGraph *graph)
{
if (v1 < 0 || v1 > graph->numVertices ||
v2 < 0 || v2 > graph->numVertices) {
return NULL;
}
TypeEdge *actual = graph->listAdj[v1];
while (actual && actual->next)
actual = actual->next;
TypeEdge *pNew = malloc(sizeof *pNew);
if (!pNew) {
perror ("malloc-pNew");
return NULL;
}
pNew->vDest = v2;
pNew->weight = weight;
pNew->next = NULL;
if (!actual)
graph->listAdj[v1] = pNew;
else
actual->next = pNew;
return (pNew);
}
void prnedge (const TypeEdge *e)
{
do
printf (" %3d %3d\n", e->vDest, e->weight);
while ((e = e->next));
}
void print_edge (const TypeEdge *e, int edge)
{
printf ("\nedge %d\n", edge);
prnedge (e);
}
void print_graph (const TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
print_edge (g->listAdj[i], i);
}
void freelist (TypeEdge *l)
{
while (l) {
TypeEdge *victim = l;
l = l->next;
free (victim);
}
}
void free_graphlists (TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
freelist (g->listAdj[i]);
free (g->listAdj);
}
int main (void) {
TypeGraph graph;
int result = initializeGraph (&graph, 100);
if (result) {
insertEdge (2, 3, 1, &graph);
insertEdge (2, 4, 1, &graph);
}
print_graph (&graph);
free_graphlists (&graph);
return 0;
}
$ ./bin/edgetype
edge 2
3 1
4 1
$ valgrind ./bin/edgetype
==21679== Memcheck, a memory error detector
==21679== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==21679== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==21679== Command: ./bin/edgetype
==21679==
edge 2
3 1
4 1
==21679==
==21679== HEAP SUMMARY:
==21679== in use at exit: 0 bytes in 0 blocks
==21679== total heap usage: 3 allocs, 3 frees, 832 bytes allocated
==21679==
==21679== All heap blocks were freed -- no leaks are possible
==21679==
==21679== For counts of detected and suppressed errors, rerun with: -v
==21679== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
bool initializeGraph(TypeGraph *graph, int nv)
{
if (nv < 0) {
return false;
}
graph->numVertices = nv;
graph->numEdges = 0;
/* call `calloc` to avoid using for-loop to zero memory */
graph->listAdj = calloc(nv, sizeof(TypePointer));
return true;
}
void insertEdge(int v1, int v2, Weight weight, TypeGraph *graph)
{
if (v1 < 0 || v1 > graph->numVertices || v2 < 0 || v2 > graph->numVertices) {
return;
}
/* just insert the node at the head of the adjList */
TypePointer pNew = malloc(sizeof(TypeEdge));
pNew->vDest = v2;
pNew->weight = weight;
pNew->next = graph->listAdj[v1];
graph->listAdj[v1] = pNew;
graph->numEdges++;
}