简图记录-C语言总结(二) 指针与数组

简图记录学习~

C语言常见难点就是指针和数组的使用,概念和使用上都常容易混淆

首先明确一点,指针和数组没有关系,只是从访问上有看上去类似用法,其实是两个概念,一定要区分清楚;

 指针数组
概念一种特殊数据类型它的值是作为内存地址,常用于对指向地址内存数据按所指向类型进行访问一种构造数据类型,由多个数组元素组成,每个元素是基本类型或者构造类型。编译器在定义一个数组的时候,分配了sizeof(元素类型)*元素个数 大小的内存,命名为数组名;(注意:一旦内存匹配好就不可再分开,且如定义数组int a[5] 其中a[0]、a[1]是一种访问元素方式,并非元素内存名叫a[0],元素是没有名字的)
声明指针的声明必须是指针,如char *p只能用extern char *p不能用extern char p[];char a[100];必须以extern char a[]或者extern char a[100]声明,不能以extern char *a;
大小大小置和cpu当前运行模式下的寻址位数相关,32位就是4byteint a[5]为例子:
sizeof(a)大小为sizeof(int)*5;
sizeof(a[0])和sizeof(a[5])大小为sizeof(int) (注意这里a[5]是a[4]后面 一个元素,已越界)
访问可以 指针方式*(p+i) 或者 下标方式 p[i]访问指向内存数据。
本质是对地址=P值+i*sizeof(类型)内存进行访问;(指针计算:注意p+i相当于p值加sizeof(类型)*i而非p值直接加i)
可以 指针方式*(a+i) 或者 下标方式a[i] 访问a[i]元素。
本质是对地址=首元素a[0]地址值+i*sizeof(类型)元素进行访问;
a做右值时表示首元素地址相当于&a[0],数组首地址为&a
,注意虽然二者值一样但概念不同。
二级指针/二维数组二级指针就是指向一个指针类型数据的指针.
常用与当希望通过函数修改某个指针数据时如内存分配获取新地址,若使用一级指针做函数入参只是传递指针值。而通过对指针取地址以二级指针做入参,则可以通过指针地址修改内容
如int a[3][4],由于内存是线性的,编译器其实将二维数组看做一维数组,每个元素为一个数组连续存储
可以按下标 方式a[i][j]或者指针方式*(*(a+i)+j)访问指定位置数组元素;本质就是对 地址=首元素a[0][0]地址值+i*(sizeof(int)*4)+j*sizeof(int)的元素访问;
其他重要信息函数指针:指向函数的指针。
使用*p可调用函数,如char (*p)(char *a);
例如:
(*(void(*)())0)();
//将0地址强转为void(*)()型函数指针并调用;
char (*p[10])(char *a);
//函数指针数组
char (*(*p)[10])(char *a);
//函数指针数组指针
 
数组和指针关联(1)数组指针和指针数组
数组指针:int (*p)[10]
指针数组:int *p[10] (注意[]优先级比*高 先结合就表示为数组
(2)数组做函数入参

一维数组做函数入参时,编译器将其解析为指向其首元素的指针
如void test(char a[10])或者void test(char a[])等价于void test(char *a)。原因:C语言中所以非数组类型做实参时均以传值方式,数组传值引起的时间和空间开销太大因此解析为指针方式访问。同理 函数的返回值也不能为数组。
针对超过一维数组做入参时,只能将第一维数组解析为指向首元素的指针
如void test(char a[3][4])或者void test(char a[][4])等价为void test(char (*a)[4])。
(注意指针数据解析 void test(char *p[5])等价为void test(char **p))

四、几练习题

1、求哪几个地址哪几个相同

int a[5]={1,2,3,4,5};
void print_test(int *p)
{
    print("addr1=%p addr2=%p\n",&p,&p[0]);
}
int main()
{
    print_test(a);
    print("addr3=%p addr4=%p\n",&a,&a[0]);
}

解析:addr2、addr3、addr4相同。&p为指针变量P在栈上的地址,addr2为通过p[0]取出指向内存(相当于a[0])然后取地址。&a为数组首地址、&a[0]为数组首元素a[0]地址;

2、求*(a+1)、*(p1-1)、*p2值

int a[5]={1,2,3,4,5};
int *p1=(int *)(&a + 1);
int *p2=(int *)((int)a + 1);

解析:

*(a+1)就是a[1]为2;    

&a+1实际为数值取地址+1相当于int (*)[5]型指针+1,就相当于p1指向了a[5]已越界,由于P为int*型,p-1地址减sizeof(int)和a[4]一样,因此值为5;

(int)a+1由于转化为,实际地址只加了1,相当于从a[0]元素第2个byte到a[1]前3个byte构成一个int数据,考虑到字节序,在小端系统上为0x2000000;

3、求&p[4][2]-&a[4][2]

int a[5][5];
int (*p)[4];
p=a;

解析:&p[4][2]值=p值+4*(sizeof(int)*4)+2*sizeof(int),&a[4][2]值为=a[0]地址+4*(sizeof(int)*5)+2*sizeof(int),因此为-4;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值