如何将结构副本修复为结构段错误

时间:2018-09-30 18:12:58

标签: c memory-leaks segmentation-fault

我有以下两个结构:

typedef struct {
    char* key;
    char* value;
} kvpair;

typedef struct {
    kvpair ** array;
    size_t length;
} kvarray;

我想将新的键和值对复制到kvarray。我使用realloc为要添加到kvpair数组中的每个新项目分配内存,但是努力弄清楚如何复制键和值。

如果我这样做:

  kvs->array resized using realloc

    // *** get segfault here!!! how to fix ***
    kvs->array[kvs->length]->key = key;
  kvs->array[kvs->length]->value = value;

但是,如果我为kvpair *单独分配内存,并这样做:

kvpair* kvp = malloc(sizeof(kvpair));
// copy key and value

// This below then works
kvs->array[kvs->length] = kvp;
// but there is a memory leak - or seems to be double allocation of memory for same thing

如何正确执行此操作?

下面是代码(请参见// *在此处获取段错误!如何修复* 注释)

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


typedef struct {
    char* key;
    char* value;
} kvpair;

typedef struct {
    kvpair ** array;
    size_t length;
} kvarray;

kvarray * readKVs(const char** array, size_t length);
void freeKVs(kvarray * pairs);

int main() {
    const char* things[] = { "wood=brown\n", "brick=red\n", 
        "grass=green", "hedge=green", "leaf=green" };
    const size_t sz = sizeof(things) / sizeof(things[0]);

    kvarray* kvs = readKVs(things, sz);
    freeKVs(kvs);
}

kvarray * readKVs(const char** array, size_t length) {

    kvarray* kvs = NULL;

    for (size_t i = 0; i < length; ++i) {
        const char* line = array[i];

        if (kvs == NULL) {
            kvs = malloc(sizeof(kvarray));
            kvs->length = 0;
            kvs->array = NULL;
        }

        char * found = strchr(line, '=');
        if (found == NULL) {
            // skip to next line
            continue;
        }

        size_t len = strlen(line);
        size_t pos = found - array[i];

        char* value = NULL;
        if (len > (pos + 1)) {
            // non-blank value
            // length of value is len - pos
            value = malloc(len - (pos + 1));
            strncpy(value, &line[pos + 1], (len - (pos + 1)) - 1);
            // null terminate string
            value[len - (pos + 1) - 1] = '\0';
            printf("value:'%s'\n", value);
        }

        char* key = malloc(found - line + 1);  // +1 for null terminator
        strncpy(key, line, pos);
        // remember strncpy bug!
        key[found - line] = '\0';  // ensure null termination. 
        printf("key:'%s', length=%lu\n", key, strlen(key));

        /*
        // if I allocate an individual pair, then I am duplicating memory so should have to do this below
        kvpair* kvp = malloc(sizeof(kvpair));
        //kvpair kvp = {NULL, NULL};
        printf("about to assign kvs->key = key\n");
        kvp->key = key;
        printf("about to assign kvs->value = value\n");
        kvp->value = value;
        */

        kvs->array = realloc(kvs->array, (kvs->length + 1) * sizeof(kvpair*));

        // I want to be able to do this 2 lines below - but crashes
        // *** get segfault here!!! how to fix ***
        kvs->array[kvs->length]->key = key;
        kvs->array[kvs->length]->value = value;

        kvs->length++;
        printf("kvs->length now=%lu\n", kvs->length);
    }
    return kvs;
}

void freeKVs(kvarray * pairs) {
    if (pairs == NULL) {
        return;
    }

    for (size_t i = 0; i < pairs->length; ++i) {
        free(pairs->array[i]->key);
        free(pairs->array[i]->value);
        free(pairs->array[i]);
    }
    free(pairs);
}

1 个答案:

答案 0 :(得分:2)

这样做的时候

kvs->array = realloc(kvs->array, (kvs->length + 1) * sizeof(kvpair*));

分配的新内存的内容将不确定,未初始化。那意味着下一行

kvs->array[kvs->length]->key = key;

您将取消引用无效的指针kvs->array[kvs->length]。那当然会导致undefined behavior

解决方案当然是使kvs->array[kvs->length]指向某个有效的地方,例如这样做

kvs->array[kvs->length] = malloc(sizeof(kvpair));