1,sizeof和strlen的区别(细节)2,指针的练习

9.指针和数组练习题

sizeof 是一个操作符,计算的是对象所占的内存大小,单位是字节,返回类似是soze_t

(unsigned int),不在乎内存里面放的是什么。

strlen 是个库函数,求字符串长度,参数是一个地址(char*类型的地址)(类型不匹配会被强制类型转换为(char*)类型的)

从给定的地址向后访问字符,统计\0之前出现的字符个数。

1,练习:sizeof和int a[] = { 1,2,3,4 };

#include<stdio.h>
int main()
{
	//数组名一般是数组首元素的地址
	//但是也有两个例外 1,sizeof(arr);  2,&数组名

	//sozeof计算的是对象所占内存的大小

	//一维数组
	int a[] = { 1,2,3,4 };//[1,2,3,4]

	printf("%d\n", sizeof(a));//16
	printf("%d\n", sizeof(a + 0));//4或者8

	//这里的a+0首元素的地址。a+1就是第二个元素的地址
	//地址占4或者8个字节

	printf("%d\n", sizeof(*a));//4
	//这里是a是首元素的地址,*a就是第一个元素,int类型的数据

	printf("%d\n", sizeof(a + 1));//4或者8
	//上面讲到a+1 就是第二个元素的地址,
	//地址占4或者8字节

	printf("%d\n", sizeof(a[1]));//4
	//这里a[1]就是第二个元素,int类型的数据

	printf("%d\n", sizeof(&a));//4或者8
	//&a取出的是整个数组的地址,但是也是一个地址
	//是地址都占4或者8字节
	printf("%d\n", sizeof(*&a));//16
	//&a取出整个数组的地址,对数组的地址解引用就拿到整个数组
	//所以他就是16//相当于sizeof(a)

	printf("%d\n", sizeof(&a + 1));//4或者8
	//&a就是整个数组的地址,整个数组的地址加一跳过整个数组,就是加了16
	//但是还是一个地址  地址就占4或者8个字节

	printf("%d\n", sizeof(&a[0]));//4或者8
	//这个就是数组第一个元素的地址啊
	//地址就是4或者8个字节。

	printf("%d\n", sizeof(&a[0] + 1));//4或者8
	//这个就是第一个元素的地址加一,第二个元素的地址




	return 0;
}

2,练习sizeof,strlen和char arr[ ] = { 'a','b','c','d','e','f' };


int main()
{

	//strlen功能就是给他一个地址,他会计算从这个地址到'\0'之间的字节大小。


	char arr[] = { 'a','b','c','d','e','f' };//[a,b,c,d,e,f]

	printf("%d\n", strlen(arr));//随机数>=6
	//arr数组首元素的地址
	//这个数组里面是放了那几个字符 没有'\0'
	//strlrn在计算字符串的大小的时候遇到'\0'才会停止
    //这里的虽然也构成的越界访问,但是报错与否是是编译器决定的。

	printf("%d\n", strlen(arr + 0));//随机数>=6	
	//arr数组名 表示首元素的地址
	//arr+0也是数组首元素的地址
    //这里的虽然也构成的越界访问,但是报错与否是是编译器决定的。

	printf("%d\n", strlen(*arr));//错误
	//arr是首元素地址,
	//*arr就是数组的首元素也就是字符a,ascll就是97
	//也就是97 传给strlen ,strlen会把97看成char*类型的地址
	//这样就出现的野指针,会报出非法访问

	printf("%d\n", strlen(arr[1]));//错误
	//和上面一样非法非法访问

	printf("%d\n", strlen(&arr));//随机数>=6
	//&arr取出整个数组的地址,传给我的strlen
	//最终也会被看成一个(char*)类型的指针
	//这个和直接传arr是没有什么区别的
	//arr和&arr的意义虽然不一样但是值都是一样的
	//警告强制类型转换都的char*类型的指针
    //这里的虽然也构成的越界访问,但是报错与否是是编译器决定的。

	printf("%d\n", strlen(&arr + 1));//随机值>=0
	//&arr取出整个数组的地址+1就跳过整个数组
	//就是整个数组后面的那个地址。同样什么时候遇到'\0'是不知道的
    //这里的虽然也构成的越界访问,但是报错与否是是编译器决定的。

	printf("%d\n", strlen(&arr[0] + 1));//随机值>=5
	//&arr[0]取出首元素的地址,
	//&arr[0]+1是第二个元素的地址
    //这里的虽然也构成的越界访问,但是报错与否是是编译器决定的。



	return 0;
}


