C语言【指针1】

  金牌会员 | 2024-1-6 15:10:42 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 882|帖子 882|积分 2646

C语言【指针1】

1、指针类型长度随操作系统,64位操作系统为8Byte。

​        具体说一下:地址相当于门牌号,一般一个地址指向的空间是一个字节(下面按一个字节叙述,计算机底层也许也有按双字节编码的)。对于64位机器,某一个地址有64位,所以在空间里存那某一个地址时,这64位即8Byte。这64位总共能表示的数量(即寻址数量)为2^64,十六进制0x0000000000000000到0xffffffffffffffff,这个数很大很大,以现在的内存空间来看,如果一个地址指向的空间是1Byte,根本用不完。
2、 %p为输出指针的占位符;&为取址运算符;*为取值运算符(即取地址对应的数据)。

3、指针一些基础知识,以代码为例。
  1. int a = 100;
  2. /**        
  3. *        下面的代码是声明并初始化。
  4. *        之后想要改变指针指向,要修改p而不是*p(这里声明并初始化时用*p是指明定义的是一个指针)。
  5. *        之后想要改变变量a的值,修改*p即可。
  6. */
  7. int* p = &a;       
  8. *p = 200;        // 修改*p时,a也会跟着改变
  9. printf("%p\n", &a);        //        输出a的地址
  10. printf("%p\n", p);        //        输出a的地址
  11. printf("%d\n", a);        //        输出a的值
  12. printf("%d\n", *p);        //        输出a的值
  13. printf("%p\n", &p);        //        输出p的地址。p本身也有地址指向它,它也是个空间,空间里存的地址。
复制代码
​        指针就是个变量,存的别的数据地址,如果存自己的地址,那没啥意义。
​        指针就是个变量,它是p而不是* p。* p是那个数据,参考上面代码。
​        数组名、函数名等就是地址本身(或者说是表示数组或函数首地址的常量),所以,可以通过数组名给指针的方式使指针指向数组,反之不行,数组名和函数名不可更改。
  1. /**
  2. *        如果把指针赋给普通整型变量,可以。但如果想像*指针一样给这个变量加 * ,就不行了。
  3. */
  4. int a = 100;
  5. int * p = &a;
  6. long long la = p;
  7. *la;        // 会报错。
复制代码
  1. /**
  2. * 不同指针类型
  3. */
  4. int a = 100;
  5. int* p = &a;
  6. double * p1 = p;        // p1和p空间里的字节数一样,但去a那找的宽度不一样。* p1 去a那要找8Byte.
复制代码
  1. /**
  2. * 野指针问题
  3. */
  4. int * p;        // 一个野指针
  5. *p = 100;        // 如果p是在函数里定义的,直接修改随机指向里的值,不会报错,但可能使程序崩掉。
复制代码
​        指针的运算,即地址的运算,只不过指针可以接收运算的结果,而地址不行
​                1.指针(地址)只能和整数作加减运算(包括两地址相加减)。本质就是地址的运算,指针可以接收结果。
对于int类型的指针来说,p+=1即p往后(高位)移动了4个字节。其他类型同理。
​                2.同类型指针相减,得到一个ptrdiff_t类型的数据。其占位符为 %td 。
  1. int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  2. int *p1 = &arr[0];        // int * p1 = arr;
  3. int *p2 = &arr[3];        // int * p2 = arr+3;   
  4. p1[2];        // 等同arr[2] 指定数组后,指针可以这样使用
  5. p2[2];        // arr[5], 看第三行代码
  6. printf("%td\n", p1 - p2);        // -3  两地址相差3,(自动除过int的字节数)
复制代码
​                3.指针(地址)也可以作比较运算。栈先进后出,所以在函数中,一般先初始化的放在高地址,指针指向的时候可比较指向变量的地址大小。
4、指针和数组名的区别与共用。


  • 区别
    指针是变量,数组名是常量。
    sizeof(数组名) 返回为整个数组的字节数;当指针指向数组后,sizeof(指针) 返回仍然是跟随系统的字节数。
  • 相同。数组除了不能随意修改或指向外,基本可以当指针使用;当指针指向数组后,指针可以使用数组的所有方式操作数组。举个例子:
    1. int arr[20] = {10, 20, 30, ...};
    2. printf("%d\n", (arr+1)[0]);        // 20。 这里arr+1并没有修改arr的值。这个(arr+1)[0]可替换为*(arr+1).
    复制代码
5、指针数组。int  *p[10];     指针数组是一个大数组,里面存放的是一个个的指针。

​        * p[1] 和*(p[1])是一样的。表示第二个数组元素中指针指向的数值。
  1. int a = 10, b = 20;
  2. int *p[2] = {&a, &b};
  3. printf("%d %d\n", *p[0], *p[1]);        // 10 20
复制代码
6、数组指针。int (*p)[10];        数组指针是一个指针,里面存放了一个数组。[10]表示这个二维的p加一就跳10个长度。这里这个p是一个二维的指针。
  1. int (*p)[3];        // p+1即跳3个元素
  2. int arr[2][3] = {1, 2, 3, 4, 5, 6};
  3. p = arr;                // 这里是二维的,就不加&了
  4. printf("%d\n", (*(p+1))[0]);        // 跳三个加个*再取数组第一个元素
复制代码
补一个案例
  1. int a = 256;
  2. int* p = &a;  
  3. // int* p = &a + 1;  // 这里+1的话也是加了4返回给p
  4. long long p1 = p;        // 这里就是为了下面可以加真实的数,而不是加定义类型的倍数
  5. p = p1+1;                        // 真正的+1 而不是+4
  6. *p = 10;
  7. printf("%d\n", a);        // 2560   凑巧10倍了
  8. printf("%d\n", *p);        // 10
  9. // 这个程序就是往左移了一个字节再改数,回到之前的变量输出混乱的值。
复制代码



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表