C语言指针笔记
B站C指针学习笔记
1.指针和数组
代码如下(示例):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//数组名的意义
//1、sizeof(数组名)-数组名表示整个数组-计算的是整个数组的大小
//2、&数组名-数组名表示整个数组,取出的的整个数组的地址
//3、除此以外,所有的数组名都是数组首元素地址,例如sizeof(a+0)
//const:放在*右边指针变量本身不能修改,放在*左边指针指向的内容不能修改
//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));// 16
printf("%d\n",sizeof(a+0));// 4/8(32位是4,64位是8)a+0是第一个元素的地址(首元素地址+0),sizeof(a+0)计算的是地址的大小
printf("%d\n",sizeof(*a));// 4 不属于1、2,属于3,代表首元素地址,再*,因此*a表示数组的第一个元素1,sizeof(*a)计算的是第一个元素的大小
printf("%d\n",sizeof(a+1));// 4/8 a+1是第二个元素的地址
printf("%d\n",sizeof(a[1]));// 4 第二个元素的大小
printf("%d\n",sizeof(&a));// 4/8 &a虽然是数组的地址但也是地址,sizeof(&a)计算的是一个地址的大小
printf("%d\n",sizeof(*&a));// 16 &a--int(*p)[4]=&a,&a取的是数组的地址,再*,计算的是数组的大小(*&可理解为抵消)
printf("%d\n",sizeof(&a+1));// 4/8 跳过整个数组,数组后面(4后面)空间的地址
printf("%d\n",sizeof(&a[0]));// 4/8 第一个元素地址
printf("%d\n",sizeof(&a[0]+1));// 4/8 第二个元素地址
//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(arr));// 6 没有\0
printf("%d\n",sizeof(arr+0));// 4/8 首元素地址+0,即a的地址
printf("%d\n",sizeof(*arr));// 1 arr没取地址也没单独放sizeof内部,属于第3种情况,数组名表示首元素地址,再*,取出a
printf("%d\n",sizeof(arr[1]));// 1 元素b
printf("%d\n",sizeof(&arr));// 4/8 数组地址
printf("%d\n",sizeof(&arr+1));// 4/8 跳过整个数组,数组后面(f后面)空间的地址
printf("%d\n",sizeof(&arr[0]+1));// 4/8 b的地址
printf("%d\n",strlen(arr));// 随机值 strlen表示从给的地址开始数,数到\0为止,不知道什么时候遇到
printf("%d\n",strlen(arr+0));// 随机值
printf("%d\n",strlen(*arr));// error 字符a被传过去,a值为97,把97当作地址
printf("%d\n",strlen(arr[1]));//error 同理,字符b 98
printf("%d\n",strlen(&arr));// 随机值 取出数组地址,只要传给char* str( int my_strlen(char* str)),就变成字符的地址,
//值没变但类型变了,本来类型是char(*)[6];,传过去就变char*
printf("%d\n",strlen(&arr+1));//随机值 比上一个随机值-6
printf("%d\n",strlen(&arr[0]+1));//从b的地址开始数 随机值比上上个-1
char arr[] = "abcdef";// 有\0
printf("%d\n",sizeof(arr));// 7
printf("%d\n",sizeof(arr+0));// 4/8 首元素地址+0
printf("%d\n",sizeof(*arr));// 1 第一个元素地址解引用,第一个元素a
printf("%d\n",sizeof(arr[1]));// 1 元素b
printf("%d\n",sizeof(&arr));// 4/8 整个数组的地址 地址类型:char(*)[7]
printf("%d\n",sizeof(&arr+1));// 4/8 跳过7个字符
printf("%d\n",sizeof(&arr[0]+1));// 4/8 第一个元素地址+1,元素b的地址
printf("%d\n",strlen(arr));// 6 有\0
printf("%d\n",strlen(arr+0));// 6
printf("%d\n",strlen(*arr));// error 97做地址
printf("%d\n",strlen(arr[1]));// eror 98做地址
printf("%d\n",strlen(&arr));// 6 从a开始数
printf("%d\n",strlen(&arr+1));// 随机值 跳过整个数组包括\0,不知道后面什么时候有\0
printf("%d\n",strlen(&arr[0]+1));// 5 从b开始数
char* p = "abcdef";// 有\0,把常量字符串首字符a的地址放到p里
printf("%d\n",sizeof(p));// 4/8 字符指针
printf("%d\n",sizeof(p+1));// 4/8 b的地址
printf("%d\n",sizeof(*p));// 1
printf("%d\n",sizeof(p[0]));// 1 p[0]等价于*(p+0)
printf("%d\n",sizeof(&p));// 4/8
printf("%d\n",sizeof(&p+1));// 4/8
printf("%d\n",sizeof(&p[0]+1));// 4/8 b的地址
printf("%d\n",strlen(p));// 6
printf("%d\n",strlen(p+1));// 5
printf("%d\n",strlen(*p));// error 传字符a,就是传97
printf("%d\n",strlen(p[0]));// error 也是传字符a
printf("%d\n",strlen(&p));// 随机值 (p)->(abcdef\0)p指向a的地址,(p)本身在另一个位置,&p是从地址p开始数p里具体不知道是什么
printf("%d\n",strlen(&p+1));// 随机值,跳过p开始数,这个随机值与上一个随机值无任何关系 (如p里面可能有\O,0就是\0)
printf("%d\n",strlen(&p[0]+1);// 5 从b的地址向后数
//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));// 48 3*4*sizeof(int)
printf("%d\n",sizeof(a[0][0]));// 4 第一行第一个元素
printf("%d\n",sizeof(a[0]));// 16 a[]可理解为第一行的数组名
printf("%d\n",sizeof(a[0]+1));// 4 a[]作为数组名没有单独放在sizeof内部,也没取地址。:第一行第一个元素地址+1
printf("%d\n",sizeof(*(a[0]+1)));// 4 第一行第二个元素解引用(*),int类型
printf("%d\n",sizeof(a+1));// 4 a是二维数组的数组名并没有取地址,也没有单独放在sizeof内部。a表示二维数组首元素地址,:第二行地址
printf("%d\n",sizeof(*(a+1)));// 16 a+1表示第二行地址,*(a+1表示第二行) (*(a+1)等价于a[1])
printf("%d\n",sizeof(&a[0]+1));// 4 a[0]是第一行的数组名,&a[0]取的是第一行的地址,+1:第二行的地址
printf("%d\n",sizeof(*(&a[0]+1)));// 16 第二行的地址
printf("%d\n",sizeof(*a));// 16 首元素地址,即第一行地址,再解引用->第一行
printf("%d\n",sizeof(a[3]));// 16 没有访问 表达式 1.值属性2.类型属性 sizeof内部表达式是不算的。其实不存在,通过数据类型计算大小
short s=5;
int a=4;
printf("%d\n",sizeof(s=a+6));// 2 放在s,看s,2字节
printf("%d\n",s); // s=5,sizeof里面不计算
system("pause");
return 0;
}
2.练习题
代码如下(示例):
1、int main()
{
int a[5] = {1,2,3,4,5};
int* ptr = (int*)(&a+1);//(&a+1)跳过整个地址,指向5的后面,再把该地址类型(原本是int(*)[5])强转成int*在赋值给ptr,所以ptr指向5后面
printf("%d,%d",*(a+1),*(ptr-1));//ptr-1跑到5的前面,再解引用向后访问4字节
system("pause");
return 0;
//答案为2,5
}
2、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);//0x1为16进制的1,和十进制1无区别,+1->+20
printf("%p\n",(unsigned long)p + 0x1);//p被强转成整形
printf("%p\n",(unsigned int*)p + 0x1);//强转为无符号整型指针
system("pause");
return 0;
}
//答案:0x100014 0x10001 0x100004
//3、int main()
{
int a[4] = {1,2,3,4};
int* ptr1 = (int*)(&a+1);//ptr1指向4后面
int* ptr2 = (int*)((int)a+1);
printf("%x,%x",ptr1[-1],*ptr2);
}
//答案:4,2000000
4、int main()
{
int a[3][2] = {(0,1),(2,3),(4,5)}; //(0,1)逗号表达式相当于放了1 3 5,其它补0:1 3,5 0,0 0
int* p;
p = a[0];//1的地址放p里面
printf("%d",p[0]);//p[0]等价于*(p+0)
return 0;
}
//答案:1
5、int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf("%p,%d",&p[4][2] - &a[4][2],&p[4][2]-&a[4][4]);//两个指针相减得到的是指针之间的远元素个数
system("pause");
return 0;
}
//答案:FFFFFFFC
6、int main()
{
int aa[2][5] = {1,2,3,4,5,6,7,8,9,10};
int* ptr1 = (int*)(&aa+1);//ptr1指向10的后面
int* ptr2 = (int*)(*(aa+1));//(aa+1)指向第二行即5的后面,再*取出第二行 ,*(aa+1)相当于aa[1]又相当于第二行的数组名,相当于6的地址,(int*)无用迷惑
printf("%d,%d",*ptr1-1),*(ptr2-1);//ptr1-1向左移一个int到9的后面,取出10
system("pause");
return 0;
}
//答案:10,5
7、int main()
{
char*a[] = {"work","at","alibaba"};
char** pa = a;
pa++;
printf("%s\n",*pa);//a的地址向后打印字符串
system("pause");
return 0;
}
//答案:at
8、int main()
{
char* c[] = {"ENTER","NEW","POINT","FIRST"};
char** cp[] = {c + 3,c + 2,c + 1,c};
char*** cpp = cp;
printf("%s\n",**++cpp);
printf("%s\n",*-- * ++cpp + 3);
printf("%s\n",*cpp[-2] + 3);
printf("%s\n",cpp[-1][-1] + 1);
system("pause");
return 0;
}
//答案:POINT,ER,ST,EW