目录
前言
随着深入的学习,数组的重要性也来越凸显出来,博主为了让初学者走出误区,专门写了这篇文章来给读者们阐述一下关于数组常见的几种误区、sizeof 和 strlen 的区别以及操作系统的内存地址占位 。
一、操作系统的内存地址都有哪些分别是什么?
16位操作系统的内存地址占用大小是16位,即2字节
32位操作系统的内存地址占用大小是32位,即4字节
64位操作系统的内存地址占用大小是64位,即8字节
128位操作系统的内存地址占用大小是128位,即16字节
(下面程序运行出来的结果是博主用64位操作系统的内存地址运行出来的)
二、sizeof 与 strlen 的区别
1、sizeof的用法
1). sizeof是操作符
2). sizeof不关注类型,只关注占用空间的大小,单位是字节
2、strlen的用法
1). strlen是函数,要包含头文件即:#include<string.h>
2). strlen关注的字符串中到 ‘\0’ 为止的字符,计算的是 ‘\0’ 之前出现了多少个字符
三、数组的常见应用
1、一维数组(sizeof和strlen的应用)
1)sizeof的应用
例1:(具体原因已在代码中表明)
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
//数组名单独放在sizeof()内部,计算的是整个数组的大小,单位是字节(Byte) --- 16
printf("%d\n", sizeof(*a));
//a表示的是首元素的地址,*a是对首元素地址的解引用,拿到的就是首元素,大小是4个字节
printf("%d\n", sizeof(a[1]));
//a[1]是数组的第二个元素,大小就是4个字节
printf("%d\n", sizeof(&a));
//&a表示的是数组的地址,但也是地址,地址大小8个字节
printf("%d\n", sizeof(*&a));
//可以理解为*和&抵消,*&a相当于a,sizeof(*&a) == sizeof(a)是16
//&a -> int(*)[4]
//&a是数组的地址它的类型是int(*)[4]数组指针,如是果解引用访问的是4个int的数组大小是16个字节Byte
printf("%d\n", sizeof(&a[0]));
//取出数组第一个元素的地址,是地址大小8个字节
printf("%d\n", sizeof(a + 0));
//a表示的是首元素的地址,a + 0 还是首元素地址,是地址大小8个字节
printf("%d\n", sizeof(a + 1));
//a + 1是第二个元素的地址,是地址,大小就是8个字节
printf("%d\n", sizeof(&a + 1));
//&a是数组的地址,&a + 1就是跳过整个数组后的地址,是地址大小8个字节
printf("%d\n", sizeof(&a[0] + 1));
//&arr[0] - int*,第二个元素的地址,是地址大小8个字节
return 0;
}
例1运行结果:
例2:
#include<stdio.h>
int main()
{
char arr[] = { 'a','b','c' };
printf("%d\n", sizeof(arr));
//arr作为数组名放在sizeof()内部,计算的整个数组的大小,单位是字节 --- 3
printf("%d\n", sizeof(*arr));
//arr是首元素地址,*arr就是首元素,是一个字符,大小是1个字节
printf("%d\n", sizeof(arr[1]));
//arr[1]是数组的第二个元素,是一个字符大小是1个字节
printf("%d\n", sizeof(&arr));
//&arr取出的是数组的地址,数组的地址也是地址,地址就是8个字节
printf("%d\n", sizeof(arr + 0));
//arr是首元素地址,arr + 0还是首元素的地址,地址大小就是8个字节
printf("%d\n", sizeof(&arr + 1));
//&arr取出的是数组的地址,&arr + 1跳过了整个数组,还是个地址,地址就是8个字节
printf("%d\n", sizeof(&arr[0] + 1));
//&arr[0]是第一个元素地址,&arr[0] + 1是第二个元素的地址,地址就是8个字节
return 0;
}
例2运行结果:
例3:
#include<stdio.h>
int main()
{
char* p = "abcd";
//p里面存的是a的地址
printf("%d\n", sizeof(p));
//p是一个指针变量,sizeof(p)计算的就是指针变量的大小,8个字节
printf("%d\n", sizeof(*p));
//p是char*的指针,解引用访问一个字节,sizeof(*p)是1个字节
printf("%d\n", sizeof(p[0]));
//p[0] --> *(p + 0) -- *p还是1个字节
printf("%d\n", sizeof(&p));
//&p也是地址,是地址就是8个字节 &p是二级指针
printf("%d\n", sizeof(p + 1));
//p是指针变量,是存放地址的,p + 1也是地址,地址大小就是8个字节
printf("%d\n", sizeof(&p + 1));
//&p是char**类型的 &p + 1还是地址,是地址8个字节
printf("%d\n", sizeof(&p[0] + 1));
//&p[0]就是a,&p[0]就是a的地址,&p[0] + 1就是b的地址,是地址就是8个字节
return 0;
}
例3运行结果:
2)strlen的应用
对于以下关于strlen的代码,博主为了让读者更加了解strlen的应用例举了很多情况,有的情况运行有错,在这博主就不给大家发运行截图了,感兴趣的小伙伴可以试试哦!
例1:(具体原因已在代码中表明,strlen的例子采用相邻两个比较容易理解)
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = { 'a','b','c','d' };
printf("%d\n", strlen(arr));
//arr是首元素地址,但是arr数组中没有\0,计算的时候不知道什么时候停止,结果是:随机值
printf("%d\n", strlen(arr + 0));
//arr是首元素地址,arr + 0还是首元素的地址,结果:是随机值
printf("%d\n", strlen(*arr));
//err,strlen需要的是一个地址,从这个地址开始向后找字符,直到\0统计字符的个数
//但是*arr表示的是数组首元素,也就是'a',这时传给strlen的是'a'的ASCLL码值97,strlen函数会把97作为起始地址
//统计字符串,会形成内存访问冲突
printf("%d\n", strlen(arr[1]));
//err 和上一个一样,内存访问冲突
printf("%d\n", strlen(&arr));
//&arr是arr数组的地址,虽然类型和strlen的参数类型有所差异,但是传参过去还是从第一个字符的位置
//向后数字符,结果还是随机值,因为没有 \0 ;
printf("%d\n", strlen(&arr + 1));
//随机值
printf("%d\n", strlen(&arr[0] + 1));
//随机值
return 0;
}
例2:
#include<stdio.h>
#include<string.h>
int main()
{
char* p = "abc";
//p里面存的是a的地址
printf("%d\n", strlen(p));
//p中存放的是'a'的地址,strlen(p)就是从'a'的位置向后求字符串的长度,长度是3
printf("%d\n", strlen(p + 1));
//p + 1是字符'b'的地址,从b的位置
printf("%d\n", strlen(*p));
//'a' - 97(ASCLL码)
printf("%d\n", strlen(p[0]));
//err p[0] -> *(p + 0) -> *p
printf("%d\n", strlen(&p));
//随机值
printf("%d\n", strlen(&p + 1));
//随机值
printf("%d\n", strlen(&p[0] + 1));
//&p[0] -> *(p + 0) -> *p -> 'a',&p[0]就是首字符的地址
//&p[0] + 1就是第二个字符的地址,从第二个字符的位置向后数字符串,长度是2
return 0;
}
2、二维数组
例:(具体原因已在代码中标明)
#include<stdio.h>
int main()
{
int a[4][4] = { 0 };
printf("%d\n", sizeof(a));
//数组名单独放在sizeof内部,计算的是整个数组的大小(int整形字节 * 行 * 列) --- 4*4*4 = 64
printf("%d\n", sizeof(a[0]));
//a[0]表示第一行的数组名,a[0]作为数组名单独放在sizeof内部,计算的是第一行大小 --- 16
printf("%d\n", sizeof(*a));
//a是二维数组的数组名,没有&,没有单独放在sizeof()内部,a表示首元素的地址。*a就是二维数组的首元素
//也就是第一行,*a -> *(a + 0) -> a[0] ---16
printf("%d\n", sizeof(a[3]));
//感觉a[3]是越界了,但是没关系,sizeof只看类型不会去访问,会去推导sizeof()内的类型 --- 16
printf("%d\n", sizeof(a[0][0]));
//4
printf("%d\n", sizeof(a[0] + 1));
//a[0]作为第一行数组名,没有&,没有单独放在sizeof()内部,
//所以a[0]表示的就是首元素地址,即a[0][0]的地址,a[0] + 1就是第一行第二个元素的地址,是地址就是8个字节
printf("%d\n", sizeof(*(a[0] + 1)));
//第一行第二个元素 --- 4
//二维数组的数组名是第一行数组的地址,类型是数组指针int(*)[]类型的
printf("%d\n", sizeof(a + 1));
//a是二维数组的数组名,没有&,没有单独放在sizeof()内部,a表示首元素地址
//即第一行地址,a + 1就是第二行的地址 a + 1 的类型是个数组指针int(*)[4],是地址就是8个字节
printf("%d\n", sizeof(*(a + 1)));
//*(a + 1)就是第二行,相当于第二行数组名,*(a + 1) -> a[1]就是第二行数组名
//sizeof(*(a + 1)) -> sizeof(a[1])计算的是第二行的大小 --- 16
printf("%d\n", sizeof(&a[0] + 1));
// &a[0]是第一行的地址, &a[0] + 1就是第二行的地址,是地址就是8个字节
printf("%d\n", sizeof(*(&a[0] + 1)));
//*(&a[0] + 1)就相当于第二行,也就是第二行的数组名a[1],sizeof(a[1]) --- 16个字节
return 0;
}
运行结果:
总结
以上就是今天要讲的内容,本文仅仅简单介绍了操作系统的内存地址都有哪些以及分类,还讲解了sizeof 与 strlen 的区别,最后博主还为大家总结了一些关于一维数组和二维数组的一些小情况方便读者们理解。如果有问题的话可以私信我或在评论区留言。
没问题的话觉得可以的话,还可以在评论区留下你的足迹哦!