指针常见题及解析

指针是C语言的中的精髓部分,在于他什么的地址都能指,所以说指针是十分重要的。在常见的一些考法中,指针经常会搭配到数组进行考察,虽然有些时候代码看着复杂,但我们只要抓住重点,就可以轻松解答。

一.指针搭配一维数组及sizeof()操作符和strlen()函数

1.

#include<stdio.h>
int main(){
int a[]={1,2,3,4};
printf("%d\n",sizeof(a));//16,数组名单独放在sizeof()内部,这时候的求的是整个数组的字节大小

printf("%d\n",sizeof(a+0));//4,a是数组首元素的地址,+0后还是数组首元素地址,地址的大小4字节

printf("%d\n",sizeof(*a));//4,a是首元素地址,*a是数组首元素,首元素是整型,大小4字节

printf("%d\n",sizeof(a+1));//4,a是数组首元素地址,+1是第二个元素地址,地址大小4字节

printf("%d\n",sizeof(a[1]));//4,a[1]是数组第二个元素,第二个元素类型是整型,整型大小4字节

printf("%d\n",sizeof(&a));//4,&a是整个整型数组的地址,地址的大小4字节

printf("%d\n",sizeof(*&a));//16,&a是整个数组地址,*&a就是整个数组,相当于将数组名直接放在sizeof(),求的是整个数组的字节大小

printf("%d\n",sizeof(&a+1));//4,&a是整个数组,+1后就是数组后面的地址,地址的大小4字节

printf("%d\n",sizeof(&a[0]));//4,a[0]是首元素,&a[0]是首元素地址,地址大小4字节

printf("%d\n",sizeof(&a[0]+1));4,&a[0]首元素地址,加1后为第二个元素地址,地址的大小4字节
return 0;}

2.

