使用带有char **类型的strlcpy后,有时会覆盖值

时间:2017-03-06 19:42:32

标签: c pointers segmentation-fault

我最近一直在努力学习C以更好地理解(相对)低级编程,因为我通常在Python,PHP,Swift,Java,Javascript等工作中完成大部分工作。我想我理解指针的概念以及如何分配/释放内存,但在一个特定的实例中,我很困惑。似乎有时(可能<10%的时间)我必须测试strlcpy的一些代码会产生意想不到的结果。其他90%以上的时间,按预期工作。以下是我正在运行的代码,其中包含描述我的意图的评论:

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

void populate(int length, size_t size, char **strings) {
    char test[5] = "test"; //the string we use to populate our incoming array
    for (int i = 0; i < length; ++i) //iterate through the length of the string array
    {
        strings[i] = malloc(sizeof(*strings) * size); //allocate memory for this string to the size of {size}
        strlcpy(*(strings + i), test, size); //copy our test string to the string at index {i} of our array
        printf("%p - ", (void *) strings[i]); //print the address as a dummy check
        printf("String %d: %s\n", i, strings[i]); //confirm our string is being copied as expected
    }
}

int main() {
    int length = 3; //the length of our array of strings
    size_t size = 5; //the length of each string
    char **strings = malloc(sizeof(**strings) * length); //a pointer to a {length}-element array of char pointers
    printf("Start iteration 1\n");
    populate(length, size, strings); //a function which fills **strings with {length} strings of size {size}
    printf("Start iteration 2\n");
    for (int i = 0; i < length; ++i) //iterate through each string to validate the result
    {
        printf("%p - ", (void *) strings[i]); //print the address as a dummy check
        printf("String %d: %s\n", i, strings[i]); //display our string at index {i}
        free(strings[i]); //free the memory of this string
    }
    free(strings); //free the memory of our string array
    return 0;
}

我构建这个是为了更好地理解**指向指针的语法和逻辑。在大多数情况下,一切似乎都运行正常,我将在我的控制台中获得以下打印输出:

Start iteration 1
0x7ffd70c027a0 - String 0: test
0x7ffd70c027b0 - String 1: test
0x7ffd70c027c0 - String 2: test
Start iteration 2
0x7ffd70c027a0 - String 0: test
0x7ffd70c027b0 - String 1: test
0x7ffd70c027c0 - String 2: test

Process finished with exit code 0

但是,有时候,在第二次迭代中显示的一些值要么不正确,要么导致我认为是分段错误:

Start iteration 1
0x7f9f78f00840 - String 0: test
0x7f9f78f00850 - String 1: test
0x7f9f78f00860 - String 2: test
Start iteration 2
0x7f9f78f00840 - String 0: �x�
0x7f9f78f00850 - String 1: test

Process finished with exit code 11

我无法弄清楚为什么会发生这种情况,但我认为根据我的结果,我可以安全地假设它超出了populate函数的范围。我的指针算术有问题吗?在某些情况下,我没有分配足够的内存吗?

最初,我认为这可能与我在main函数结束时释放内存的方式有关,但我在SO中查找了几个问题,发现我似乎是通过在释放外部数组(*strings)之前首先释放内部数组(strings)来正确执行此操作。但是,基于错误的位置,我仍然有理由相信问题可能与我如何释放内存有关。我只是无法弄清楚我做错了什么。

任何建议将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:3)

问题是:char **strings = malloc(sizeof(**strings) * length);

请注意,您正在分配sizeof(**strings)char **解除引用两次仅为char,因此sizeof(**strings)为1.因此,您只需分配3个字节。那不是你想要的。

相反,您需要sizeof(*strings),该内容存储在strings中。这将是char *,将是4或8,具体取决于你是32位还是64位。