初谈指针(2)

初谈指针(2)

前言

上一篇(初探指针(1))从指针的概念开始入手,依次是:什么是指针>>指针传递>>多级指针>>指针函数。尽管指针远不于此,但寻常应付想来足够了。这一次想谈谈关于指针易混淆的地方。
倒不知是否翻译之故,一度出现了指针函数和函数指针,指针数组和数组指针,指针常量和常量指针,字符指针数组和二维字符数组……统统被我认为属于一个群体——不用就会忘记系列。其实抛开考试中会故意找茬,实际运用到都算不上太难。但这些术语名字嘛……想起我还小的时候,范冰冰李冰冰傻傻分不清。

指针与二维数组

首先我们需要理清指针与数组的关系:数组不等于指针,但在某些情况下二者等价

定义一个一维数组int a[i] = {...};,当我们使用a[i]的时候,实际上编译器做了转换处理,变成了*(a+i)

一维数组是方便理解的,那么二维数组呢?
a[i][j]*(*(a+i)+j)具有等价效果,对后者分析如下:

  1. a表示二维数组中第一行的地址,a+i则表示第i+1行的地址
  2. *(a+i)表示第i+1行的列地址(这个列为第一列),*(a+i)+j则表示第i+1行、第j+1列的地址
  3. *(*(a+i)+j)表示取出这个地址上的数据

有了这个铺垫,我们就可以愉快的开始下面的旅程了。

指针函数

前面说到在指针函数中,return的时候注意不要是局部变量的地址,这句话本身是有瑕疵的。但如果就这样做了,保准儿程序不会出错。但是等一等,我们需要这般畏首畏尾吗?

与“猥(畏)琐(缩)”说不!
一般说来,存放在栈中的变量不可以被return地址。这是由于栈中的数据由系统产生,也由系统回收,很难说我们在return栈中的某个数据的地址时,系统是不是早一步把它干掉了。

但这几个数据是可以的:全局变量,静态变量,常量数据,堆中的数据。一个运行的程序里,这些数据并不存放在栈中,具体在哪里涉及到内存分配的问题,这里不做延伸了。

函数指针

函数指针的根本是指针,它能够指向一个函数。

扫描二维码关注公众号,回复: 3707170 查看本文章

定义:int (*p)(int, int);
表示p是一个能够指向函数的指针,并且它指向的函数是int类型,且这个函数有两个参数,这个两个参数都是int类型。

#include <stdio.h>


int add_xy(int x, int y)
{
    return x+y;
}

int main(int argc, char **agrv)
{
    int (*p)(int, int);
    p = &add_xy;

    int result = p(1, 2);
    printf("%d\n", result);

    return 0;
}

// 输出
>>3

举一反三:char *(*p)(int, char *) 表示p是一个指向函数的指针,这个函数有两个参数:一个int类型,一个char*类型(char*的指针),并且这个函数返回char *的指针

一定要区分: char *p(int, char *),当没有小括号把指针运算符和指针变量包起来的时候,表示指针函数的声明,函数的名字为p

指针数组

指针数组的根本是数组,即:一个数组里的成员都是指针

定义:int *p[];
按照优先级顺序,这里p[]是一个整体,所以可以看作:int * —> p[]

示例:

#include <stdio.h>

int main(int argc, char **agrv)
{
    int a=1, b=2, c=3;
    int *p[3] = {&a, &b, &c};  // 定义一个指针数组,并且初始化

    int i = 0;
    for(i=0;i<3;i++){
        printf("%d\n", *(*(p+i)));
        // printf("%d\n", *p[i]); 也可以这样写
    }

    return 0;
}

// 输出
>>1
>>2
>>3

数组指针

数组指针的根本是指针,即:一个指向数组的指针

定义:int (*p)[];
按照优先级顺序,*p是一个整体,所以可以看作int *p —> []

示例:

#include <stdio.h>

int main(int argc, char **argv)
{
    int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

    int (*p)[3] = a;  // 定义一个数组指针,并且初始化

    int i = 0, j = 0;
    int row = 3, col = 3;
    for(i=0; i<row; i++){
        for(j=0; j<col; j++){
            printf("%d ", *(*(p+i)+j));
            // printf("%d ", (*(p+i))[j]);  也可以这样写
        }
    }

    return 0;
}

// 输出
>>1 2 3 4 5 6 7 8 9

指针常量

指针常量表示:这个指针为“只读”(从始至终只能指向一个地址,可以通过指针运算符来修改所指向的地址上的数据,一定在定义的时候赋初值

定义:int *const p;
指针(*)常量(const),也就是说指针运算符在const的前面;const修饰的是p,所以p不能被赋值

#include <stdio.h>

int main(int argc, char **argv)
{
    int a = 1;
    int *const p = &a;  

    printf("%d\n", a);

    *p = 2;
    printf("%d\n", a);

    return 0;
}

// 输出
>>1
>>2

常量指针

常量指针表示:这个指针指向的地址上的数据为“只读”(该指针可以随意更改指向的地址,但不能通过取地址运算符来修改所指向的地址上的数据

定义:int const *p;
常量(const)指针(*),也就是说,const在指针运算符的前面;并且可以看做const 修饰的是*p,所以*p不能被赋值

示例:

#include <stdio.h>

int main(int argc, char **argv)
{
    int const *p = NULL;
    int a = 1, b = 2;

    p = &a;
    printf("%d\n", *p);

    p = &b;
    printf("%d\n", *p);

    return 0;
}

// 输出
>>1
>>2

字符指针数组和二维字符数组

字符指针数据,也就是一个数组,里边的成员都是char *的指针,即:char *str[] = {"...", "...", ...};
二维字符数组,一个二维数组,里边成员都是char类型的字符,即:char str[][n] = {"...", "...", ...};

#include <stdio.h>

int main(int argc, char **agrv)
{
    char *names[] = {"Tom", "Alice", "Bob"};

    int i = 0;
    for(i=0; i<3; i++){
        printf("%s ", *(names+i));
        // printf("%s ", names[i]);  也可以这样写
    }
    printf("\n");

    char hobbies[][10] = {"swimming", "sleeping", "reading"};
    for(i = 0; i<3; i++){
        printf("%s ", *(hobbies+i));
        // printf("%s ", hobbies[i]);  也可以这样写
    }
    printf("\n");

    return 0;
}

// 输出
>>Tom Alice Bob
>>swimming sleeping reading

在使用上,二者是没差的,但从内存上分析就存在区别。
字符指针数组中的成员都是一个char *的指针,也就是说,它们都是地址,真正的字符串存放在常量区;二维字符数组里边存放的都是一个个char类型的字符。建议使用前者,因为字符指针数组存储字符串要比二维字符数组开销小。

连连看

我记得有一个送命游戏叫做:韩国女星连连看。其实对我重度脸盲患者,岂止韩国女星,即便是现在的许多大陆女星,我也着实难分辨(其实现在的新兴男星我也基本分不清了)。好在能不能区分出明星还是其次,重要的是区分以下的表达式。如果能够轻易识别,指针也算入门了。

  • int *p[n];
  • int (*p)[n];
  • int (*p)(int, int);
  • int (*p[])(int, int);
  • int p(int, int);
  • int *p(int, int);
  • int const *p;
  • int *const p;
  • int const * const p;

猜你喜欢

转载自blog.csdn.net/qq_41359051/article/details/81291326