指针的sizeof的使用
char*p的sizeof的使用
把*p当成数组来理解即可,跟数组名是一个道理
int main() { char *p = "abcdef"; printf("%d\n", sizeof(p)); printf("%d\n", sizeof(p+1)); printf("%d\n", sizeof(*p)); printf("%d\n", sizeof(p[0])); printf("%d\n", sizeof(&p)); printf("%d\n", sizeof(&p+1)); printf("%d\n", sizeof(&p[0]+1)); return 0; }
1.sizeof(p)
p是指向字符串首字符'a'的,是用来存放地址的,但是地址本身是不占用内存的,p这个字符指针变量把'a'的地址存放起来了,那么创建一个变量就要开辟一块内存空间,但是指针变量的大小就是4/8 byte
运行结果:
2.sizeof(p + 1)
char*的指针+1跳过一个字符,也就是'b'的地址,还是一个指针变量,大小还是4/8 byte
运行结果:
3.sizeof(*p)
指针p的类型是char*,对p解引用访问1个字符,字符'a'的大小是1byte
运行结果:
4. sizeof(p[0])
p[0] --> *(p+0) --‘a’ ,大小1byte
运行结果:
5.sizeof(&p)
但凡在内存中开辟空间就有地址,跟字符串是没有关系的,p的类型是char*,所以&p的类型是二级指针
运行结果:
6.sizeof(&p + 1)
&p+1为什么跳过一个p:
图解:
运行结果:
7.sizeof(&p[0] + 1)
p[0]是'a',&p[0]那就是'a'的地址,&p[0]+1,那就是'b'的地址,指向'b'的指针就是4/8byte
运行结果:
char*p的strlen的使用
int main() { char* p = "abcdef"; printf("%d\n", strlen(p));//6 printf("%d\n", strlen(p + 1));//p+1是'b'的地址 5 printf("%d\n", strlen(*p));//err printf("%d\n", strlen(p[0]));//err printf("%d\n", strlen(&p));//随机值 printf("%d\n", strlen(&p + 1));//随机值 printf("%d\n", strlen(&p[0] + 1)); return 0; }
1.strlen(p)
从'a'开始数,到'\0',6个字符
运行结果:
2.strlen(p + 1)
从'b'开始数,到'\0',5个字符
运行结果:
3.strlen(*p)
解引用的结果--‘a’,ascll码值是97,非法访问,err
运行结果:
4.strlen(p[0])
和3是一样的结果,err
运行结果:
5.strlen(&p)
共同点:
不管是p指向的字符串地址,还是&p的这个地址,传入strlen 都是计算长度的,计算长度的结束标志就是遇到\0
关于这里我要详细说明一下p和&p的区别:
传入p后, 从字符串首元素地址开始向后找 能找到\0 因为字符串就是以\0结尾的
例如:
传入p能确定的原因就是 "abcdef\0" 这个是顺序存储的, p的地址就是字符a的地址 ,从a开始向后找\0 是能找到的
而传入&p这个地址,每次执行程序都是不确定的,内存中数据的存储也是不确定的,所以\0的位置也是不确定的
可以看到三次的执行结果都不一样的:
三次&p的结果都是不同的,所以从&p这个地址向后寻找\0也是不确定的
虽然p的地址 执行三次也可能不同,但是它后面的\0位置是确定的
然而关于'\0'后面还有数据我的理解是:
并不是说\0之后就不存数据了,内存中肯定是有数据的,但是strlen关心的是首次出现\0的位置在哪里,计算的是这个长度
运行结果:
6.strlen(&p + 1)
跳过了一个p变量,也是随机值
运行结果:
注意:strlen(&p + 1)和strlen(&p),不存在大小问题,还是随机的
7.strlen(&p[0] + 1)
字符串第二个元素,向后数,5个字符
运行结果:
二维数组的sizeof
int a[3][4] 的sizeof的使用
#include<stdio.h> int main() { int a[3][4] = {0}; printf("%d\n",sizeof(a)); printf("%d\n",sizeof(a[0][0])); printf("%d\n",sizeof(a[0])); printf("%d\n",sizeof(a[0]+1)); printf("%d\n",sizeof(*(a[0]+1))); printf("%d\n",sizeof(a+1)); printf("%d\n",sizeof(*(a+1))); printf("%d\n",sizeof(&a[0]+1)); printf("%d\n",sizeof(*(&a[0]+1))); printf("%d\n",sizeof(*a)); printf("%d\n",sizeof(a[3])); return 0; }
数组在内存中是连续存放的,这种二维数组题其实脑子要清晰一点,什么都是相对的,无论是sizeof还是strlen,其实只要记住:它们就计算两样东西:元素和地址(针对上面的题),第一时间先弄明白它到底是元素还是地址,二者选一,题就会做出来了。
图解:
1.sizeof(a)
a这个二维数组的数组名单独放在sizeof内部,计算整个二维数组的大小
运行结果:
2.sizeof(a[0][0])
二维数组第一行第一个元素,4个字节
运行结果:
3.sizeof(a[0])
二维第一行的数组名,参照上图arr1,这时数组名单独放在sizeof内部了,就是计算数组第一行的大小
运行结果:
4.sizeof(a[0] + 1)
a[0]不是单独放在sizeof内部
a[0]表示的首元素的地址,即第一行第一个元素的地址 - &a[0][0]
a[0] + 1 是第一行第2个元素的地址 &a[0][1]
个人理解:把a[0]理解成上图arr1,那么就算数组arr1的第一个元素的地址,也就是二维数组第一行第一个元素地址,如果arr1+1,那就是第一行第二个元素地址,是地址那大小为4/8 byte
运行结果:
5.sizeof(*(a[0] + 1))
二维数组第一行第二个元素地址解引用,那就是二维数组第一行第二个元素,大小4byte
运行结果:
6.sizeof(a + 1)
a作为二维数组的数组名并非单独放在sizeof内部,所以表示首元素的地址
二维数组的首元素是第一行,这里的a就是第一行的地址--- int (*)[4]
a+1是跳过第一行,指向了第二行
由上图得
那就是二维数组数组名没有单独放在sizeof内部,此时表示二维数组第一个行的地址,也就是arr1(a[0]),那么arr1+1(a[0]+1),变成arr2(a[1]),也就是二维数组第二行的地址,是地址大小为4/8 byte
运行结果:
7.sizeof(*(a + 1))
由6得此时是二维数组第二行的地址解引用,也就是第二行所有元素,也就是*(a[1])
*(a+1)-->a[1],计算第二行元素,那么结果为16byte
运行结果:
8.sizeof(&a[0] + 1)
&a[0]是第一行的地址,&a[0]+1是第二行的地址
个人理解:
由图:
&a[0]是二维数组第一行的数组名,数组名表示首元素地址,也就算二维数组第一行的地址,
类比为&arr1,即为整个数组的地址,那么&arr1+1是跳过第一个数组,也就是arr2(二维数组第二行地址)
可以写成:&a[1]
运行结果:
9.sizeof(*(&a[0] + 1))
由8得,*&a[1]-->a[1]-->二维数组第二行元素
运行结果:
10.sizeof(*a)
*a - 就是第一行元素
运行结果:
11.sizeof(a[3])
这里是下标是存在越界问题,但是sizeof还是可以正常计算,也就是二维数组的第4行(下标:3)
数组名单独放在sizeof内部,计算的是第4行的大小,为16 byte
为解释此问题,举一个例子:
#include<stdio.h> int main() { int a = 5; short s = 11; printf("%d\n", sizeof(s = a + 2));//2 printf("%d\n", s);//11 return 0; }
s=a+2,a和2类型都是int,但是赋值的时候s是short类型,那么结果的类型就是short,表达式就不计算了,直接看由s的类型算出2byte,由于表达式没有运算所以值是不会改变的,答案依旧为11
无论是值还是表达式都有值属性和类型属性,像int a=10 , a+3
a+3的值属性是10,a是int型,3是int型,类型属性是int,其实无论a+3怎么样都是要看它赋给什么类型,要是double型,那sizeof就是8
所以回到题目,sizeof(a[3])在编译期间就完成了运算,直接由类型判断算出值
运行结果:
3.指针笔试题
笔试题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)); return 0; }
图解:
笔试题2
//由于还没学习结构体,这里告知结构体的大小是20个字节 struct Test { int Num; char *pcName; short sDate; char cha[2]; short sBa[4]; }*p; //假设p 的值为0x100000。 如下表表达式的值分别为多少? //已知,结构体Test类型的变量大小是20个字节 int main() { printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0; }
16进制,10进制,8进制,2进制只是数值的表示形式而已,
就像 f 15 17 1111表达的形式的值都为15
图解:
代码运行:
接下来还有不少笔试题,还待继续。欢迎大佬补充!