wordpress 群站,做网站需要ps吗,泰州模板建站源码,手工制作小汽车深入理解指针#xff08;5#xff09; 一、sizeof和strlen的对比1.1sizeof1.2strlen1.3sizeof和strlen的对比 二、数组和指针笔试题解析2.1 一维数组2.2 字符数组2.2.1代码1#xff1a;2.2.2代码2#xff1a;2.2.3代码3#xff1a;2.2.4代码4#xff1a;2.2.5代码5#… 深入理解指针5 一、sizeof和strlen的对比1.1sizeof1.2strlen1.3sizeof和strlen的对比 二、数组和指针笔试题解析2.1 一维数组2.2 字符数组2.2.1代码12.2.2代码22.2.3代码32.2.4代码42.2.5代码52.2.6代码6 2.3 二维数组 三、指针运算笔试题解析3.1题目13.2题目23.3题目33.4题目43.5题目53.6题目63.7题目7 四、总结1. sizeof与strlen的区别2. 数组和指针的关系3. 字符数组与字符串4. 指针运算总结 一、sizeof和strlen的对比
1.1sizeof
sizeof是单目操作符绝不是函数sizeof计算变量所占内存空间的大小的单位是字节。 如果操作数是类型的话计算的是使用类型创建的变量所占内存空间的大小。 注sizeof只关注占用内存空间的大小不在乎内存中存放什么数据。 比如 #inculde stdio.hint main(){int a 10;printf(%d\n, sizeof(a));printf(%d\n, sizeof a);printf(%d\n, sizeof(int));return 0;}1.2strlen
strlen是C语言库函数功能是求字符串长度。 函数原型是
size_t strlen ( const char * str );统计的是从strlen函数的参数str中这个地址开始向后\0之前字符串中字符的个数。 注strlen 函数会一直向后找 \0 字符直到找到为止所以可能存在越界查找。 代码如下
#include stdio.h
int main()
{char arr1[3] {a, b, c};char arr2[] abc;printf(%d\n, strlen(arr1));printf(%d\n, strlen(arr2));printf(%d\n, sizeof(arr1));printf(%d\n, sizeof(arr2));return 0;
}运行结果如下
1.3sizeof和strlen的对比
sizeofstrlen1.sizeof是操作符1.strlen是库函数使用需要包含头文件string.h2.sizeof计算操作数所占内存的大小单位是字节2.strlen是求字符串长度的统计的是\0之前字符的个数3.不关注内存中存放什么数据3.关注内存中是否有\0如果没有\0就会持续往后找可能会越界4.sizeof括号中有表达式的话表达式是不参与计算的
用代码检验4代码如下
#include stdio.h
int main()
{
int a 8;
short s 4;
printf(%d\n,sizeof(s a 2));//2
printf(%d\n,s);//4
return 0;
}运行结果如下 那么为什么sizeof中的表达式不计算 C语言是编译型语言在编译期这个表达式并不会被执行sizeof 运算的结果是在编译期间就已知的常数值并不需要等到运行时才求解。因此对于其中涉及到的操作数或者操作本身都不需要实际执行。
二、数组和指针笔试题解析
2.1 一维数组 *a a[0] *(a 0) 数组名的理解数组名是数组首元素第一个元素的地址。 但是有2个是例外1.sizeof(数组名) —— 数组名表示整个数组计算的是整个数组的大小单位是字节。 2.数组名 —— 数组名表示的是整个数组取出的是整个数组的地址。 除此之外所有的数组名是数组首元素第一个元素的地址。 笔试题代码和解析如下
#include stdio.h
int main()
{
int a[] {1,2,3,4};//数组有几个元素//4
printf(%zd\n,sizeof(a));//16
printf(%zd\n,sizeof(a 0));//a是首元素的地址 —— 类型是int*a 0还是首元素的地址是地址大小就是4/8。
printf(%zd\n,sizeof(*a));//a是首元素的地址*a是首元素大小就是4个字节。
printf(%zd\n,sizeof(a 1));//a是首元素地址类型是int*a 1跳过1个整型a 1就是第二个元素的地址是地址大小就是4/8。
printf(%zd\n,sizeof(a[1]));//a[1]就是第二个元素大小是4个字节。
printf(%zd\n,sizeof(a));//a是数组的地址数组的地址也是地址是地址大小就是4/8字节。
printf(%zd\n,sizeof(*a));//1.*互相抵消了等价于sizeof(a),16
//2.a是数组的地址类型是int(*)[4],对数组指针解引用访问的是数组计算的是数组的大小16
//char* —— 解引用访问的是char
//int* —— 解引用访问的是int
printf(%zd\n,sizeof(a 1));//a 1是跳过这个数组后的那个位置的地址是地址大小就是4/8字节。
printf(%zd\n,sizeof(a[0]));//首元素的地址大小就是4/8字节。
printf(%zd\n,sizeof(a[0] 1));//a[0] 1 —— 数组第二个元素的地址大小就是4/8字节。
return 0;
}运行结果如下图
2.2 字符数组
2.2.1代码1
笔试题代码和解析如下
#include stdio.h
int main()
{
char arr[] {a,b,c,d,e,f};
printf(%d\n,sizeof(arr));//数组名单独放在sizeof内部计算的是数组的大小单位为字节6。
printf(%d\n,sizeof(arr 0));//arr是数组名表示首元素的地址arr 0还是首元素的地址是地址就是4/8字节。
printf(%d\n,sizeof(*arr));//arr是首元素的地址*arr就是首元素大小就是1个字节。
//*arr arr[0] *(arr 0)
printf(%d\n,sizeof(arr[1]));//arr[1]是第二个元素大小也是1个字节。
printf(%d\n,sizeof(arr));//arr是数组的地址数组的地址也是地址是地址大小就是4/8个字节。
//arr —— char(*)[6]
printf(%d\n,sizeof(arr 1));//4/8个字节arr 1,跳过整个数组指向了数组后边的空间。
printf(%d\n,sizeof(arr[0] 1));//第二个元素的地址是地址就是4/8个字节。
return 0;
}运行结果如下图
2.2.2代码2
笔试题代码和解析如下
#include stdio.h
#include string.h
int main()
{
char arr[] {a,b,c,d,e,f};
printf(%d\n,strlen(arr));//arr是首元素的地址数组中没有\0就会导致越界访问结果就是随机的。
printf(%d\n,strlen(arr 0));//arr 0是数组首元素的地址数组中没有\0就会导致越界访问结果就是随机的。
printf(%d\n,strlen(*arr));//arr是首元素的地址*arr是首元素就是a,a的ASCII码值是97就相当于97作为地址传递给了strlenstrlen得到的就是野指针代码是有问题的。
printf(%d\n,strlen(arr[1]));//arr[1] —— b —— 98传给strlen函数也是错误的。
printf(%d\n,strlen(arr));//arr是数组的地址起始位置是数组的第一个元素的位置随机值。
printf(%d\n,strlen(arr 1));//随机值。
printf(%d\n,strlen(arr[0] 1));//从第二个元素开始向后统计的得到的也是随机值。
return 0;
}运行结果如下图
2.2.3代码3
笔试题代码和解析如下
#include stdio.h
int main()
{
char arr[] abcdef;
printf(%d\n,sizeof(arr));//7,计算的是数组总大小数组名单独放在sizeof内部。
printf(%d\n,sizeof(arr 0));//arr表示数组首元素的地址arr 0还是首元素的地址4/8字节。
printf(%d\n,sizeof(*arr));//arr表示数组首元素的地址*arr是首元素大小是1字节。
printf(%d\n,sizeof(arr[1]));//arr[1]是第二个元素大小是1个字节。
printf(%d\n,sizeof(arr));//arr是数组的地址是地址就是4/8字节。
printf(%d\n,sizeof(arr 1));//arr是数组的地址是地址就是4/8字节。
printf(%d\n,sizeof(arr[0] 1));//arr是数组的地址1跳过整个数组还是地址是地址就是4/8字节。
return 0;
}运行结果如下图
2.2.4代码4
笔试题代码和解析如下
#include stdio.h
#include string.h
int main()
{
char arr[] abcdef;
printf(%d\n,strlen(arr));//6
printf(%d\n,strlen(arr 0));//arr首元素的地址arr 0还是首元素的地址向后统计在\0之前的字符个数。//6
printf(%d\n,strlen(*arr));//a —— 97出错。
printf(%d\n,strlen(arr[1]));//b —— 98.出错。
printf(%d\n,strlen(arr));//arr是数组的地址也是从数组第一个元素开始向后找6。
printf(%d\n,strlen(arr 1));//随机值。
printf(%d\n,strlen(arr[0] 1));//5
//arr —— char(*)[7]
//size_t strlen(const char*s);
return 0;
}运行结果如下图
2.2.5代码5
笔试题代码和解析如下
#include stdio.h
int main()
{
const char*p abcdef;
printf(%d\n,sizeof(p));//p是指针变量我们计算的是指针变量的大小4/8个字节。
printf(%d\n,sizeof(p 1));//p 1是b的地址是地址大小就是4/8个字节。
printf(%d\n,sizeof(*p));//p的类型是char**p就是char类型了1个字节。
printf(%d\n,sizeof(p[0]));//1.p[0]-*(p 0)-*p-a,大小1个字节。
//1.把常量字符串想象成数组。
//2.p可以理解为数组名p[0],就是首元素。
printf(%d\n,sizeof(p));//取出的是p的地址地址的大小就是4/8个字节。
printf(%d\n,sizeof(p 1));//p 1是跳过p指针变量后的地址地址的大小是4/8个字节。
printf(%d\n,sizeof(p[0] 1));//4/8取出首元素的地址1是第二个字符的地址。
return 0;
}运行结果如下图
2.2.6代码6
笔试题代码和解析如下
#include stdio.h
#include string.h
int main()
{
char*p abcdef;
printf(%d\n,strlen(p));//6
printf(%d\n,strlen(p 1));//5
printf(%d\n,strlen(*p));//*p就是a —— 97err
printf(%d\n,strlen(p[0]));//p[0]-*(p 0)-*p//err
printf(%d\n,strlen(p));//p是指针变量p的地址和字符串“abcdef”关系就不大了从p这个指针变量的起始位置开始向后数的p变量存放的地址是什么不知道所以答案是随机值。
printf(%d\n,strlen(p 1));//随机值
printf(%d\n,strlen(p[0] 1));//5
return 0;
}运行结果如下图
2.3 二维数组
二维数组笔试题代码和解析如下
#include stdio.h
int main()
{
int a[3][4] {0};
printf(%d\n,sizeof(a));//a是数组名单独放在sizeof内部计算的是数组的大小单位是字节 —— 48 3*4*sizeof(int)。
printf(%d\n,sizeof(a[0][0]));//a[0][0]第一行第一个元素大小是4个字节。
printf(%d\n,sizeof(a[0]));//a[0]是第一行的数组名数组名单独放在sizeof内部了计算的是数组的总大小16个字节。
printf(%d\n,sizeof(a[0] 1));//a[0]并没有单独放在sizeof内部所以这里的数组名a[0]就是数组首元素的地址即a[0]-a[0][0],1后是a[0][1]的地址大小是4/8个字节。
printf(%d\n,sizeof(*(a[0] 1)));//第一行第一个元素大小是4
printf(%d\n,sizeof(a 1));//a作为数组名并没有单独放在sizeof内部a表示数组首元素的地址是二维数组首元素的地址也就是第一行的地址a 1跳过一行指向了第二行a 1是第二行的地址a 1是数组指针是地址大小就是4/8个字节。
printf(%d\n,sizeof(*(a 1)));//1.a 1是第二行的地址*(a 1)就是第二行计算的是第二行的大小 —— 16。2.*(a 1) a[1],a[1]是第二行的数组名sizeof(*(a 1))就相当于sizeof(a[1])意思就是把第二行的数组名单独放在sizeof内部计算的是第二行的大小。
printf(%d\n,sizeof(a[0] 1));//a[0]是第一行的数组名a[0]取出的就是数组的地址就是第一行的地址a[0] 1就是第二行的地址是地址大小就是4/8字节。
printf(%d\n,sizeof(*(a[0] 1)));//对第二行地址解引用访问的就是第二行大小是16个字节。
printf(%d\n,sizeof(*a));//a作为数组名并没有单独放在sizeof内部a表示数组首元素的地址是二维数组首元素的地址也就是第一行的地址*a就是第一行计算的就是第一行的大小16个字节。
printf(%d\n,sizeof(a[3]));//a[3]无需真实存在仅仅通过类型的推断就能算出长度a[3]是第四行的数组名单独放在sizeof内部计算第四行的大小16个字节。
//sizeof(int);//4
//sizeof(35);//4
return 0;
}运行结果如下图
三、指针运算笔试题解析
3.1题目1
指针运算笔试题代码和解析如下
#include stdio.h
int main()
{
int a[5] {1,2,3,4,5};
int*ptr (int*)(a 1);//a —— int(*)[5]
printf(%d %d,*(a 1),*(ptr - 1));//ptr跳过了原来a数组指向下一个位置*(ptr-1)访问的就是数组a中的5。
return 0;
}运行结果如下图
3.2题目2
在X86(32位)环境下假设结构体的大小是20个字节程序输出的结果是什么 指针运算笔试题代码和解析如下
#include stdio.h
struct Test
{
int Num;
char*PcName;
short sDate;
char cha[2];
short sBa[4];
}*p (struct Test*)0x100000;//结构体指针1跳过一个结构体整型值1就是1。
//指针-整数
int main()
{
printf(%p\n,p 0x1);//0x100000 20 - 00100014
printf(%p\n,(unsigned long)p 0x1);//0x100000 1 -0x100001 - 00100001
printf(%p\n,(unsigned int*)p 0x1);//0x100000 4 - 0x100004 - 00100004
return 0;
}运行结果如下图
3.3题目3
指针运算笔试题代码和解析如下
#include stdio.h
int main()
{
int a[3][2] {(0,1),(2,3),(4,5)};//1 3 5//初始化
int*p;
p a[0];//a[0][0];
printf(%d,p[0]);//1//*(p 0) - *p
return 0;
}运行结果如下图
3.4题目4
假设环境是X86环境程序的输出结果是什么 指针运算笔试题代码和解析如下
#include stdio.h
int main()
{//%d —— 是打印有符号的整数
//%p —— 是打印地址的
int a[5][5];//a —— 类型是int(*)[5]
int(*p)[4];//p —— 类型是int(*)[4]//p是一个数组指针p指向的数组是4个整型元素的
p a;//类型的差异 —— 警告
printf(%p,%d\n,p[4][2] - a[4][2],p[4][2] - a[4][2]);//FFFFFFFC,-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));
printf(%d %d,*(ptr1 - 1),*(ptr2 - 1));//10 5
return 0;
}
//*(aa 1)-aa[1],aa[1]是第二行的数组名数组名表示首元素的地址。
//aa[1]也是aa[1][0]
//*(aa 1)-aa[1],aa[1]-第二行的地址
//sizeof(aa[1])-计算的是第二行的大小运行结果如下图
3.6题目6
指针运算笔试题代码和解析如下
#include stdio.h
int main()
{
char*a[] {work,at,alibaba};//a是指针数组
char**pa a;
pa;
printf(%s\n,*pa);//at//%s是打印字符串给一个地址从这个地址向后打印字符串直到\0
return 0;
}画图分析
运行结果如下图
3.7题目7
指针运算笔试题代码和解析如下
#include stdio.h
int main()
{
char*c[] {ENTER,NEW,POINT,FIRST};
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);//**(cpp - 2) 3//ST
printf(%s\n,cpp[-1][-1] 1);//*c*(cpp-1) - 1//EW
return 0;
}运行结果如下图
四、总结
本文深入探讨了C语言中关于sizeof、strlen、数组和指针的一些基础概念并通过代码示例进行了详细的讲解。以下是对主要内容的总结
1. sizeof与strlen的区别
sizeof是一个运算符用于计算变量或类型所占的内存空间大小单位是字节。它与数据存储内容无关只关注内存的占用。例如sizeof(int)会返回一个整数类型的大小而sizeof(a)会返回数组a的总字节数。需要注意的是sizeof中的表达式不会被计算仅仅是编译时确定的常量。
与此不同strlen是C标准库中的一个函数用于计算以\0空字符结尾的字符串的长度。它统计的是字符串中的字符个数而不包括\0字符。因此strlen在处理字符串时必须确保字符串正确地以\0结尾否则可能导致越界访问。
2. 数组和指针的关系
数组和指针是C语言中常见的概念它们密切相关。数组名通常被认为是指向数组首元素的指针。通过数组名可以访问数组的元素但是数组名和指针在某些情况下也有所不同。例如sizeof(a)计算的是整个数组的大小而sizeof(a 1)计算的是数组中某个元素的指针大小。此外数组名也可以通过a表示整个数组的地址a[0]表示数组首元素的地址。
3. 字符数组与字符串
字符数组在内存中的存储方式可能导致不同的行为。在没有\0结尾的情况下使用strlen函数可能会导致越界访问进而产生随机结果。通过具体的代码示例文章展示了不同数组类型在使用sizeof和strlen时的差异特别是字符数组和字符串常量。
4. 指针运算
指针运算是C语言中强大的功能之一。指针可以进行加减操作指向内存中的不同位置。通过对数组指针进行运算可以访问数组中的不同元素。指针间的运算遵循指针类型的大小比如int*指针加1时会跳过一个int类型的大小指向下一个int类型的数据。文章通过一系列例子展示了指针和数组在内存中的操作包括指针的解引用、指针数组的运算等。
总结
本篇文章深入分析了sizeof、strlen、数组与指针等概念并通过一系列代码示例加深了对这些概念的理解。对于初学者来说掌握这些基础知识是学习C语言的关键。文章不仅揭示了这些基本概念的使用方法还通过具体例子帮助理解如何避免常见的错误如越界访问和指针运算中的误解。