//编译器也是人写的 也会有一些错误情况是不会报错的

int main()
{
	//字符数组1
	char arr[] = { 'a','b','c','d','e','f' };//[a,b,c,d,e,f]
	printf("%d\n", sizeof(arr));//6
	//sizeof只是计算目标所占内存的大小
	//没有'\0'一说

	printf("%d\n", sizeof(arr + 0));//4或者8
	//这个就是arr是首元素的地址+0也是首元素的地址
	//地址就是占4或者8个字节

	printf("%d\n", sizeof(*arr));//1
	//arr是首元素的地址 *arr就是首元素 char类型的数据
	//相当于arr[0]

	printf("%d\n", sizeof(arr[1]));//1
	//第二个元素 char类型的数据

	printf("%d\n", sizeof(&arr));//4或者8
	//是数组的地址 
	//地址就是4或者8个字节

	printf("%d\n", sizeof(&arr + 1));//4或者8
	//数组的地址+1就是跳过整个数组,相当于加6
	//但是还只是一个地址
	//地址就是4或者8字节

	printf("%d\n", sizeof(&arr[0] + 1));//4或者8
	//是第二个元素的地址
	//地址就是4或者8字节

}

3,练习sizeof,strlen和 char arr[] = "abcdef";


int main()
{
	char arr[] = "abcdef"; //[a,b,c,d,e,f,\0]
	//默认会带一个\0

	printf("%d\n", sizeof(arr));//7

	printf("%d\n", sizeof(arr + 0));//4或者8
	//这个就是arr是首元素的地址+0也是首元素的地址
	//地址就是占4或者8个字节

	printf("%d\n", sizeof(*arr));//1
	//arr是首元素的地址 *arr就是首元素 char类型的数据
	//相当于arr[0]

	printf("%d\n", sizeof(arr[1]));//1
	//数组的第二个元素

	printf("%d\n", sizeof(&arr));//4或者8
	//是数组的地址 
	//地址就是4或者8个字节

	printf("%d\n", sizeof(&arr + 1));//4或者8
	//是整个数组最后一个元素后面的地址 
	//地址就是4或者8个字节

	printf("%d\n", sizeof(&arr[0] + 1));//4或者8
	//这个就是第一个元素的地址加一,第二个元素的地址


	return 0;
}

int main()
{

	char arr[] = "abcdef"; //[a,b,c,d,e,f,\0]


	printf("%d\n", strlen(arr));//6
	//arr首元素地址

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

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

	printf("%d\n", strlen(&arr));//6
	//&arr取出整个数组的地址,传给我的strlen
	//最终也会被看成一个(char*)类型的指针
	//这个和直接传arr是没有什么区别的
	//arr和&arr的意义虽然不一样但是值都是一样的
	//警告强制类型转换都的char*类型的指针

	printf("%d\n", strlen(&arr + 1));//随机数
	//&arr取出整个数组的地址+1就跳过整个数组
	//就是整个数组后面的那个地址。同样什么时候遇到'\0'是不知道的

	printf("%d\n", strlen(&arr[0] + 1));//5
	//从第二个元素地址开始的


	return 0;
}

4,sizeof ,strlen 和char* p = "abcdef";


int main()
{
	//"abcdef"是一个常量字符串
	char* p = "abcdef";//p是一个指针变量
	//里面放的是a的地址,p指向的是a

	printf("%d\n", sizeof(p));//4或者8
	//p是指针变量,
	//存的是地址,地址占4或者8

	printf("%d\n", sizeof(p + 1));//4或者8
	//p+1是b的地址
	//是地址就是4或者8个字节

	printf("%d\n", sizeof(*p));//1
	//*p就是a char类型的

	printf("%d\n", sizeof(p[0]));//1
	//p[0]==*(p+0) 就是 a

	printf("%d\n", sizeof(&p));//4或者8
	//p是a的地址
	//&p是指针变量p的地址(二级指针)

	printf("%d\n", sizeof(&p + 1));//4或者8
	//&p是a地址的二级指针
	//p是一个指针,&p+1就是二级指针+1
	//&p是p的地址,&p+1就是p后面的地址
	//跳过p之后的地址
	

	printf("%d\n", sizeof(&p[0] + 1));//4或者8
	//p[0]==*(p+0) 就是 a
	//&a就是p
	//a的地址+1,就是b的地址



	return 0;
}


