C语言 指针

每一个变量都有内存地址,而指针就是用来存储变量内存地址的。

通过指针给变量赋值

#include 

void main(){

    int i = 89;
    int* p = &i;
    *p = 23;
    printf("i = %d\n", i);
    getchar();
}

输出结果:

i = 23

上面的示例中,我们看到了通过给变量取地址来给指针赋值,那么指针与地址有什么区别?

指针有类型,地址没有类型

地址只是开始的位置,类型决定读取到什么位置结束,比如int类型指针,就从指针指向地字向后读取4个字节,得出变量值,下例:

#include 
void main(){
    int i = 89;
    //int 类型的指针
    int *p = &i;
    double j = 78.9;
    //赋值为double类型变量的地址
    p = &j;
    printf("double size:%d\n", sizeof(double));
    printf("%#x,%lf\n", p, *p);     

    getchar();
}

输出结果:

double size:8
0x1cfef0,0.000000

我们发现int 类型的指针,指向一个浮点类型的地址时,指针自身储存地址改变是没有问题的,但所指向的变量值读取出问题了,这是因为int 4个字节,double 8个字节,想通过4字节读取8字节变量的值,是不行的。

NULL 空指针

看下面部份代码示例:

void main(){
    int i = 9;
    int *p = NULL;
    printf("%#x\n",p);
    getchar();
}

输出结果为:

0

空指针的默认值为0,且所指向值系统不允许访问:

void main(){
    int i = 9;
    int *p = NULL;
    printf("%d\n", *p);
    getchar();
}

上面的代码,运行会出错,就是因为空指针的问题。

二级指针(多级指针)

我们知道指针存储的是变量的地址,但指针实际上也是一个变量,那么它必然也有一个在内存中的地址。而存储指针地址的指针,就是二级指针,以此嵌套下去,就形成了多级指针。

看下面一段代码:

void main(){
    int a = 50;
    //p1上保存的a的地址
    int* p1 = &a;
    
    //p2上保存的p1的地址
    int** p2 = &p1;

    //int*** p3 = &p2;

    printf("p1:%#x,p2:%#x\n",p1,p2);
    **p2 = 90;

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

    getchar();
}

输出结果:

p1:0x7afce8,p2:0x7afcdc
90

上面示例中p2就是一个二级指针,存储的是指针p1的地址,通过一元运算符*,就可以得到指针p1的值,p1的值是变量a的内存地址,所以再进行一个*运算就可以对变量a 进行赋值运算。

指针的运算

指针的运算一般只有在变量在内存中以线性排列方式的情况下才有意义,例如数组,它每一个元素的地址在内存中是连续的。

看下面一段代码:

void main(){
    //数组在内存中连续存储
    int ids[] = { 78, 90, 23, 65, 19 };
    //数组变量名:ids就是数组的首地址
    printf("%#x\n",ids);
    printf("%#x\n",&ids);
    printf("%#x\n",&ids[0]);
    //指针变量
    int *p = ids;
    printf("%d\n",*p);
    //指针的加法
    p++; //p++向前移动sizeof(数据类型)个字节
    printf("p的值:%#x\n", p);
    //p--;
    printf("%d\n", *p);
    getchar();
}

输出结果:

0x12ff868
0x12ff868
0x12ff868
78
p的值:0x12ff86c
90

我们发现,数组的地址与数组中首元素的地址是一样的。所以,我们可以通过指针运算,来对数组作循环。

先来看看一段对数组遍历赋值的作法:

void main(){

    int array[10];

    int i = 0;

    for (; i < 10; i++){
        array[i] = i;
    }
    //输出结果
    for ( i = 0; i < 10; i++){
        printf("i = %d\n",array[i]);
    }

    getchar();
}

输出结果:

i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9

再来看看,通过指针如何实现:

void main(){
    int array[10];
    int i = 0;
    int* p = array;
    for (; p < array+10; p++)
    {
        *p = i;
        i++;
    }
    //输出结果
    for ( i = 0; i < 10; i++){
        printf("i = %d\n",array[i]);
    }

    getchar();
}

输出结果:

i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9

函数指针

函数指针分为:函数返回值类型,函数指针的名称,函数的参数列表
函数指针的声明方式为:

returnType(*name)(type arg1,type arg2);

如下例:

int add(int a,int b){
    return a + b;
}

int minus(int a,int b){
    return a - b;
}

void main(){
    int(*math)(int, int) = add;
    printf("result = %d\n", math(1, 3));
    math = minus;
    printf("result = %d\n",math(5,2));
    getchar();
}

输出结果为:

result = 4
result = 3

上例中:

int(*math)(int, int) = add;

是简写,也可以写为:

int(*math)(int a, int b) = add;

综合实例:
用随机数生成一个数组,写一个函数查找最小的值,并返回最小数的地址,在主函数中打印出来。

#include 
#include 
#include 
#include 

int getMins(int array[],int len){
    int* p = array;
    int* min = p;
    p++;
    for (; p < array + len; p++)
    {
        if (*p < *min){
            min = p;
        }
    }
    return *min;
}

void main(){

    int nums[10];

    int i = 0;
    //初始化随机数发生器,设置种子,种子不一样,随机数才不一样
    //当前时间作为种子 有符号 int -xx - > +xx
    srand((unsigned)time(NULL));
    for (;  i< 10; i++)
    {
        //100范围内
        nums[i] = rand() % 100;
        printf("%d\n", nums[i]);

    }

    int(*funMin)(int[], int) = getMins;
    int result = funMin(nums, 10);
    printf("数组中最小数为:%d\n",result);
    getchar();

}

输出结果为:

91
75
9
13
78
93
88
25
22
29
数组中最小数为:9

你可能感兴趣的:(C语言 指针)