C语言——深入理解指针(5)

目录

1. sizeof和strlen的对比

1.1 sizeof

1.2 strlen

1.3 sizeof和strlen 的对比

2. 数据和指针题解析

2.1 一维数组

2.2 字符数组

2.2.1

2.2.2

2.2.3

2.2.4

2.2.5

2.2,6

2.3 二维数组

3. 指针运算题解析

3.1 例1

3.2 例2

3.3 例3

3.4 例4

3.5 例5

3.6 例6

3.7 例7


1. sizeof和strlen的对比

1.1 sizeof

sizeof是用来计算变量所占内存空间的大小,单位:字节

如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。

sizeof 只关注占用空间的大小,不在乎内存中放了什么

1.2 strlen

strlen 是用来求字符串长度的。

size_t strlen ( const char * str );

strlen 统计的是字符串开始到 \0 之前的字符串的字符个数。(strlen 找到 \0 就会停止,没有找到就会一直找下去)

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[3] = { 'a', 'b', 'c' };//没有\0
	char arr2[] = "abc";//a,b,c,\0
	printf("%d\n", strlen(arr1));//随机数
	printf("%d\n", strlen(arr2));
	return 0;
}

1.3 sizeof和strlen 的对比

sizeofstrlen

1. sizeof 是操作符

2. sizeof 计算操作数所占内存的大小,单位:字节

3. 不管内存中存什么数据

1. strlen 是库函数,使用时需要包含头文件<string.h>

2. strlen 是求字符串长度的,统计的是\0 之前字符的间隔个数

3. 关注内存中是否有 \0 如果没有 \0 ,就会持续往后找,可能会越界。

2. 数据和指针题解析

首先我们先来补充一个知识点

数组名:数组名一般表示数组首元素的地址,但是有2个例外,

1. sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节;

2. &数组名,数组名表示整个数组,取出的数组的地址;

除此之外,所有遇到的数组都是数组首元素的地址。

2.1 一维数组

int main()
{
	int a[] = { 1,2,3,4 };//a数组有4个元素,每个元素是int类型的数据
	printf("%d\n", sizeof(a));//计算的是整个数组的大小---16
	printf("%d\n", sizeof(a + 0));//计算的是首元素地址+0,也就是首元素地址,——4或8
	printf("%d\n", sizeof(*a));//计算的是首元素的大小--4
	printf("%d\n", sizeof(a + 1));//计算的是首元素地址+1,也就是第二个元素地址的大小,——4或8
	printf("%d\n", sizeof(a[1]));//计算的是下标为1的元素大小——4
	printf("%d\n", sizeof(&a));//&a—取出的是数组地址,但是数组地址也是地址,所以——4或8
	printf("%d\n", sizeof(*&a));//计算的是整个数组的大小——16
	printf("%d\n", sizeof(&a + 1));//&a—取出的是数组地址,&a+1是跳过整个数组后的地址,也是地址——4或8
	printf("%d\n", sizeof(&a[0]));//&a[0]是第一个元素的地址--4或8
	printf("%d\n", sizeof(&a[0] + 1)); //&a[0] + 1是第二个元素的地址——4或8
	return 0;
}

2.2 字符数组

2.2.1

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));//计算的是整个数组元素的大小——6
	printf("%d\n", sizeof(arr + 0));//就是的是arr+0的地址,也就是数组第一个元素的地址——4或8
	printf("%d\n", sizeof(*arr));//计算的是数组的第一个元素的地址——1
	printf("%d\n", sizeof(arr[1]));//计算的是数组下标为1的元素——1
	printf("%d\n", sizeof(&arr));//&arr是整个数组的地址,但是数组地址也是地址——4或8
	printf("%d\n", sizeof(&arr + 1));//&arr—取出的是数组地址,&arr+1是跳过整个数组后的地址,也是地址——4或8
	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址——4或8
	return 0;
}

2.2.2

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));//随机值
	printf("%d\n", strlen(arr + 0));//随机值
	printf("%d\n", strlen(*arr));//访问错误,*arr是‘a’-97
	printf("%d\n", strlen(arr[1]));//访问错误,arr[1]是'b'
	printf("%d\n", strlen(&arr));//随机值
	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//随机值
	return 0;
}

2.2.3

int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//arr+0是数组的首元素地址,地址的大小——4/8
	printf("%d\n", sizeof(arr + 0));//
	printf("%d\n", sizeof(*arr));
	printf("%d\n", sizeof(arr[1]));
	printf("%d\n", sizeof(&arr));//&arr-是数组的地址,数组的地址也是地址,是地址大小就是4/8
	printf("%d\n", sizeof(&arr + 1));//&arr+1,跳过数组,指向的是数组后面的地址--4/8
	printf("%d\n", sizeof(&arr[0] + 1));
	return 0;
}

