2

程序员!

我完全沉迷于双指针(指针对指针)......这里有很多问题!

让我们从这个任务开始:我正在编写自定义版本的“calloc”函数,它必须返回指向“n”个大小为“size”的内存元素的指针。这是我发明的:

void **calloc1(int n, int size)
{
    int i, j;
    char *tmp, **p = NULL;
    tmp = (char *) malloc1(n * size);
    p = tmp;
    for (i = 0; i < n; i++) {
        p[i] = tmp;
        for (j = 0; j < size; j++)
            tmp++;
    }
    p = &p[0];
    return (void **)p;
}
/* I entered n==4, size==3;  real pointers are: p[0] == 0x804cfe0; p[1] == 0x804cfe3; p[2] == 0x804cfe6; ... */

所以,基本上我分配 n*size 个字节,然后将相等“大小”的指针数组“分配”到相应的起始位置。让我们输入 n=4 和 size=3;这意味着 p[0] 指向 tmp[0],p[1] 指向 tmp[3],p[2] 指向 tmp[6] 等等。在 GDB 中,我几乎在每一步之后都跟踪指针值。

然后,在“main”中,我声明了一个双指针并将其“附加”到从我的“calloc”接收到的缓冲区中:

int main (short argc, char **argv)
    {
        char **space;
        space = (char **) calloc1(n, size);   /* removing '(char**)' here does not have effect */ 

    /*  at this stage pointers seems to be correctly "located": 'space' == 'space[0]' == 0x804cfe0; 'space[1]' == 0x804cfe3; 'space[2]' == 0x804cfe6; ... */

1)这已经是第一个问题:'main()'(或我将传递** p副本的任何其他函数)如何知道指针算术的大小?例如,'main()' 是如何知道如果我将 '1' 添加到 'space' (或简单地增加一次),它应该指向它的第二个指针(在 'calloc' 中它是 p[1]),它(在这种特殊情况下)是第一个指针(p [0])的3个字符吗?此外,如果我在 'alloc' 数组中创建指向具有“可变长度”的字符串的指针(例如,p[0] 指向 tmp[0],p[1] 指向 tmp[7],p[2] 指向 tmp [11] 等),任何其他函数如何知道它应该在哪里将“上”指针增加 4 以及在哪里增加 7 个“字符”?

好吧,我们更进一步,我尝试将一些字符放入获取的缓冲区:

int i = 0, j = 0, n, size;
char nn, ssize, c, temp[3];

printf ("Enter number/size \n");
sc = scanf ("%c/%c", &nn, &ssize);
n = nn - '0';  /* n==4 */
size = ssize - '0';   /* size==3 */ 

printf ("Enter a 'number' of words\n");
while (j < n) {
    for (i = 0; (c = getchar()) != EOF && i < size; i++)
        *(*space)++ = c; 
    (*space)--;   /* this line is unneccesary; if I remove it - nothing changes */
    ++j;
    ++space;
}

2)这是第一个问题的证据:实际上,当我在这里增加“空间”时,它移动的不是3而是4个字符(在第一个'++'之后它是0x804cfe4,在第二个0x804cfe8之后)。为什么?与“浮动”型尺寸有什么联系吗?在第一次这样递增之后,'*space' 指向 0x804cfe6...我认为它不正确。

我尝试了另一种方式 - 引用“空间”,而不是指针而是数组:

....
while (j < n) {
    for (i = 0; (c = getchar()) != EOF && i < size; i++)
        *space[j]++ = c; 
    space[j]--;
    ++j;
}

3) 在这种情况下,指针似乎没问题 - 例如 space[1] == 0x804cfe3,space[2] == 0x804cfe6。问题是,当这个循环在 j == 2 的情况下运行时,'space[0]' 的值不知何故从 0x804cfe2(移动了两次 - ok)变成了 0x6a04cfe2(超出范围)。什么。。???

4) 而且,地址有一些奇怪的行为。我也试过不直接将字符写入**空间,而是使用字符串复制功能:

    char i, temp[3];  
    ...
    while (j < n) {
        for (i = 0; (c = getchar()) != EOF && i < size; i++)
            temp[i] = c; 
        strncpy1 (space[j],temp,3);
        ++j;
    }
.....
void strncpy1 (char *s, char *t, int k)
{
    while (--k > 0) {
        *s = *t;
        s++;  t++;
    }
}

在复制函数内部,GDB 中的复制和递增显示正确。但在从'strncpy1'返回后,space[j] 从 0x804cfe0 变为 0x804000a 之类的东西。被调用函数怎么可能影响父母的(外部)指针?

那么最后,指针到字符指针是什么类型的?它有什么尺寸?

4

2 回答 2

1

我相信您的系统指针大小为 4,并且由于您使用的是指向指针的指针,然后将其递增,因此它将 4 字节添加到当前位置以到达其类型的下一个指针(char**)。

注意:您不是在增加指向 char 的指针,而是在增加指向指针的指针。

现在,如果我再次谈论您的第二个问题,即函数如何知道在哪里增加 4 和在哪里增加 7,因此它与函数无关。因为指针数组确实保存在连续位置的指针地址(它们不是指针的值,我说的是保存在指针数组中的指针),所以它只会将该指针递增一并到达下一个指针其类型的天气它在 P[0] 或 P[4] 或 p[7]..

于 2015-05-08T04:51:11.257 回答
1

您遇到的最大问题是指针和数据使用相同的内存位置。这就是为什么您会看到这种奇怪的行为。

您只分配一个缓冲区,然后使用此缓冲区来包含指向同一缓冲区的指针。当然,当您随后修改内容时,您的指针会发生变化。您必须有单独的内存位置:一个用于数据,另一个用于指向该数据的指针。

如果你真的想这样做,你可以这样做:

void **calloc1(int n, int size)
{
    int i, j;
    char *tmp, **p = NULL;
    tmp = (char *) malloc1(n * size);
    p = (char**) malloc1(n * sizeof(char*));
...

注意:这样,您自然需要两次调用来释放内存,并且您可能无法知道第二次调用是什么,因为用户可以更改指针。因此,更好的办法是将分配合并为一个:

void **calloc1(int n, int size)
{
    int i, j;
    char *tmp, **p = NULL;
    p = (char**) malloc1(n * size + n * sizeof(char*));
    tmp = (char *) (p + n);
...

这样,p 指向一个分配,但指针将具有与实际项目分开的内存。

至于其他问题:

1)'main()'如何知道指针算术的大小?

指针始终具有固定大小。他们是指针,他们不关心他们指向什么。sizeof(char*) == sizeof(int*) == sizeof(yourcoolstruct*)

2)当我在这里增加“空格”时,它移动的不是3而是4个字符(在第一个'++'之后它是0x804cfe4,在第二个0x804cfe8之后)。为什么?与“浮动”型尺寸有什么联系吗?

因为在您的系统中 sizeof(pointer) == 4,所以每个指针占用 4 个字节。在 32 位环境中正常,与浮点数、整数或任何东西无关。

3) 当这个循环在 j == 2 的情况下运行时,'space[0]' 的值以某种方式从 0x804cfe2(移动了两次 - ok)变为 0x6a04cfe2(超出范围)。什么。。???

因为您为指针和数据使用相同的内存。您将'j'(十六进制的0x6A)写入空间[1][0],它指向分配的第四个字节。这也是 space[0] 指针的最高有效字节,所以它变成了那个。

于 2015-05-08T04:57:24.600 回答