C语言之指针

指针的定义

指针,是C语言中的一个重要概念及其特点,也是掌握C语言比较困难的部分。指针也就是内存地址,指针变量是用来存放内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。
指针是一个占据存储空间的实体在这一段空间起始位置的相对距离值。在 C/C﹢﹢ 语言中,指针一般被认为是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组,函数等占据存储空间的实体

1、用代码简单的解释a, &a, *p, p之间的关系

    int a = 200;
    int b = 300;
    int *p = &a;
    //也就是说,定义指针变量时必须带*,给指针变量赋值时不能带*
    p = &b;
    //int *p = &a;
    //*p = 100;
    //第1行代码中*用来指明 p 是一个指针变量,第2行代码中*用来获取指针指向的数据

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

运行结果:    
a = 200
&a = 000000000061FE14
p = 000000000061FE10
*p = 300

2、关于 * 和 & 的谜题

假设有一个 int 类型的变量 a,pa 是指向它的指针,那么*&a和&*pa分别是什么意思呢?

&a可以理解为(&a),&a表示取变量 a 的地址(等价于 pa),*(&a)表示取这个地址上的数据(等价于 pa),绕来绕去,又回到了原点,&a仍然等价于 a。

&*pa可以理解为&(*pa),*pa表示取得 pa 指向的数据(等价于 a),&(*pa)表示数据的地址(等价于 &a),所以&*pa等价于 pa

附详细介绍指针的链接:http://c.biancheng.net/view/1991.html

二、学习的代码

1、指针

    //指针
    char a = 'F';
    int f = 123;

    char *pa = &a;
    int *pb = &f;

    printf("a = %c\n", *pa);
    printf("b = %d\n", *pb);

    *pa = 'C';
    *pb += 1;
    printf("now, a = %c\n", *pa);
    printf("now, b = %d\n", *pb);

    printf("sizeof pa = %d\n", sizeof(pa));
    printf("sizeof pb = %d\n", sizeof(pb));

    printf("The addr of a is pa = %p\n", pa);
    printf("The addr of a is pb = %p\n", pb);

    //避免访问未初始化的指针 例如:int *a;

2、指针和数组

    //指针和数组
    int a;
    int *p = &a;

    printf("请输入一个整数:");
    scanf("%d", &a);
    printf("a = %d\n", a);

    printf("请重新输入一个整数:");
    scanf("%d", p);
    printf("a = %d\n", a);
    char str[128];

    printf("请输入你的域名:");
    scanf("%s", str);
    printf("你的域名是:%s", str);

    //数组名其实是数组第一个元素的地址
    printf("str 的地址是:%p\n", str);
    printf("str 的地址是:%p\n", &str[0]);

    //指向数组的指针
    char a[] = "fishs";
    char *p = a;
    //*(p+1)并不是对地址加1,
    printf("*p = %c, *(p+1) = %c, *(p+2) = %c", *p, *(p+1), *(p+2));


    char *str = "I love fish";
    int i, length;

    length = strlen(str);

    for(i = 0; i < length; i++)
    {
        printf("%c", str[i]);
    }
    printf("\n");


    char str[] = "I love fish";
    char *target = str;
    int count = 0;

    printf("");
    //自增运算符(++,--)的运算级别高于*
    //左值是地址且可以改变,数组地址不可以改变,所以他不是左值,右值是操作数据可以改变
    while(*target++ != '\0')
    {
        count++;
    }

    printf("总共有%d个字符", count);



    //指针和数组的区别

    //指针数组 int *p1[5];  因为[]运算符级别大于*,所以先看括号内的
    //结论:指针数组是一个数组,每个数组元素存放一个指针变量
    //
    int a = 1;
    int b = 2;
    int c = 3;
    int d = 4;
    int e = 5;
    int *p[5] = { &a, &b, &c, &d, &e };
    int i;
    for(i = 0; i < 5; i++)
    {
        printf("%d\n", *p[i]);
    }


    //数组指针(*p)[5]  数组指针是一个指针,它指向的是一个数组

    int temp[5] = {1, 2, 3, 4, 5 };
    int (*p2)[5] = &temp;
    int i;
    for(i = 0; i < 5; i++)
    {
        printf("%d\n", *(*p2 + i));
    }





    //指针与二维数组的关系
    //*(array+i) == array[i]


    int array[4][5] = {0};
    int i, j, k = 0;
    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 5; j++)
        {
            array[i][j] = k++;
        }

    }

    printf("*(array+1):%p\n", *(array + 1));
    printf("array[1]:%p\n", array[1]);
    printf("&array[1][0]:%p\n", &array[1][0]);
    //**(array+1)为地址,对地址进行引用**(array+1)则为值
    //array[1][0]
    printf("**(array+1):%d\n", **(array+1));
    //array[1][3]
    printf("*(*(array+1)+3):%d\n", *(*(array+1)+3));

    //数组指针和二维数组
    int array[2][3] = {{0, 1, 2}, {3, 4, 5}};
    int (*p)[3] = array;

    printf("**(p+1): %d\n", **(p+1));
    printf("**(array+1): %d\n", **(array+1));
    printf
    printf("array[1][0]: %d\n", array[1][0]);



     int num  = 1024;
     int *pi = &num;
     char *ps = "Fish";
     void *pv;

     pv = pi;
     printf("pi: %p, pv: %p\n", pi, pv);
     printf("pv: %d\n", *(int *)pv);


     pv = ps;
     printf("ps: %p, pv: %p\n", ps, pv);
     printf("pv: %s\n", (char *)pv);


    int *p1;
    int *p2 = NULL;

    printf("%d\n", *p1);
    printf("%d\n", p2);
    printf("\n");
    printf("============\n");


    int * ptr_socr = NULL;
    int * ptr_socr2 =NULL;
    int a = 5;
    printf("a====:%p", &a);
    printf("p====:%p", &ptr_socr);


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


    char *cBooks[] = {
            "《c语言程序设计》",
            "《c专家编程》",
            "《c和指针》",
            "《c陷阱和缺陷》",
            "《c primer plus》",
            "《带你学c带你飞》"
            };

    char **byFishC;
    char **myLoves[4];

    byFishC = &cBooks[5];
    myLoves[0] = &cBooks[0];
    myLoves[1] = &cBooks[1];
    myLoves[2] = &cBooks[2];
    myLoves[3] = &cBooks[3];
    printf("FishC出版的图书有:%s\n", *byFishC);
    printf("我喜欢的图书有:\n");
    for(int i = 0; i < 4; i++)
    {
        printf("%s\n", *myLoves[i]);
    }

