做网站找个人,外包公司软件开发可以去吗,无锡八匹马网站建设,网站投票链接怎么做#xff08;1#xff09;指针的概念
指针是一种数据类型#xff0c;而内存地址是这种数据类型具体的值#xff08;注意区分两者的概念#xff09;。先说一下什么是内存地址#xff1a;假设CPU的寻址方式是以字节寻址的#xff0c;即每一个字节对应一个地址编号#xf…1指针的概念
指针是一种数据类型而内存地址是这种数据类型具体的值注意区分两者的概念。先说一下什么是内存地址假设CPU的寻址方式是以字节寻址的即每一个字节对应一个地址编号则机器字长、存储字长和数据字长都是字节的整数倍所有的数据类型占据的空间大小都是字节的整数倍。对于32位操作系统地址码最长可达32位则可以寻址的最大数目为4G由于最小单位是字节因此可寻址的最大内存为4GB。64位操作系统则为B。因此在32位操作系统中地址指针值是一个32位的二进制数0~-1因此指针变量地址值在32位操作系统中占据的空间大小为4bytes32位由于地址值用32位二进制数表示不方便因此用8位16进制数表示0x00000000~0xFFFFFFFF。指针变量跟其余任何变量一样都是一个值且都要占据地址空间。指针是指本身的地址值与指针的地址不同两者不一定相等。指针计算机内一块内存来存放另一块内存的地址注意是首地址。所以对一个指针取地址无非就是对一块内存取地址跟对一个整数取地址对一个浮点数取地址对一个数组取地址对一个函数取地址没有任何区别char c[5]abc; // 内存c的地址是c void f(int size, float length); // 内存f的地址是f int *p a; // 内存p的地址是p 一般情况下字节占据1个字节int为4个字节指针跟操作系统位数相关。
int *p1 int **p2 int (*p3)[5]; int (**p4)[5]; int (*p5)[5][5]; p1~p5都是指针p1为一级指针p2为二重指针二级指针或指针的指针即p2所指的地址的内容依然是地址而该地址所指的地址的内容为int类型p3为指针其类型为int (*)[5]所指地址存储的内容为整型数组5个元素p4为二级指针其最终存储的内容为整型数组5个元素p5为指针其类型为int (*)[5][5]所指地址存储的内容为整型二维数组25个元素。
指针的步长。每个指针都是有步长的这与指针的计算有着密切关系。指针的步长就是指针地址所指的内容的大小占据的字节数。如 int *p则p的步长为4bytesp1则是p地址的基础上移动4个bytes。int (*p3)[5]; p3的步长就是20bytes。
*与[ ]对指针的作用。*(pi)是取出指针pi所指向的内容如*p1是取出的整形数值int*p3是取出的整个一维数组5个元素。int a[6][7] *a取出的是a[0]这个一维数组*(a1)取出的是a[1]这个一维数组*a[0]取出的是a[0][0]。*(pi)p[i]两者作用一样即p[i]则是指将指针p移动i个步长后所指向的内容。
二级指针步长分析二级指针的内存分布。例如int **p p是一个地址由于p地址的内容依然是地址因此p指针的步长为指针的字节数8个字节以32位为例。因此所有二级指针的步长都是一样的都是8bytes。而*p依然是指针即存储的内容为int数值因此*p的步长为4bytes。因此当用二级指针p来表示一个二维数组时其每一个元素int在内存中的分布并不向二维数组int a[i][j]那样都是连续的它们的分布不一样的。*p表示二维数组中的每一个元素a[i]一维数组的首地址而p则是将所有*p作为一维数组的首地址。因此在用指针p表示二维数组时只有二维数组中的每一个元素一位数组内部分布是连续的至于元素与元素之间的分布不一定是连续的取决于*p与*(p1)的值。综上二级指针p与二维数组a之间不能相互传递参数因为它们在内存中的分布是不一样的否则会引发段错误SIGSEGV。如果pa则p的步长为8bytes则*p或p[0]就会把数组a的前两个元素a[0][0]和a[0][1]合并在一起8个字节当成一个地址紧接着*(*p)或p[0][0]就是前一个地址所指向的前4个bytes的内容但是*p这个地址是用户未定义的因此属于非法访问内存因此会引发段错误。所以一定要注意两者之间不能直接传递参数。可以将二维数组重新用二级指针表示后面会介绍方法然后就可以用二级指针p来访问二维数组了其访问方法为p[i][j]或*(*(pi)j)即先将指针p移动i个步长取出地址值然后再移动j个步长的地址的内容就是p[i][j]元素对应的就是a[i][j]。
对于一维数组int a[10]与int *pp与a之间可以直接传递因为内存分布一样具体分析同前面。pa则*(pi)p[i]a[i]。对于char *argv[10] char **p; p与argv之间也可以直接传递数据因为两者内存分布一样*(pi)p[i]argv[i]都是char *类型的指针它们存储的内容都是char步长都为1bytes因此都可以表示一个字符串所以在命令行参数和环境变量中可以使用char **p二级指针来传递形参。
二维数组int b[i][j]用二级指针int **p来表示int *a[i]a[i]b[i]pa则有*(pi)p[i]a[i]*(*(pi)j)p[i][j]a[i][j]b[i][j]。因此b与p之间要传递参数时可以用a来搭桥。
2指针与数组的关系举例分析
探究数组名与指针的关系将a[3][5]全部元素初始化为0
//ex1.c
#include stdio.hint main(void)
{int a[10]{0};int *p;pa;printf(a[1]%d, p%#x, p%#x\n,p[1],p,p);return 0;
}
[rootlocalhost 01_pthread_test]# ./ex1
a[1]0, p0xff875cc4, p0xff875cc8//ex.c
#include stdio.hint main(void)
{int **p;int a[3][5]{0};pa;printf(a%#x, a%#x, a[0]%#x, *a%#x, a1%#x, a[0]1%#x, a[1]%#x, a[0][0]%#x\n,a, a,a[0],*a,a1,a[0]1,a[1],a[0][0]);printf(*(a[0][0])%#x\n,*(a[0][0]));printf(*(*a)%#x\n,*(*a));printf(a%#x\n,a);printf(p%#x, p%#x, *p%#x\n,p,p,*p); printf(*(*p)%d\n,*(*p)); //该句出现段错误return 0;
}
[rootlocalhost 01_pthread_test]# ./ex
a0xff83a4d0, a0xff83a4d0, a[0]0xff83a4d0, *a0xff83a4d0, a10xff83a4e4, a[0]10xff83a4d4, a[1]0xff83a4e4, a[0][0]0xff83a4d0
*(a[0][0])0
*(*a)0
a0xff83a4d0
p0xff83a50c, p0xff83a4d0, *p0
Segmentation fault (core dumped)
//ex2.c二维数组用二级指针的另一种表示方法
#include stdio.h
#include stdlib.h
#include stddef.hint main(void)
{int **p;int i, j;p(int **)malloc( sizeof(int *)*3 );for(i0;i3;i){p[i](int *)malloc( sizeof(int)*5 );}for(i0;i3;i)for(j0;j5;j){p[i][j]3;}printf(p[2][3]%d\n,p[2][3]);return 0;
}
[rootlocalhost 01_pthread_test]# ./ex2
p[2][3]3
分析
强调一点数组名、函数名等类似的东西都不是指针只是在使用的时候它们被隐式转换为了指针。一维数组int a[10]; sizeof(a)中a就没有转换为指针a指的就是数组本身 sizeof(a)的结果为4040bytes。如果对a的操作中涉及元素的操作时由于仅仅指出a系统并不清楚要具体取哪一个元素因此直接返回给数组的首地址即a被隐式转换为数组的第一个元素的地址a[0]。二维数组int a[10][9] 其本质就是一个一维数组数组的数组在内存中的分布是一维的一行紧接着一行连续分布即a[0][8]的后面紧接着就是a[1][0]。a[10][9]可以看成是a[0]、a[1]、······、a[9]这十个元素构成的数组其中a[0]是二维数组的首元素而a[0]、a[1]、······、a[9]这十个元素中每一个元素又是一个数组类型为int [9]即a[0]代表a[0][0]~a[0][8]。因此在隐式转换时a被隐式转换为二维数组第一个元素的首地址即aa[0]a的步长为36bytes指向的是a[0]这个数组这一行而a[0]如果进行隐式转换则转换为a[0]这个一维数组的首地址即a[0][0]。注意a与a[0]隐式转换后值是相等的但是步长不一样a[0]转换后所指向的内容是a[0][0]即int类型因此步长为4bytes。因此a与a[0]的指针值虽然是相等的但是步长不一样即a1与a[0]1不相等。a1指向的是a[1][0]a[0]1指向的是a[0][1]。
在上面程序ex.c中。p、a、a、a[0]、*a、a1、a[0]1、a[1]、a[0][0]、*(a[0][0])、*(*a)。p是一个二级指针最终地址内容为int型数值a为int (*)[3][5]类型即指向整个二维数组a是整个数组隐式转换为指向a[0]的指针int (*)[5]类型a[0]是一维数组隐式转换为指向a[0][0]的指针int *类型*a经历了两次隐式转换第一次a被转换第二次*a被转换最终为指向a[0][0]的指针为int *类型a1int (*)[5]类型a[0]1int *类型a[1]int *类型a[0][0]int *类型。根据上面程序输出结果可以判断。若pa则pint ***类型pint **类型*p为int*内容此时程序可以输出结果不会发生错误但是结果毫无意义。*(*p)则会发生段错误因此*p地址的内容用户未定义非法访问内存。
程序ex2.c描述了另一种方法将二级指针表示二维数组。