指针的指针(二)

实例

这里接上一章指针的指针(一)

这里有几个例子程序,用于说明指针表达式的一些常用用法。我们先看下面这张图片,text是一个char类型的二维数组,而cp是指向这个二维数组的一个指针数组,strings是指向cp地址的指针

 

 接下来,我们看一下下面这段代码,我们要在text这个二维数组中查找一个字符,查找方法实现在find_char这个函数中

#include <stdio.h>
#include <assert.h>
#define TRUE 1
#define FALSE 0

int find_char(char **strings, int value)
{
    assert(strings != NULL); //<8>
    while (*strings != NULL) //<9>
    {
        while (**strings != '\0') //<10>
        {
            if (*(*strings)++ == value) //<11>
            {
                return TRUE;
            }
        }
        strings++; //<12>
    }
    return FALSE;
}

int main(int argc, char const *argv[])
{
    char text[6][10] = {"spring", "struts", "hibernate", "flask", "numpy", "sklearn"}; //<1>
    char *cp[6];                                                                       //<2>
    int i = 0;
    for (; i < 6; i++)
    {
        cp[i] = text[i]; //<3>
    }
    char **strings = &cp[0]; //<4>
    char *before = cp[0];    //<5>
    printf("before find_char:\n");
    for (i = 0; i < 6; i++)
    {
        printf("cp[%d] = %p\n", i, cp[i]); //<6>
    }
    int res = find_char(strings, 'g'); //<7>
    printf("res = %d\n", res);
    printf("after find_char:\n");
    for (i = 0; i < 6; i++)
    {
        printf("cp[%d] = %p\n", i, cp[i]); //<13>
    }
    char *after = cp[0];                                                             //<14>
    printf("before = %p\nafter = %p\ndiff = %d\n", before, after, (after - before)); //<15>
    return 0;
}

        

现在我们来分析一下上面的程序,下面的标号与程序注释中的标号一一对应

  1. 我们先声明一个名称为text的二维数组,这个数组里有6个字符串,每一个字符串都是字符数组
  2. 声明一个名为cp的指针数组
  3. 将指针数组中的每个元素,指向text每个字符串的起始地址
  4. 声明一个指向指针的指针strings,用指针数组cp的起始位置(即&cp[0])来初始化
  5. 这里声明一个指针before,保存cp[0]最开始指向的位置
  6. 打印指针数组每个元素指向的位置
  7. 传入指向指针的指针stings,和我们要查找的字符'g'
  8. 这里,我们进入到find_char()函数中,检查传入指向指针的指针是否为NULL,
  9. 如果strings保存的值不为空,则进入循环
  10. 简单分析一下**strings,从右到左,strings保存的是一个指针数组的初始位置,所以*strings首先间接访问到cp指针数组的第一个值,这里是一个地址,**strings则是再次对cp数组第一个元素所保存的地址进行间接访问,访问到text第一个字符串的第一个元素,为一个字符,这里判断当前字符是否为'\0',如果是则代表到了字符串的末尾了。如果**strings当前的指向的字符不为'\0',则进入循环
  11. *(*strings)++是一个很有趣的表达式,我们来分析一下,首先是*strings参与运算,strings指向的是cp第一个元素的地址,所以*strings则是指向cp第一个元素的值,然后再进行++运算,这里先返回一个*string的值的拷贝,再对*strings指向的那个值+1,即在cp第一个元素所保存的值+1,这时候cp已经指向text下一个字符串的起始地址,而前一个*拿着之前(*string)++的运算结果,这里还是指向text的第一个地址,然后用*进行间接访问,获取该地址的值,比较是不是要查找的value元素。(*string)++会一直循环,即cp第一个元素指向的地址不断往后,一直到*(*strings)++指向一个'\0',代表当前的字符串(即数组)结束
  12. string++则是将string当前保存的地址指向后一个地址
  13. 执行完find_char()函数后,我们打印cp指针数组中每一个元素的值,如果不出意料,cp元素第一个值已经和执行find_char()之前不一样了
  14. 初始化一个指针after,将cp指针第一个元素的值赋给它,用于和之前的before比较
  15. 打印before、after的值,并计算指针之间的距离

下面,我们运行一下代码看一下效果:

# gcc main.c -o main
# ./main 
before find_char:
cp[0] = 0x7fffadcd5250
cp[1] = 0x7fffadcd525a
cp[2] = 0x7fffadcd5264
cp[3] = 0x7fffadcd526e
cp[4] = 0x7fffadcd5278
cp[5] = 0x7fffadcd5282
res = 1
after find_char:
cp[0] = 0x7fffadcd5256
cp[1] = 0x7fffadcd525a
cp[2] = 0x7fffadcd5264
cp[3] = 0x7fffadcd526e
cp[4] = 0x7fffadcd5278
cp[5] = 0x7fffadcd5282
before = 0x7fffadcd5250
after = 0x7fffadcd5256
diff = 6

  

确实如我们之前所分析,cp[0]这个元素所保存的值在find_char()执行之前和执行之后有所变化。

上面的程序确实可以在一个二维数组中查找一个字符,但它并不完美,因为主方法main()中的cp变量的值改变了,如果cp这个值在后续还要用到的话,那我们又要重新声明一个指针数组或者复用cp指针数组,将text中每个字符串的地址挨个挨个赋值过去,有没有办法在查找的时候不改变cp变量的值呢?肯定是有的,下面让我们看另外一个find_char()方法,这里省略了main主函数

int find_char(char **strings, char value)
{
    char *string;                         //<1>
    while ((string = *strings++) != NULL) //<2>
    {
        while (*string != '\0') //<3>
        {
            if (*string++ == value) //<4>
            {
                return TRUE;
            }
        }
    }

    return FALSE;
}

  

  1. 先声明一个指针string
  2. *strings++这个表达式,首先string++先返回一个strings保存的值的一份拷贝,然后对strings所保存的值+1,指向下一个内存地址,然后再用*进行之前strings所指向的地址间接访问,这里仍然访问的是ch的第一个元素,尽管这时候strings已经指向ch的的第二个元素了
  3. 通过上一个步骤,string的值为ch指针数组中的一个元素,即为地址,再用*进行间接访问,访问到text中的元素的第一个字符,判断不为'\0'则代表字符串还未结束
  4. *string++首先是返回string所保存的值的一份拷贝,再对string+1,将string的值指向原先的下一个地址,然后*拿着原先的拷贝进行间接访问,一直循环到找到想要的字符为止

这里,我们将现在的find_char()函数替换上一个find_char()函数,再看看运行结果

# gcc main.c -o main
# ./main 
before find_char:
cp[0] = 0x7ffd0e28f970
cp[1] = 0x7ffd0e28f97a
cp[2] = 0x7ffd0e28f984
cp[3] = 0x7ffd0e28f98e
cp[4] = 0x7ffd0e28f998
cp[5] = 0x7ffd0e28f9a2
res = 1
after find_char:
cp[0] = 0x7ffd0e28f970
cp[1] = 0x7ffd0e28f97a
cp[2] = 0x7ffd0e28f984
cp[3] = 0x7ffd0e28f98e
cp[4] = 0x7ffd0e28f998
cp[5] = 0x7ffd0e28f9a2
before = 0x7ffd0e28f970
after = 0x7ffd0e28f970
diff = 0

  

这里我们可以看到,执行find_char()函数后,没有再改变ch变量的值

 

posted @ 2018-07-14 06:15  北洛  阅读(241)  评论(0编辑  收藏  举报