2.2.4

#include<string.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//6
	printf("%d\n", strlen(arr + 0));//arr+0是数组首元素的地址:6
	printf("%d\n", strlen(*arr));//err   传递的是'a'
	printf("%d\n", strlen(arr[1]));//err	传递的是'b'
	printf("%d\n", strlen(&arr));//err		
	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//&arr[0] + 1是第二个的地址--5
	return 0;
}

2.2.5

int main()
{
	const char* p = "abcdef";
	printf("%d\n", sizeof(p));//计算的是指针变量的大小-4/8
	printf("%d\n", sizeof(p + 1));//p+1是’b‘的地址
	printf("%d\n", sizeof(*p));//'a'---1
	printf("%d\n", sizeof(p[0])); //p[0]=='a'---1字节
	printf("%d\n", sizeof(&p));//&p-是自己的地址--4/8
	printf("%d\n", sizeof(&p + 1));//4/8
	printf("%d\n", sizeof(&p[0] + 1));//(&p[0] + 1)是'b'的地址
	return 0;
}

2.2,6

int main()
{
	const char* p = "abcdef";
	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//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));//5
	return 0;
}

2.3 二维数组

int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//12*4=48个字节,数组名单独在sizeof内部
	printf("%d\n", sizeof(a[0][0]));//4
	printf("%d\n", sizeof(a[0]));//是第一行这个一维数组的数组名,数组名单独放置sizeof内部了--16
	printf("%d\n", sizeof(a[0] + 1));//a[0]是第一行这个一维数组的数组名,这里表示数组首元素
	//也就是a[0][0]的地址,a[0] + 1是a[0][1]的地址
	printf("%d\n", sizeof(*(a[0] + 1)));//a[0]][1]--4个字节
	printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,但是没有&,也没有单独放在sizeof内部
	//所以这里的a是数组首元素的地址,应该是第一行的地址,a+1是第二行的地址----4/8
	printf("%d\n", sizeof(*(a + 1)));//第二行的数组名,计算的是第二行的大小--16
	printf("%d\n", sizeof(&a[0] + 1));///&a[0]是第一行的地址,&a[0]+1就是第二行的地址
	printf("%d\n", sizeof(*(&a[0] + 1)));//对第二行的地址解引用,计算的是第二行的大小--16
	printf("%d\n", sizeof(*a));//这里的a是第一行的地址,*a就是第一行---16
	//*a->*(a+0)--.a[0]
	printf("%d\n", sizeof(a[3]));//a[3]就是的是第四行的大小---16
	//因为sizeof内部的不都是不会真实计算
	return 0;
}

3. 指针运算题解析

3.1 例1

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));
	return 0;;
}

运行结果:

3.2 例2

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p = (struct Test*)0x100000;
//指针+整数
int main()
{
	printf("%p\n", p + 0x1);//0x100000+20=0x100014
	printf("%p\n", (unsigned long)p + 0x1);//0x100001
	printf("%p\n", (unsigned int*)p + 0x1);//ox100004
	return 0;
}

3.3 例3

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };//里面的括号是小括号,所以表示的逗号表达式
	//所以真正的数组元素是1,3,5,其他都是0
	int* p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}

3.4 例4

//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{
	int a[5][5];//int (*ptr)[5]=a
	int(*p)[4];//P是数组指针,指向的数组4个类型的元素
	p = a;
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//指针-指针点决斗者得到的是指针和指针之间的元素个数,FFFFFC,-4
	return 0;
}

3.5 例5

#include <stdio.h>
int main()
{
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int* ptr1 = (int*)(&aa + 1);
	int* ptr2 = (int*)(*(aa + 1));//a[1]//aa是首元素的地址,也就是第一行的地址,aa+1就是第二行的地址
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
	return 0;
}

3.6 例6

#include <stdio.h>
int main()
{
	const char* a[] = { "work","at","alibaba" };//指针数组
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

3.7 例7

#include <stdio.h>
int main()
{
	const char* c[] = { "ENTER","NEW","POINT","FIRST" };
	const char** cp[] = { c + 3,c + 2,c + 1,c };
	const char*** cpp = cp;
	printf("%s\n", **++cpp);//POINT
	printf("%s\n", *-- * ++cpp + 3);//ER
	printf("%s\n", *cpp[-2] + 3);//ST	cpp[2]-->*(cpp-2)
	printf("%s\n", cpp[-1][-1] + 1);//EW	cpp[-1][-1]-->*(*(cpp-1)-1)+1	
	return 0;
}
  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值