C语言 【初始指针】【指针一】

打印 上一主题 下一主题

主题 1374|帖子 1374|积分 4122

引言

        思绪好久,照旧决定写一写指针,指针这块内容很多,也不是那么容易说清楚,这里尽大概写地详细,让各人理解指针。(未完序)
一、内存和地点

           在讲指针前,需要有一个对内存和地点的认识,不然后面的指针不是那么容易理解。在我们的内存中:一个字节里存储着 0 或 1 的信息。那计算机是怎么快速找到对应的信息的呢?
          回复:在内存中每个字节都有自己对应的地点,计算机通过找到地点,就能访问地点里面的信息。
          那么指针,就是一种可以存储地点的数据范例。
  二、一级指针

1.存地点: 

         重点:其实指针是很简单的,只要会使用int ,float, double,long long 等数据范例,那么指针变量,你也一定会使用。
            先介绍一下指针变量是怎么创建的:
          在对应数据范例的后面加上*,就可以存储该范例的内存地点。
  认识个东西 : & 取地点操作符,看下面的代码:
  1.         int b = 10;
  2.         int* a = &b;
复制代码
        这段代码创建了一个变量b,&b,就可以取出b的地点。
int* 就是int范例的指针变量,a 里面存的就是  b 的地点

  通过调试来看一下:
 


可以看到 b 的地点 
下面通过监视窗口,看一下a里面存的是什么:

发现就是b的地点。
   雷同地,假如要存float数据范例的地点,就要创建float范例的指针变量:
  1.         float c = 1.2;
  2.         float* d = &c;
复制代码
d中存储的就是 c 的地点。
  其他的数据范例一样,包括自界说范例的数据。
  可以自己多试试。
  2.解读地点对应的内容: 

   要用到一个东西:解引用操作符:*
  使用起来也特别简单:
  比如上面代码中,a中存储的是b的地点,*a,就可以找到b对应位置的内容了
  来看代码: 
  1. #include<stdio.h>int main(){        int b = 10;
  2.         int* a = &b;        int c = *a;  //*a 等价于 b        printf("%d\n", c);        *a = 20;   //改变a地点里面的内容,就是把b的内容给改了        printf("%d\n", b);        return 0;}
复制代码
运行效果:

            是不是特别简单,认为指针难,是因为你不理解每个符号的内容,这里给拆开来讲,相信你一定明确了
  3.指针变量的大小

   int在内存中占4个字节,float在内存中占4个字节,double在内存中占8个字节,和int,float,double等范例一样,指针范例在内存中也是占有字节的。
          那指针范例在内存中占多少个字节呢?
  先给出结论,下面来看代码证明。
  • 32位平台下地点是32个bit位,指针变量大小是4个字节
  • 64位平台下地点是64个bit位,指针变量大小是8个字节
  • 注意指针变量的大小和范例是无关的,只要指针范例的变量,在相同的平台下,大小都是相同的。(和CPU里面的线路有一定的关系)
  sizeof操作符同样可以返回指针范例在内存中占多少个字节。 
  1. #include<stdio.h>
  2. int main()
  3. {
  4.         printf("%zd\n", sizeof(char*));
  5.         printf("%zd\n", sizeof(short*));
  6.         printf("%zd\n", sizeof(int*));
  7.         printf("%zd\n", sizeof(double*));
  8.         return 0;
  9. }
复制代码
 在差别平台下运行这段代码:
在32位平台下:

运行效果: 

在64位平台下: 
 运行效果:

 三、指针变量范例的意义

   你是不是会有这么个疑问:
          指针变量的大小和范例无关,只要是指针变量,在同一个平台下,大小都是一样的,为什么还要有各种各样的指针范例呢?
  其实指针范例是有特别意义的,通过两中方法来理解一下。
1.指针的解引用

   下面看两段代码: 
  1. //代码1
  2. #include <stdio.h>
  3. int main()
  4. {
  5.         int n = 0x11223344;
  6.         int* pi = &n;
  7.         *pi = 0;
  8.         return 0;
  9. }
复制代码
  1. //代码2
  2. #include <stdio.h>
  3. int main()
  4. {
  5.                 int n = 0x11223344;
  6.                 char* pc = (char*)&n;
  7.                 *pc = 0;
  8.                 return 0;
  9. }
复制代码
代码二中给int*范例,逼迫转换成了char*范例。末了都解引用后赋值0
  通过调试,来看一下两段代码在内存中的存储。
  
  代码一:


代码二:

        相信聪明的你一定发现了差别,代码1会将n的4个字节全部改为0,但是代码2只是将n的第一个字节改为0。
    得出结论:指针的范例决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)。 比如: char* 的指针解引用就只能访问⼀个字节,而 int* 的指针的解引用就能访问四个字节。 
   2.指针+ -整数

