前言
发光不是太阳的权利你也可以,追逐光靠近光成为光散发光,你本来就是应该闪闪发光的人啊。看过前几篇文章都应该对数组和指针有些了解了吧,接下来我们用试题的方式来向各位展示让你更深的理解数组和指针这样就不怕难以区分啦~
提示:以下是本篇文章正文内容,下面案例可供参考
一、回顾数组和指针
数组和指针
数组 - 能够存放 - 一组相同类型元素,数组的大小取决于数组的元素个数和元素类型
指针 - 地址/指针变量,大小是4/8个字节
数组是数组,指针是指针,二者不等价
数组名是数组首元素地址,这个地址就可以存放在指针变量中
我们就可以使用指针来遍历数组
数组名大部分情况下是数组首元素地址
但有两个例外:
sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小
&数组名 - 数组名表示整个数组,取出的是数组的地址
二、数组例题
(1).整形类型
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//16
//sizeof(a)就是数组名单独放在sizeof内部,计算的是数组总大小,单位是字节
//4个元素int整形4个字节所以4*4=16
printf("%d\n", sizeof(a+0));//4/8
//这里sizeof(a+0)并不是数组名单独放在sizeof内部,尽管里面加0并没有加但是它也是加上了0同时也没有&数组名所以排除两个意外
//a是数组首元素地址,+0还是数组首元素地址,地址那就是4/8个字节
printf("%d\n", sizeof(*a));//4
//同理先看是不是例外中的其中一个显然不是所以a是首元素地址,也就是&a[0]
//*a -> *&a[0](&和*抵消) -> a[0]也就是数组首元素int类型每个元素都是4个字节
printf("%d\n", sizeof(a+1));//4/8
//a是数组首元素地址 -- int*类型的
//a+1 跳过一个整形,是第二个元素的地址,是地址那就是4/8个字节
printf("%d\n", sizeof(a[1]));//4
//a[1]也就是数组第二个元素int类型每个元素都是4个字节
printf("%d\n", sizeof(&a));//4/8
//&数组名 - 数组名表示整个数组,取出的是数组的地址
//&a取出的就是数组的地址,但数组的地址也是地址,是地址大小就是4/8个字节
//数组指针int(*pa)[4]=&a
printf("%d\n", sizeof(*&a));//16
//取地址(&)和解引用(*)可以抵用,所以sizeof(*&a) -> sizeof(a)
printf("%d\n", sizeof(&a+1));//4/8
//&a取出的是数组的地址+1跳过一个数组指向下一个数组的地址,所以还是地址也就是4/8个字节
printf("%d\n", sizeof(&a[0]));//4/8
//去除首元素地址也就是4/8
printf("%d\n", sizeof(&a[0]+1));//4/8
//第二个元素的地址所以4/8个字节
return 0;
//最后一定要分清&a和&a[0]是不同的一个是数组的地址一个是首元素地址所以+1跳过的一个是数组一个是元素但是都是地址所以都是4/8
}
(2).字符类型
sizeof计算的是占用内存空间的大小,单位是字节,不关注内存中到底存放的是什么,sizeof(arr) -> 6
sizoef不是函数是操作符
strlen是函数
strlen是针对字符串的求的是字符串的长度,本质上统计的是\0之前出现的字符的个数
#include<stdio.h>
int main()
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//6
//6个元素每个元素都是char类型的所以是6
printf("%d\n", sizeof(arr + 0));//4/8
//arr没有单独放在sizeof内部所以arr是数组首元素地址+0还是数组首元素地址,所以就是4/8个字节
printf("%d\n", sizeof(*arr));//1
//arr是数组首元素地址*arr就是首元素char类型所以就是1个字节
printf("%d\n", sizeof(arr[1]));//1
//数组第二个元素同理char类型所以也是1
printf("%d\n", sizeof(&arr));//4/8
//&arr取出数组的地址但也是地址所以4/8
printf("%d\n", sizeof(&arr + 1));//4/8
//&arr取出数组的地址+1跳过一个数组的地址但也是地址所以4 / 8
printf("%d\n", sizeof(&arr[0] + 1));//4/8
//第二个元素的地址
return 0;
}
注意这里是strlen不是sizeof所以不存在sizeof(数组名)
strlen求字符串长度把地址传给它它从那个地址开始往后数知道\0从而求出长度
#include<stdio.h>
int main()
{
int arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));//随机值
//strlen找到\0之前的个数但是这并不是一个字符串所以\0在哪未可知所以是随机值
printf("%d\n", strlen(arr + 0));//随机值
//arr首元素地址+0还是首元素地址所以还是从'a'开始往后数到\0所以还是随机值
printf("%d\n", strlen(*arr));//error
//*arr拿到的就是字符a,'a'本质上就是97,我们把97传给strlen,strlen就把97当成地址了开始往后数了
//但是97所找的这块内存不是我们的也就是所说的非法访问
printf("%d\n", strlen(arr[1]));//error
//arr[1]就是第二个元素也就是字符b,,我们把98传给strlen,strlen就把98当成地址了开始往后数了
但是98所找的这块内存不是我们的也就是所说的非法访问
printf("%d\n", strlen(&arr));//随机值
//虽然&arr取出的是数组的地址但是传给strlen还是从这个数组地址的首地址开始往后数知道\0所以就是随机值
printf("%d\n", strlen(&arr + 1));//随机值
//&arr+1就是跳过一个数组后的地址从这开始往后数直到到\0所以同样是随机值但是这个随机值比前面的随机值少6
//因为跳过了a,b,c,d,e,f
printf("%d\n", strlen(&arr[0] + 1));//随机值
//&arr[0]+1是从第二个字符也就是b的地址开始往后数,直到\0所以也是随机值比起之前的少1
return 0;
}
#include<stdio.h>
int main()
{
char arr[] = "abcdef";//这种是字符串最后位隐藏着放着一个\0
printf("%d\n", sizeof(arr));//7
//sizeof只关注数组的大小,里面隐藏着一个\0所以总共是7
printf("%d\n", sizeof(arr + 0));//4/8
//首元素地址+0还是首元素地址是地址就是4/8
printf("%d\n", sizeof(*arr));//1
//arr首元素地址,*arr就是首元素char类型就是1
//arr[0] *(arr+0)都是首元素
//int sz=sizeof(arr)/sizeof(*arr)这种也对
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
//指向的b的地址所以地址4/8
return 0;
}
注意这里是strlen不是sizeof所以不存在sizeof(数组名)
strlen求字符串长度把地址传给它它从那个地址开始往后数知道\0从而求出长度
#include<stdio.h>
int main()
{
char arr[] = "abcdef";//这种是字符串最后位隐藏着放着一个\0
printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr + 0));//6
//还是首元素地址开始往后数到\0总共6个字节
printf("%d\n", strlen(*arr));//error
//把a的地址给过去了
printf("%d\n", strlen(arr[1]));//error
//把b的地址给过去了
printf("%d\n", strlen(&arr));//6
//虽然取的整个数组的地址但是还是从数组首地址开始往后数到\0共6个
//&arr取出的是char(*)[7]类型;strlen的参数类型是const char*
printf("%d\n", strlen(&arr + 1));//随机值
//&arr+1是跳过一个数组开始往后数而后面的数据完全不可知所以是随机值
printf("%d\n", strlen(&arr[0] + 1));//5
//&arr[0]+1是从第二个元素的地址开始往后数到\0是5个
return 0;
}
三、指针例题
char* p = “abcdef”;常量字符串的首地址放在p里面去了;指针变量存放地址的
#include<stdio.h>
int main()
{
char* p = "abcdef";//常量字符串的首地址放在p里面去了;指针变量存放地址的
printf("%d\n", sizeof(p));//4/8
//我们算的是p变量的大小,p是一个变量,算的是一个指针变量的大小所以是4/8个字节
printf("%d\n", sizeof(p + 1));//4/8
//p里面放的是a的地址是char*指针+1跳过一个字符指向了b的地址所以是4/8
printf("%d\n", sizeof(*p));//1
//char*的指针对它解引用访问一个字符
printf("%d\n", sizeof(p[0]));//1
//p[0] -- *(p+0) -- 'a'所以是一个字节
//p里面存的a的地址解引用就是a
printf("%d\n", sizeof(&p));//4/8
//取地址p取得是p的地址和"abcdef"没有关系;&p是一个二级指针但还是地址所以同样4/8
printf("%d\n", sizeof(&p + 1));//4/8
//&p+1跳过一个p去但也是一个地址所以是4/8
//char* p; char** pp=&p; -- char*(这里旨在告诉我们pp指向的是一个char*类型的p) *pp(这里旨再告诉我们pp是一个指针)
printf("%d\n", sizeof(&p[0] + 1));//4/8
//p[0]就是a;&p[0]就是取出a的地址+1就是指向b的地址所以还是地址4/8
return 0;
}
&p+1跳过的是p变量的地址;而和数组没有关系,p变量是指针的话就是4个字节意思就是把这个4个字节的变量跳过去了
#include<stdio.h>
int main()
{
char* p = "abcdef";//常量字符串的首地址放在p里面去了
printf("%d\n", strlen(p));//6
//p里面放的a的地址所以从a开始往后数到\0;6个
printf("%d\n", strlen(p + 1));//5
//p里面放的a的地址+1指向b的地址所以从b开始往后数到\0;5个
printf("%d\n", strlen(*p));//error
//*p也就是a,同之前一样
printf("%d\n", strlen(p[0]));//error
//p[0]--*(p+0),同样是a
printf("%d\n", strlen(&p));//随机值
//&p取到的是p的地址至于p里面存的地址值是什么后面有没有遇到\0完全位置所以是随机值
printf("%d\n", strlen(&p + 1));//随机值
//同理p+1我们也不知道所以也是随机值;但是这个随机值和上面那个随机值没有半毛钱关系因为我们不知道有没有\0
//所以没有类似之前的少5少1的关系
printf("%d\n", strlen(&p[0] + 1));//5
//从b的地址向后数到\0也就是5个
return 0;
}
四、二维数组例题
(1).二维数组注意点一:
谈起二维数组我们就要来说一下数组名a[0] a[1] a[2]分别代表第一第二第三行的数组名
#include<stdio.h>
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//48
//二维数组数组名单独放在sizeof内部表示整个数组,计算整个数组的大小
//4*3*4=48
printf("%d\n", sizeof(a[0][0]));//4
//第一行第一个元素大小四个字节
printf("%d\n", sizeof(a[0]));//16
//a[0]第一行的数组名,这时数组名单独放在sizeof内部计算的是第一行数组的总大小
//4*4=16(一行四个元素)
printf("%d\n", sizeof(a[0]+1));//4/8
//这里是arr[0]+1所以不是单独放在sizeof内部所以a[0]只表示首元素的地址--第一行第一个元素的地址
//+1就是第一行第二个元素的地址 -- &a[0][1]所以是4/8
printf("%d\n", sizeof(*(a[0] + 1)));//4
//这个就是在上面的那个基础上加上*所以就是第一行第二个元素int类型4
printf("%d\n", sizeof(a + 1));//4/8
//a作为二维数组的数组名并没单独放在sizeof内部,所以表示首元素地址
//二维数组的首元素是第一行,所以这里的a就是第一行的地址 --- int(*)[4]
//a+1的时候是跳过第一行指向第二行的地址 --- &a[1]
printf("%d\n", sizeof(*(a+1)));//16
//同理这个同样是在上面代码的基础上解引用拿到的就是第二行的大小
//一行4个元素int类型$*4=16
//*(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
//同理在上面代码的基础上解引用得到的就是第二行
//4*4=16
printf("%d\n", sizeof(*a));//16
//*a,a没有单独放在sizeof内部所以表示首元素地址也就是第一行地址解引用也就是第一行元素
//4*4=16
//*a -- *(a+0) --- a[0]
printf("%d\n", sizeof(a[3]));//16
//数组下标从0开始这个数组总共就三行那是不是越界了呢
//答案是不是的因为sizeof并不会真的去访问只是计算所以这也是第四行的元素
//4*4=16
printf("%d\n", sizeof(*a+1));//4/8
//*a是第一行的元素+1---*a+1并没有单独放在sizeof内部所以*a---a[0]也就是第一行首元素地址
//+1也就是第一行第二个元素的地址
return 0;
}
(2).二维数组注意点二:
注意:
下面这段代码并没有越界
printf(“%d\n”, sizeof(a[3]));//16
数组下标从0开始这个数组总共就三行那是不是越界了呢
答案是不是的因为sizeof并不会真的去访问只是计算所以这也是第四行的元素;4*4=16
#include<stdio.h>
int main()
{
int a = 5;
short s = 11;
printf("%d\n", sizeof(s = a + 2));
//a和2都是int类型但计算结果要放到short类型里面所以会发生截断最终结果short说了算
//short的大小是2字节
printf("%d\n", s);
//按理来说s=a+2=7所以这里s打印出来是7但运行结果确实11没有改变为什么呢
//因为sizeof内部的表达式并没有真的计算
return 0;
}
总结
Ending,今天的指针和数组内容就到此结束啦~,如果后续想了解更多,就请关注我吧,在接下来的茫茫探索路上我们一起前进。