C语言-指针

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.练习题

代码如下(示例):

1int 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
}
2struct 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
4int 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
5int 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
6int 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
7int main()
{
	char*a[] = {"work","at","alibaba"};
	char** pa = a;
	pa++;
	printf("%s\n",*pa);//a的地址向后打印字符串
	system("pause");
	return 0;
}
//答案:at
8int 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 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值