int main()
{
	//"abcdef"是一个常量字符串
	char* p = "abcdef";//p是一个指针变量
	//里面放的是a的地址,p指向的是a


	printf("%d\n", strlen(p));//6
	//p里面是a的地址,遇到\0就停止

	printf("%d\n", strlen(p + 1));//5
	//p+1就是b的地址

	printf("%d\n", strlen(*p));//错误
	//*p就是'a',会构成非法访问,

	printf("%d\n", strlen(p[0]));//错误
	//p[0] == *(p+0)就是'a'
	//和上面一样会构成非法访问

	printf("%d\n", strlen(&p));//随机数
	//&p就是a的二级指针,就是从p处开始向后数计数
	//并不知道什么时候遇到\0

	printf("%d\n", strlen(&p + 1));//随机数
	//&p+1就是,跳过p地址开始向后访问,开始计数
	//也是不知道什么时候遇到\0

	printf("%d\n", strlen(&p[0] + 1));//5
	//&p[0]就是a的地址,+1就是b的地址



	return 0;
}

5,二维数组和sizeof


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

	printf("%d\n", sizeof(a));//48
	//这里的a就是整个数组,3*4*4

	printf("%d\n", sizeof(a[0][0]));//4
	//这个是第一行第一个元素,int类型的

	printf("%d\n", sizeof(a[0]));//16
	//a[0]就是第一行的数组名,sizeof(a[0]) 就是第一行的数组名单独放在sizeof内部,
	//计算的是第一行的大小
	//第一行元素,第一行有4个元素。

	printf("%d\n", sizeof(a[0] + 1));//4或者8
	//a[0]是第一行的数组名,但是+1就不是数组名单独放在sizeof内部
	//这里a[0]就是数组首元素的地址。就是第一行第一个元素的地址。
	//这里单独值的是第一行第二个数的地址。

	printf("%d\n", sizeof(*(a[0] + 1)));//4
	//上面分析道()里面的是第一行第二个元素的地址
	//*()就是第一行第二个元素。

	printf("%d\n", sizeof(a + 1));//4或者8
	//a表示首元素的地址,二维数组首元素就是第一行的地址(行指针)
	//a+1就是第二行的地址,

	printf("%d\n", sizeof(*(a + 1)));//16
	//上面说到()他是第二行1的地址,
	//*()就是第二行的所有元素。
	//这里*(a+1)->a[1]

	printf("%d\n", sizeof(&a[0] + 1));//4或者8
	//a[0]是第一行的数组名,&()取出的是第一行的地址
	//&a[0]+1 -> 就是函数第二行的地址

	printf("%d\n", sizeof(*(&a[0] + 1)));//16
	//上面讲到()就是第二行的地址,
	//*()就是第二行的所有元素

	printf("%d\n", sizeof(*a));//16
	//代表首元素的地址,第一行的地址
	//*()就是第一行的所有元素
	//*(a)->*(a+0)->a[0]
	
	printf("%d\n", sizeof(a[3]));//16
	//这里a[0]是第一行的数组名,a[1]是第二行的数组名
	//但是sizeof 不会去访问他的类型,
	//例如:sizeof(a)和sizeof(int),,a为int类型的数据
	// 
	//所以a[3]和a[0]的类型是一样的。




	return 0;
}



10. 指针练习题

练习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;
}
//答案:2,5

练习2:


#include<stdio.h>
struct Test
{//已知,结构体Test类型的变量大小是20个字节(x86环境)(32位)
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x10 00 00


int main()
{
	p = (struct Test*)0x100000;
	printf("%#p\n", p + 0x1);
	printf("%#p\n", (unsigned long)p + 0x1);//强制转换为一个整数了
	printf("%#p\n", (unsigned int*)p + 0x1);
	return 0;
}

//答案: //0x00100014
	    //0x00100001
		//0x00100004(x86环境/32位机)

练习3:


int main()
{
    int a[4] = { 1, 2, 3, 4 };

    int* ptr1 = (int*)(&a + 1);
    //&a为整个数组的地址+1跳过整个数组。
    //被强制转换位int*类型的 存入ptr1

    int* ptr2 = (int*)((int)a + 1);
    //首元素地址a先被强转位(int)是一个整数,
    //在被强转为int*类型的指针
    //这里要具体到每一个字节,(小端字节序存储)
    printf("%x,%x", ptr1[-1], *ptr2);
    //*(ptr1-1) 就是最后一个元素
    //*ptr2
    return 0;

}
//答案:4,2000000

练习4:


#include <stdio.h>
int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    //注意这里是(0,1)是逗号表达式
    int* p;
    p = a[0];
    //第一行的数组名,是首元素的地址
    printf("%d", p[0]);
    return 0;
}
//答案:1

练习5:


