无法确定分配内存的正确算法

Cant determine correct algorithm to allocate memory

我有这段代码,我正在用 C 编写一个动态数组。所以这里的主要问题基本上是假设您将值 1 添加到数组,然后您决定添加值 5。好吧我的情况是,当您尝试打印假定为 1 的索引 0 时,它会给我一个段错误。但是当你打印索引 1 时,它给了我 5,这是正确的值。由于某种原因,它忘记了除一个当前值之外的所有先前添加的值。我已经完成了 valgrind 检查,我会在显示文件后显示结果:

Vertex.h:

#ifndef _VERTEX_AM_H_LB
#define _VERTEX_AM_H_LB 1
#pragma once
#include<stdint.h>
/**
 * Vertex Library C
 *
 * GCC C99 <Vertex.h>
 *
 * @author Amanuel Bogale
 * @copyright 2016 Amanuel Bogale
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 */

//@union for storing
//data types supported
//for vertex
typedef union
    {
        char ch; //1 byte
        unsigned char uch;//1 byte
        signed char sch;// 1 byte
        int in;//2 or 4bytes
        unsigned int uin;//2 or 4bytes
        long ln;// 4byte
        unsigned long uln; //4byte
        long long lnln; //8byte
        short sh;// 2byte
        unsigned short ush; //2bytes
        float fl;//4byte
        double db; //8byte
        long double ldb; //10byte
}type;

/*
 * @struct for defining
 * vertex. Initalize First
 */
struct vertex_am
{
    size_t current_size;
    type type;
    long long size_contents;
    void **contents; //Array Of Void Pointers
    //Add to the end of array
    void (*add)(struct vertex_am *self,void*val);
};

typedef struct vertex_am vertex_am;



vertex_am* init_vertex(size_t size, vertex_am* vertex);
void end_vertex(vertex_am* vertex);
long long get_elements_num(vertex_am vert);
void add_end(vertex_am *vert, void* val);
void* get_val(vertex_am vert,long long index);
int get_first_index(vertex_am vert, void*key);
int get_last_index(vertex_am vert, void*key);
#endif

Vertex.c:

#include<stdlib.h>
#include<stdio.h>
#include<stdint.h>
#include "../includes/Vertex.h"

/**
 * Vertex Library C
 *
 * GCC C99 <Vertex.c>
 *
 * @author Amanuel Bogale
 * @copyright 2016 Amanuel Bogale
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 */

vertex_am* init_vertex(size_t size, vertex_am* vertex)
{
    vertex = malloc(size);
    vertex->current_size = size;
    vertex->size_contents = 0;
    return vertex;
}

long long get_elements_num(vertex_am vert)
{
    return(vert.size_contents);
}

void add_end(vertex_am *vert, void* val)
{
    vert->contents = (void **)malloc(sizeof(vert->contents) + (sizeof(val)) );
//  vert->contents = (void **)malloc(sizeof(void)*(vert->size_contents+1));
    vert->contents[vert->size_contents] = val;
    vert->size_contents++;
}

void* get_val(vertex_am vert,long long index)
{
    return (vert.contents[index]);
}

int get_first_index(vertex_am vert, void*key)
{
    int returner;
    for(int i=0; i<=(vert.size_contents); i++)
    {
        if(vert.contents[i] == key)
        {
            returner=i;
            break;
        }
    }
    return (returner);
}

int get_last_index(vertex_am vert, void*key)
{
    int returner;
    for(int i=0; i<=(vert.size_contents); i++)
        {
            if(vert.contents[i] == key)
            {
                returner=i;
            }
        }
    return (returner);
}


void end_vertex(vertex_am* vertex)
{
    free(vertex);
}

main.c:

#include<stdlib.h>
#include<stdio.h>
#include<stdint.h>
#include "includes/Vertex.h"

int main()
{
    int n = 34;
    int x = 33;
    int y = 44;
    vertex_am *vert = NULL;


    vert = init_vertex(sizeof(*vert), vert);
    add_end(vert,&n);
    add_end(vert,&x);
    add_end(vert,&y);


//  int *anwser = (int*) get_val(*vert, 2);
//  printf("Val : %d \n",*anwser);

    int *check = (int*)vert->contents[2];
    printf("%d" , *check);


    int first_index_anwser = get_first_index(*vert,&n);// &n same as 34. So find first 34 in dyn_array
    printf("First Index : %d \n",first_index_anwser);

    int last_index_anwser = get_last_index(*vert,&n);// &n same as 34. So find Last 34 dyn_array
    printf("Last Index : %d \n",last_index_anwser);

    end_vertex(vert);
    return 0;
}


/*
 * TODO POP:
 * pop_beg
 * pop_last
 * pop_index
 *
 * TODO add:
 * add_beg
 * add_index
 *
 * TODO index:
 * by_index instead of first last
 */

这里的问题正如你在这里看到的,我正在打印 main.c 中的当前索引:

int *check = (int*)vert->contents[2];
        printf("%d" , *check);

因为如您在 main.c 中看到的那样添加了三个项目...并且第二个索引是最新的。好吧,如果我尝试打印索引 1 或 0,由于某种原因,它会出现分段错误......就像我说的,我已经为此做了一个 valgrind 检查,我得到了这个:

