指针指针地址&算术

时间:2015-05-08 04:24:55

标签: c pointer-to-pointer

程序员!

我完全沉没了双指针(指向指针)......这里有很多问题!

让我们从这个任务开始:我正在编写我的自定义版本的'calloc'func,它必须返回指向'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 *个大小的字节,然后“分配”相同“大小”的指针数组到相应的起始位置。 让我们输入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()'如何知道如果我向'space'添加'1'(或者只是递增一次),它应该指向它的第二个指针(在'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 ...我不认为它是正确的。

我尝试过另一种方式 - 引用'space',不是指针而是数组:

....
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(超出界限)。什么h .. ???

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。被调用的函数如何能够影响父母的(外部)指针?

最后,什么类型的指针指向char指针?它有多大?

2 个答案:

答案 0 :(得分:1)

我相信你的指针系统大小是4,因为你正在使用一个指向指针的指针,然后将它包含在内,所以它将4个字节添加到当前位置以到达其类型的下一个指针(char **)。

注意:您没有将指针递增到char,而是将指针递增到指针。

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

答案 1 :(得分: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)怎样才能#(主)()&#39;知道指针算术的大小吗?

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

  

2)当我增加&#39;空间&#39;在这里,它不是移动3而是移动4个字符(在第一个&#39; ++&#39;它是0x804cfe4,在第二个0x804cfe8之后)。为什么?是否与“&#39; -type size”有某种联系?

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

  

3)当此循环以j == 2运行时,空间[0]&#39;的值为某种程度上从0x804cfe2(移动两次 - 确定)变为类似0x6a04cfe2(超出界限)。什么h .. ???

因为对指针和数据使用相同的内存。你写的是&#39; j&#39; (0x6A,十六进制)到空间[1] [0],它指向分配的第四个字节。哪个也是space [0]指针的最重要的字节,所以它就变成了。