#include<stdio.h>
#include<string.h>
int main(){
char arr[]={'a','b','c','d','e','f'};//定义一个字符数组存放'a' 'b' 'c' 'd' 'e' 'f'

printf("%d\n",sizeof(arr));//6,arr单独放在sizeof求整个数组的大小,整个数组6个元素都是char类

printf("%d\n",sizeof(arr+0));//4,arr数组首元素地址+0还是数组首元素地址,地址大小4字节

printf("%d\n",sizeof(*arr));//1,arr数组首元素地址,*arr数组首元素,字符型大小1字节

printf("%d\n",sizeof(arr[1]));//1,arr[1]即数组第二个元素,字符型大小1字节

printf("%d\n",sizeof(&arr));//4,&arr取出整个数组的地址,地址大小4字节

printf("%d\n",sizeof(&arr+1));//4,&arr+1是整个数组后面的地址,地址大小4字节

printf("%d\n",sizeof(&arr[0]+1));//4,&arr[0]即数组首元素地址,+1为第二个元素地址



printf("%d\n",strlen(arr));//随机值x,arr是字符a地址,strlen从a地址进去知道遇到'\0’停止计数,由于字符数组里面没有存放有'\0'所以会继续访问数组后面的地址,知道遇到'\0'

printf("%d\n"strlen(arr+0));//随机值x,arr数组首元素地址,+0后还是数组首元素'a'地址

printf("%d\n"strlen(*arr));//err,非法访问,*arr是数组首元素即'a',strlen会默认把a当作地址,即把a的ASICC码值97当作地址,访问地址为97的地方

printf("%d\n",strlen(arr[1]));//err,非法访问,arr[1]是'b',strlne会把b的ASICC码98当作地址访问

printf("%d\n",strlen(&arr));//随机值x,&arr是整个数组的地址,但是入口仍然是字符a地址

printf("%d\n",strlen(&arr+1));//随机值x-6,&arr+1跳过整个数组

printf("%d\n",strlen(&arr[0]+1));//随机值-1,数组首元素地址加一,即第二个元素地址,strlen从数组第二个元素进入访问

小结:strlen()函数实参必须是一个地址,也就是说,不管传给strlen函数的是什么,strlen函数都把它当作地址进行访问,地址传给strlen()函数后,strlen访问该地址,知道遇到'\0'停止访问,然后计算字符个数。

3.

#include<stdio.h>
int main()
{
char arr[]="abcdef";

printf("%d\n",sizeof(arr));//7,arr单独放在sizeof计算整个数组的大小,字符串后面默认会带'\0'

printf("%d\n",sizeof(arr+0));//4,arr+0即数组首元素地址,地址的大小是4字节

printf("%d\n",sizeof(*arr));//1,*arr是数组首元素,即字符a,char类型大小1字节

printf("%d\n",sizeof(arr[1]));//1,arr[1]即数组第二个元素b,char类型大小1字节

printf("%d\n",sizeof(&arr));//4,&arr是整个数组的地址,地址的大小4字节

printf("%d\n",sizeof(&arr+1));//4,&arr整个数组的地址,+1即数组后面的地址,地址的大小是4字节

printf("%d\n",sizeof(&arr[0]+1));//4,&arr[0】是数组首元素地址,+1即数组第二个元素地址,地址的大小是4字节





printf("%d\n",strlen(arr));//6,arr是数组首元素地址,strlen从首元素地址进去,遇到'\0'停止

printf("%d\n",strlen(arr+0));//6,arr+0是数组首元素地址

printf("%d\n",strlen(*arr));//err,非法访问

printf("%d\n",strlen(arr[1]));//err,非法访问

printf("%d\n",strlen(&arr));//6,&arr整个数组的地址

printf("%d\n",strlen(&arr[0]+1));//5,&arr[0]即首元素地址,+1即数组第二个元素地址,strlen从第二个元素地址进入

printf("%d\n",strlen(&arr+1));//随机值,&arr是整个数组地址,加一跳过整个数组,即数组后面的地址

//倒数第一和倒数第三行会报警告的原因是,&arr取出的是整个数组的地址,即自然需要用一个字符数组指针来接收,但库函数strlen里面的参数是一个字符指针

小结:注意在数组赋值的时候是直接给的字符串而不是单字符,字符串默认后面会自带一个字符0,而单字符则不会。

4.

#include<stdio.h>
int main(){
char *p="abcdef";

printf("%d\n",sizeof(p));//4,p是一个字符指针变量,存放的是字符串"abcdef"的首字符地址,地址的字节数是4

printf("%d\n",sizeof(p+1));//4,p是首字符地址,加一之后就是第二个字符的地址,地址大小是4字节

printf("%d\n",sizeof(*p));//1,p是首字符地址,*p是首字符a,a是char类型

printf("%d\n",sizeof(p[0]));//1,等价于*(p+0),即第一个字符a

printf("%d\n",sizeof(&p+1));//4,p本身是个字符指针变量,对p取地址+1即p地址后面的地址

printf("%d\n",sizeof(&p[0]+1));4,//p[0]是首字符,&p[0]即首字符地址,首字符地址加一即第二个字符b地址



printf("%d\n",strlen(p));//6,p是一个字符指针,指向常量字符串”abcdef“首字符地址

printf("%d\n",strlen(p+1));//5,p是首字符地址,+1即第二个字符地址

printf("%d\n",strlen(*p));//err,*p即首字符a,非法访问内存

printf("%d\n",strlen(p[0]));//err,p[0]即*(p+0)即字符a,非法访问内存

printf("%d\n",strlen(&p+1));//随机值,&p即字符指针变量的地址,&p+1即p指针变量后面的地址

printf("%d\n",strlen(&p[0]+1));//5,&p[0]即首字符地址,+1即第二个字符地址

二.指针与二维数组的搭配

#include<stdio.h>
int main(){
int a[3][4]={0};

printf("%d\n",sizeof(a));//48,a单独放在sizeof里面,即计算整个a数组的字节大小

printf("%d\n",sizeof(a[0][0]));//4,即数组首行首列的元素,为int型,4个字节

printf("%d\n",sizeof(a[0]));//16,a[0]即二维数组首元素,首元素即首行,首行是一个一维数组,相当于将一个一维数组直接放在sizeof里面,所以计算的是整行元素的大小

printf("%d\n",sizeof(a[0]+1));//4,a[0]是一个一维数组的数组名,表示第一行第一个元素的地址,加一即第一行第二个元素的地址

printf("%d\n",sizeof(*(a[0]+1)));//4,第一行第二列的元素地址解引用即第一行第二列的元素

printf("%d\n",sizeof(a+1));//4,a表示数组首元素地址,即首行地址,+1即第二行地址

printf("%d\n",sizeof(*(a+1)));//16,第二行地址解引用即第二行,相当于把存有第二行数据的一个一维数组数组名直接放在sizeof里面,即求整个数组的字节大小

printf("%d\n",sizeof(&a[0]+1));//4,&a[0]即首行地址,+1即第二行地址,地址大小为4字节

printf("%d\n",sizeof(*(&a[0]+1)));//16,第二行地址解引用即第二行,相当于直接把第二行这个一维数组的数组名放在sizeof

printf("%d\n",sizeof(*a));//16,a是首行地址,*a即首行,相当于直接把一个一维数组名放在sizeof

printf("%d\n",sizeof(a[3]));//16,虽然这里的a[3]不在数组范围内,但sizeof()真这个操作符是不会计算()里面的表达式的,所以计算的结果等同于a[0]

小结:1.sizeof(数组名)这个时候的数组名表示整个数组,计算的整个数组的大小;

2.&数组名,这里的数组名表示数组首元素的地址;

3.除此之外所有的数组名都表示数组首元素的地址;

4.注意区分二维数组a[0]和a,a[0]表示的是第一行的所有元素(可以把它看作一个一维数组,相当于直接把数组名防在了sizeof()里面,而a表示的是第一行的地址,*a的话就表示第一行元素,所以*a和a[0]意义是一样的。

三.

1.

#include<stdio.h>
int main(){
int a[5]={1,2,3,4,5};
int *ptr=(int*)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));//2,5

2.

//假设指针变量p的值为0x100000,已知,结构体test类型的变量大小是20字节
#include<stdio.h>
int main(){
struct test{
int num;
char*pcname;
short sdate;
char cha[2];
short sba[4];}*p

p=(struct test*)0x100000
printf("%p\n",p+0x1);//00 100014,p是结构体指针,加1即一个指针加一个整数,走过的步长决定于指针的类型
printf("%p\n",(unsigned long)p+0x1);//00 100001,将p转换为一个整型,即整数的加法
printf("%p\n",(unsigned int*)p+0x1);//00 100004,p现在为一个整型指针类型,加1即跳过4个字节

 3.

#include<stdio.h>
int main(){
int a[4]={1,2,3,4};
int *ptr1=(int*)(&a+1);
int *ptr2=(int*)((int)a+1);
printf("%x,%x\n",ptr1[-1]),*ptr2);//4,02000000

 

 解析如上图

 

 4.

#include<stdio.h>
int main()
{
int a[3][2]={(0,1),(2,3),(4,5)};
int *p;
p=a[0];
printf("%d",p[0]);//1

 注意这里二位数组的初始化大括号里面使小括号,所以是个逗号表达式,即二维数组初始化为1,3,5,0,0,0。

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值