==37900== Memcheck, a memory error detector
==37900== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==37900== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==37900== Command: ./main
==37900== 
==37900== Invalid write of size 8
==37900==    at 0x4008A1: add_end (Vertex.c:34)
==37900==    by 0x400747: main (main.c:17)
==37900==  Address 0x5420170 is 0 bytes after a block of size 16 alloc'd
==37900==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37900==    by 0x40087A: add_end (Vertex.c:32)
==37900==    by 0x400747: main (main.c:17)
==37900== 
==37900== Invalid read of size 8
==37900==    at 0x400750: main (main.c:23)
==37900==  Address 0x5420170 is 0 bytes after a block of size 16 alloc'd
==37900==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37900==    by 0x40087A: add_end (Vertex.c:32)
==37900==    by 0x400747: main (main.c:17)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x400900: get_first_index (Vertex.c:48)
==37900==    by 0x400795: main (main.c:27)
==37900== 
==37900== Invalid read of size 8
==37900==    at 0x4008F9: get_first_index (Vertex.c:48)
==37900==    by 0x400795: main (main.c:27)
==37900==  Address 0x5420170 is 0 bytes after a block of size 16 alloc'd
==37900==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37900==    by 0x40087A: add_end (Vertex.c:32)
==37900==    by 0x400747: main (main.c:17)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A4B43: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007B0: main (main.c:28)
==37900== 
==37900== Use of uninitialised value of size 8
==37900==    at 0x50A172B: _itoa_word (_itoa.c:179)
==37900==    by 0x50A50EC: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007B0: main (main.c:28)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A1735: _itoa_word (_itoa.c:179)
==37900==    by 0x50A50EC: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007B0: main (main.c:28)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A516F: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007B0: main (main.c:28)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A4C19: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007B0: main (main.c:28)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A53DA: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007B0: main (main.c:28)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A4C6B: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007B0: main (main.c:28)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A4CA2: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007B0: main (main.c:28)
==37900== 
44First Index : 44 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x40094B: get_last_index (Vertex.c:62)
==37900==    by 0x4007D7: main (main.c:30)
==37900== 
==37900== Invalid read of size 8
==37900==    at 0x400944: get_last_index (Vertex.c:62)
==37900==    by 0x4007D7: main (main.c:30)
==37900==  Address 0x5420170 is 0 bytes after a block of size 16 alloc'd
==37900==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37900==    by 0x40087A: add_end (Vertex.c:32)
==37900==    by 0x400747: main (main.c:17)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A4B43: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007F2: main (main.c:31)
==37900== 
==37900== Use of uninitialised value of size 8
==37900==    at 0x50A172B: _itoa_word (_itoa.c:179)
==37900==    by 0x50A50EC: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007F2: main (main.c:31)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A1735: _itoa_word (_itoa.c:179)
==37900==    by 0x50A50EC: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007F2: main (main.c:31)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A516F: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007F2: main (main.c:31)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A4C19: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007F2: main (main.c:31)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A53DA: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007F2: main (main.c:31)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A4C6B: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007F2: main (main.c:31)
==37900== 
==37900== Conditional jump or move depends on uninitialised value(s)
==37900==    at 0x50A4CA2: vfprintf (vfprintf.c:1631)
==37900==    by 0x50AC848: printf (printf.c:33)
==37900==    by 0x4007F2: main (main.c:31)
==37900== 
Last Index : 44 
==37900== 
==37900== HEAP SUMMARY:
==37900==     in use at exit: 48 bytes in 3 blocks
==37900==   total heap usage: 5 allocs, 2 frees, 1,136 bytes allocated
==37900== 
==37900== LEAK SUMMARY:
==37900==    definitely lost: 48 bytes in 3 blocks
==37900==    indirectly lost: 0 bytes in 0 blocks
==37900==      possibly lost: 0 bytes in 0 blocks
==37900==    still reachable: 0 bytes in 0 blocks
==37900==         suppressed: 0 bytes in 0 blocks
==37900== Rerun with --leak-check=full to see details of leaked memory
==37900== 
==37900== For counts of detected and suppressed errors, rerun with: -v
==37900== Use --track-origins=yes to see where uninitialised values come from
==37900== ERROR SUMMARY: 30 errors from 22 contexts (suppressed: 0 from 0)
amanuel@ubuntu:~/Code/E-Workspace/CustLibs$ 

针对 Vertex.c 中的添加函数的许多无效写入:

void add_end(vertex_am *vert, void* val)
{
    vert->contents = (void **)malloc(sizeof(vert->contents) + (sizeof(val)) );
//  vert->contents = (void **)malloc(sizeof(void)*(vert->size_contents+1));
    vert->contents[vert->size_contents] = val;
    vert->size_contents++;
}

。这是关于这个问题的所有信息,如往常一样,我们将不胜感激。

您在调用 malloc 时使用的表达式 sizeof(vert->contents) + (sizeof(val)) 不会像您预期的那样工作。它会为两个指针分配space,仅此而已。无论您要为多少条目分配内存,您都只会得到 8 或 16 个字节(取决于您使用的是 32 位还是 64 位平台)。

我猜你应该分配 sizeof(*vert->contents) * (vert->size_contents+1) 字节。


还有一个问题:每次调用add_end都会分配一块新的内存,完全忽略旧的内存,会导致内存泄漏,以及大量未初始化的内存进行上述更改后的内存。

如果你想重新分配内存,你应该使用 realloc。如果您正确地将指针初始化为 NULL.

,您甚至可以将其用于初始分配

所以代码应该是这样的

void **temp = realloc(vert->contents, sizeof(*vert->contents) * (vert->size_contents+1));
if (temp == NULL)
{
    // TODO: Handle error
}
else
{
    vert->contents = temp;
    // Rest of your code...
}

在第一次调用 realloc 之前将 vert->contents 初始化为 NULL 很重要,否则您将有 未定义的行为