3、常量和指针

    //常量和指针
    int num = 520;
    const int cnum = 880;
    const int * pc = &cnum;

    printf("cnum: %d, &cnum: %p\n", cnum, &cnum);
    printf("*pc: %d, pc: %p\n", *pc, pc);

    //cnum: 880, &cnum: 000000000061FE0C
    //*pc: 880, pc: 000000000061FE0C


    pc = &num;

    printf("num: %d, &num: %p\n", num, &num);
    printf("*pc: %d, pc: %p\n", *pc, pc);


    //*pc = 1024;  //error: assignment of read-only location '*pc'

    //总结:
    //指针可以修改为指向不同的常量
    //指针可以修改为指向不同的变量
    //可以通过解引用来读取指针指向的数据
    //不可以通过解引用来修改指针指向的数据




    int num = 200;
    const int cnum = 880;
    const int * const p = &num;
    //指向常量的常量指针
    const int * const *pp = &p;


    //*p = 1024;  //error: assignment of read-only location '*p'
    //printf("*p: %d\n", *p);

    //p = &cnum;  //error: assignment of read-only variable 'p'
    //printf("*p: %d\n", *p);

    printf("pp: %p, &p: %p\n", pp, &p);
    printf("*pp: %p, p: %p, &num: %p \n", *pp, p, &num);
    printf("**pp: %d, *p: %d, num: %d \n", **pp, *p, num);


4、函数与指针

#include <stdio.h>
#include <math.h>
#include <string.h>



char * getWord(char);
int square(int num);
char * getWord(char c)
{
    switch(c)
    {
        case 'A' : return "Apple";
        case 'B' : return "Banana";
        case 'C' : return "Cat";
        default : return "None";
    }
}

int square(int num)
{
    return num * num;
}


//函数指针做参数
int add(int, int);
int sub(int, int);
int calc(int (*fp)(int, int), int, int);
int (* select(char))(int, int);

int add(int num1, int num2)
{
    return num1 + num2;
}
int sub(int num1, int num2)
{
    return num1 - num2;
}
int calc(int (*fp)(int, int), int num1, int num2)
{
    return (*fp)(num1, num2);
}

//括号为第一优先级阶梯,然后是取值,运算方向是从左到右,故我们从(* select(char op))开始,
//再继续由运算符的优先级可以看出select为函数名(char op)为参数类型,则返回值为一个指针,
//然后我们把已知的去掉发现(*)(int, int), 这不就是函数指针呀
//返回整型并且是由两个参数的函数指针
int (* select(char op))(int num1, int num2)
{
    switch(op)
    {
        case '+' : return add;
        case '-' : return sub;
    }
}




int main()
{

/*
    //指针函数:int *sum();
    //函数指针:int (*sum)();


    //指针函数
    char input;

    printf("请输入一个字母:");
    scanf("%c", &input);
    printf("%s", getWord(input));
    //我解释一下吧,getword返回值是一个指针,指针指向字符串第一个字符就可以是指向整个字符串。
    //他在这里输入第一个字符,然而是指针,指针指向的字符串第一个字符,所以输出字符串。

    //不要返回局部变量的指针

    //函数指针
    int num;
    int (*fp)(int);
    printf("请输入一个整数:");
    scanf("%d", &num);
    fp = square;
    //或者写成fp = &square; 因为我们知道函数名相当于函数的地址,so我们这里就直接写成 fp = square;
    printf("%d * %d = %d", num, num, (*fp)(num));


    //函数指针做参数

    printf("3 + 5 = %d\n", calc(add, 3, 5));
    printf("3 - 5 = %d\n", calc(sub, 3, 5));

 */

    //
    int num1, num2;
    char op;
    int (*fp)(int, int);
    printf("请输入一个式子:(例如1+3)");
    scanf("%d%c%d", &num1, &op, &num2);
    fp = select(op);
    printf("%d %c %d = %d\n", num1, op, num2, calc(fp, num1, num2));

    return 0;
}


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.史

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值