int main()
{
    int a[5][5];
    int(*p)[4];//这个是一维数组指针

    p = a;//
    //a是数组首元素的地址//也就是第一行的地址,a的类型应该是 int(*)[5]类型的。
    //但是这里的地址指向的数组长度是[4],

    printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    //这里两个结果都是-4
    //-4的补码是1111 1111 1111 1111 1111 1111 1111 1100
    //地址打印就是十六进制打印(X86环境下是地址4个字节)FFFFFFFC
    //整型打印就是-4
    return 0;
}
//答案:FFFFFFFC,-4

练习6:


int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    int* ptr1 = (int*)(&aa + 1);
    //&aa就是整个数组的地址,&aa+1就是跳过整个数组的地址,指向数组最后元素的后面的那个地址
    //(int*)就是强制类型转换。


    int* ptr2 = (int*)(*(aa + 1));
    //aa是数组首元素的地址,也就是第一行的地址,aa+1就是第二行的地址,
    //*(aa+1)就是指向第二行的元素,数组名也能代表整个元素,也就相当于数组名
    //强制类型转化为(int*)类型的


    printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    //ptr1-1就指向了最后一个元素,
    //ptr2-1指向第一行最后一个元素。

    return 0;
}
//答案:10,5

练习7:

#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	//这是一个字符串首字符的地址数组,里面的每一个元素就是字符串首字母的地址。
	//a数组有三个元素,分别存了w,a,a的地址。
	char** pa = a;
	//a是数组首元素的地址,char*类型,
	//pa是a的地址,char**类型

	pa++;
	//pa++,就a++,就是第二个元素。
	//就a的地址,打印出来就是at

	printf("%s\n", *pa);

	return 0;
}

//答案为:at

练习8:


int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	//这是一个字符串首字符的地址数组,里面的每一个元素就是字符串首字母的地址。
	//a数组有四个元素,分别存了E,N,P, F的地址。

	char** cp[] = { c + 3,c + 2,c + 1,c };
	//
	char*** cpp = cp;
	//
	printf("%s\n", **++cpp);//POINT

	printf("%s\n", *-- * ++cpp + 3);//ER
	//这里的优先级++>--  那个+是最后计算的。

	printf("%s\n", *cpp[-2] + 3);//ST
	

	printf("%s\n", cpp[-1][-1] + 1);//EW
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
sizeofstrlenC语言中的两个不同的操作符,它们用于获取数据类型或字符串的大小。它们具有以下区别和用途: 1. sizeof操作符用于获取数据类型或变量的大小。对于数组,sizeof返回整个数组的内存大小。例如,对于一个整型数组a,sizeof(a)将返回整个数组所占用的内存大小。对于单个数组元素,可以使用sizeof(arr)来获取该元素的内存大小。对于指针变量,sizeof将返回指针本身的大小。 2. strlen函数用于获取字符串的长度,即字符串中字符的个数。它需要一个指向字符串的指针作为参数,并返回一个size_t类型的值,表示字符串的长度。例如,strlen("Hello")将返回5,因为字符串"Hello"由5个字符组成。需要注意的是,strlen只计算字符串中的字符个数,不包括字符串末尾的空字符('\0')。 下面是对练习中代码的解释: - sizeof(a)将返回整个数组a所占用的内存大小,因为a是一个整型数组,所以sizeof(a)的结果将是数组中所有元素所占用的总内存大小。 - sizeof(a)将返回数组a中第一个元素的内存大小,因为a是数组中的一个整型元素。 - sizeof(*a)将返回指针a所指向的元素的内存大小,因为a是一个指针,所以sizeof(*a)的结果将是指针所指向的元素的内存大小。 - sizeof(a)将返回数组a中第二个元素的内存大小,因为a是数组中的一个整型元素。 - sizeof(a)和sizeof(&a[1])将返回相同的结果,即数组a中第二个元素的内存大小。 - sizeof(&a)将返回指针&a的大小,因为&a是一个指向整个数组a的指针。 - sizeof(*&a)将返回指针&a所指向的元素的内存大小,即整个数组a的第一个元素的内存大小。 - sizeof(&a)将返回指针&a的大小,因为&a是一个指向数组a中第二个元素的指针。 - sizeof(&a)将返回指针&a的大小,因为&a是一个指向数组a中第一个元素的指针。 - sizeof(&a)将返回指针&a的大小,因为&a是一个指向数组a中第二个元素的指针。 综上所述,sizeof操作符用于获取数据类型或变量的大小,而strlen函数用于获取字符串的长度。它们在用途上有着明显的区别,需要根据具体的需求选择使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小峰同学&&&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值