有了上面的结论,这个就很容易理解了
来看代码:
  1. #include <stdio.h>
  2. int main()
  3. {
  4.         int n = 10;
  5.         char* pc = (char*)&n;
  6.         int* pi = &n;
  7.         printf("%p\n", &n);
  8.         printf("%p\n", pc);
  9.         printf("%p\n", pc + 1);
  10.         printf("%p\n", pi);
  11.         printf("%p\n", pi + 1);
  12.         return  0;
  13. }
复制代码
来看运行效果: 

           char* 范例的指针变量+1跳过1个字节, int* 范例的指针变量+1跳过了4个字节。 这就是指针变量的范例差异带来的厘革。指针+1,其实跳过1个指针指向的元素。指针可以+1,也可以-1。 
  结论:指针的范例决定了指针向前或者向后走一步有多大(间隔)。
  四、void* 指针 

           在指针范例中有⼀种特别的范例是 void * 范例的,可以理解为无详细范例的指针(或者叫泛型指针),这种范例的指针可以用来担当任意范例地点。但是也有范围性, void* 范例的指针不能直接进行指针的+-整数息争引用的运算。
   来看代码:
  1. #include <stdio.h>
  2. int main()
  3. {
  4.         int a = 10;
  5.         int* pa = &a;
  6.         char* pc = &a;
  7.         return 0;
  8. }
复制代码
这段代码在编译的时候肯定是会报警告的。(因为范例不兼容)
  1. #include <stdio.h>
  2. int main()
  3. {
  4.         int a = 10;
  5.         void* pa = &a;
  6.         void* pc = &a;
  7.         //*pa = 10; 这样写是错误的
  8.         //*pc = 0;
  9.         return 0;
  10. }
复制代码
void* 范例的指针可以接收差别范例的地点,但是无法直接进行指针运算。
           一般 void* 范例的指针是使用在函数参数的部门,用来接收差别范例数据的地点,这样的设计可以实现泛型编程的效果。
  五、指针运算 

1.指针+-整数

        上面的一个代码已经可以看出这个功能了,这里再通过一个案例来理解一下(也算是一个小的练习)
        

通过地点来访问一个数组。
  1. #include<stdio.h>
  2. int main()
  3. {
  4.         int arr[10] = { 1, 2, 3, 4, 5, 6, 7,  8, 9, 10 };
  5.         int* p = &arr[0]; //取出首元素的地址
  6.         int i = 0;
  7.         int sz = sizeof(arr)/sizeof(arr[0]);
  8.         for (int i = 0; i < sz; i++)
  9.         {
  10.                 printf("%d ", *(p + i));
  11.         }
  12.         return 0;
  13. }
复制代码
运行效果:

    从这个案例中可以看出:*(p + i) 等价于 p。(其实就是这样)
  这也可以说明数组名是就是数组首元素的地点。
  不过有来个特例需要记一下:
  1. &arr,对数组名取地点,得到的是整个数组的地点,而不是首元素的地点。
  2. sizeof(arr),这里面的arr也是整个数组的地点,而不是首元素的地点。
  把上面代码改一下来证明一下:
  1. #include<stdio.h>
  2. int main()
  3. {
  4.         int arr[10] = { 1, 2, 3, 4, 5, 6, 7,  8, 9, 10 };
  5.         int* p = &arr[0]; //取出首元素的地址
  6.         int i = 0;
  7.         int sz = sizeof(arr)/sizeof(arr[0]);
  8.         for (int i = 0; i < sz; i++)
  9.         {
  10.                 //printf("%d ", *(p + i));
  11.                 printf("%d ", p[i]);
  12.         }
  13.         return 0;
  14. }
复制代码
只改了一个地方,就是输出位置。
运行效果:

是不是又增加了新知识,嘿嘿(●ˇ∀ˇ●) 
 2.指针-指针

           后面位置的指针减前面位置的指针,可以计算出两个指针之间字节个数。
  来看参考代码:
  1. #include <stdio.h>
  2. int my_strlen(char* s)
  3. {
  4.         char* p = s;
  5.         while (*p != '\0')
  6.                 p++;
  7.         return p - s;
  8. }
  9. int main()
  10. {
  11.         printf("%d\n", my_strlen("abc"));
  12.         return 0;
  13. }
复制代码
运行效果: 

3.指针的关系运算

   指针之间也是可以比较大小的
  来看代码:
  1. #include <stdio.h>
  2. int main()
  3. {
  4.         int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  5.         int* p = &arr[0];
  6.         int sz = sizeof(arr) / sizeof(arr[0]);
  7.         while (p < arr + sz) //指针的⼤⼩⽐较
  8.         {
  9.          printf("%d ", *p);
  10.          p++;
  11.         }
  12.         return 0;
  13. }
复制代码
运行效果: 

是不是又被震动到了,哇呜,竟然还可以这么写。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

李优秀

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表