<笔试题>指针和数组

目录

1、一维数组

       1.1、整型数组

       1.2、字符数组

2、二维数组


1、一维数组

       1.1、整型数组

  • 先对数组名有个简要认知:

      数组名是首元素地址,但是有两个例外

  1. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
  2. &数组名 - 数组名表示整个数组,取出的是数组的地址
  3.  除上面两种特殊情况外,所有的数组名表示数组首元素地址
  • 再对sizeof和strlen有个简要认知:
  • strlen:    是一个库函数,计算的是字符串的长度,并且只能针对字符串,关注的字符串中是否有\0,计算的是\0之前的字符个数。
  • sizeof:   是一个操作符(运算符),sizeof是用来计算变量所占内存空间的大小,任何类型都可以使用,只关注空间大小。
#include<stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));        //16 - 数组名a单独放在szieof内部 - 计算的是数组总大小 - 单位是字节 - 4*4=16
	printf("%d\n", sizeof(a + 0));    //4/8 - a表示的首元素的地址,a+0还是首元素地址,地址的大小就是(32位是4,64位是8)字节
	printf("%d\n", sizeof(*a));       //4 - a表示的首元素的地址,*a就是对首元素地址的解引用,*a就是首元素a[0],sizeof(*a)就是4字节
	printf("%d\n", sizeof(a + 1));    //4/8 - a表示的首元素的地址,a+1是第2个元素地址,地址的大小就是(32位是4,64位是8)字节
	printf("%d\n", sizeof(a[1]));     //4 - a[1]是数组第二个元素的大小,4字节
	printf("%d\n", sizeof(&a));       //4/8 - &a取出的是数组的地址,但是数组的地址也是地址,地址的大小就是(32位是4,64位是8)字节
	printf("%d\n", sizeof(*&a));      //16 - 可以理解为*和&抵消效果,*&a相当于a,sizeof(a)是16字节
    //本质理解:
    //&a -> int(*)[4]
    //&a是数组的地址,它的类型是int(*)[4]数组指针,如果解引用,访问的就是4个int的数组,大小是16个字节
	printf("%d\n", sizeof(&a + 1));   //4/8 - &a是数组地址,&a+1虽然地址跳过整个数组,但还是地址,所以是(32位是4,64位是8)字节,补充:&a到&a+1跳过了一个数组,a到a+1跳过了一个元素
	printf("%d\n", sizeof(&a[0]));    //4/8 - &a[0]就是第一个元素的地址(32位是4,64位是8)字节
	printf("%d\n", sizeof(&a[0] + 1));//4/8 - &a[0]就是第一个元素的地址,再+1就是第二个元素的地址(32位是4,64位是8)字节
	return 0;
}

       1.2、字符数组

  • 代码一:
  • 2.1(sizeof 版):

#include<stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));    //6 - arr作为数组名单独放在sizeof内部,计算的整个数组的大小,单位是字节,6字节
	printf("%d\n", sizeof(arr + 0));//4/8 - arr是首元素的地址,arr+0还是首元素的地址,地址的大小就是(32位是4,64位是8)字节
	printf("%d\n", sizeof(*arr));   //1 - arr是首元素地址,*arr就是首元素,首元素是一个字符,大小是1个字节
	printf("%d\n", sizeof(arr[1])); //1 - arr[1]相当于第二个元素的大小,是一个字符,大小就是1字节
	printf("%d\n", sizeof(&arr));   //4/8 - &arr虽然是数组的地址,但还是地址,地址的大小就是(32位是4,64位是8)字节
	printf("%d\n", sizeof(&arr + 1));//4/8 - &arr+1是跳过整个数组后的地址,但还是地址,地址的大小就是(32位是4,64位是8)字节
	printf("%d\n", sizeof(&arr[0] + 1));//4/8 - &arr[0]是第一个元素的地址,&arr[0]+1就是第二个元素的地址,地址的大小就是(32位是4,64位是8)字节
	return 0;
}
  • 2.2(strlen版):

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f'};
	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'的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突
	//printf("%d\n", strlen(arr[1]));//err 和上一个一样,内存访问冲突
	printf("%d\n", strlen(&arr));       //随机值  &arr是arr数组的地址,虽然类型和strlen的参数类型有所差异,但是传参过去后,还是从第一个字符的位置向后数字符,结果还是随机值
	printf("%d\n", strlen(&arr + 1));   //随机值-6 &arr是数组的地址,+1跳过整个数组,但是arr数组中没有\0,计算的时候就不知道什么时候停止
	printf("%d\n", strlen(&arr[0] + 1));//随机值-1 这里相当于从第二个字符的地址开始向后访问,又因为没有\0,所以还是随机值
	return 0;
}
  • 代码二:
  • 3.1(sizeof 版):

#include<stdio.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));        //7  sizeof(arr)计算的数组的大小,单位是字节
	printf("%d\n", sizeof(arr + 0));    //4/8  arr+0是首元素的地址,既然是地址,(32位是4,64位是8)字节
	printf("%d\n", sizeof(*arr));       //1   arr是首元素地址,首元素地址被解引用,*arr拿到的就是首元素,大小是1字节
	printf("%d\n", sizeof(arr[1]));     //1   arr[1]是第二个元素,sizeof(arr[1])计算的第二个元素的大小
	printf("%d\n", sizeof(&arr));       //4/8 &arr虽然是数组的地址,但也是地址,所以(32位是4,64位是8)字节
	printf("%d\n", sizeof(&arr + 1));   //4/8 &arr+1是跳过整个数组后的地址,但也是地址,(32位是4,64位是8)字节
	printf("%d\n", sizeof(&arr[0] + 1));//4/8 &arr[0]+1是第二个元素的地址,(32位是4,64位是8)字节
	return 0;
}
  • 3.2(strlen版):

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));       // 6  arr表示首元素地址,数到\0停下
	printf("%d\n", strlen(arr + 0));   // 6  arr表示首元素地址,+0还是首元素地址,数到\0停下
	//printf("%d\n", strlen(*arr));    //err strlen需要的是一个地址,从这个地址开始向后找字符, 直到\0,统计字符的个数。
    //但是*arr是数组的首元素,也就是'a',这是传给strlen的就是'a'的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突
	//printf("%d\n", strlen(arr[1]));  //err 理由同上
	printf("%d\n", strlen(&arr));      // 6  &arr表示取出的整个数组地址,但是整个数组的地址还是这个数组的起始地址,还是从起始元素数到\0停止
	printf("%d\n", strlen(&arr + 1));  //随机值  &arr表示取出的整个数组地址,+1表示跳过这整个数组,也跳过了原数组的\0,此时又找不到\0了,随机值
	printf("%d\n", strlen(&arr[0] + 1));//5  &arr[0]就是第一个元素的地址,+1就是第二个元素的地址,即从第二个元素开始数到\0停止
	return 0;
}
  • 代码三:
  • 4.1(sizeof 版):
#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", sizeof(p));        // 4/8  p是一个指针变量,sizeof(p)计算的就是指针变量的大小,(32位是4,64位是8)字节
	printf("%d\n", sizeof(p + 1));    // 4/8  p是指针变量,是存放地址的,p+1也是地址,(32位是4,64位是8)字节
	printf("%d\n", sizeof(*p));       // 1    p是char*的指针,解引用访问1个字节,sizeof(*p)是1字节,可理解为p[0]-->*(p+0)-->*p
	printf("%d\n", sizeof(p[0]));     // 1    p[0]-->*(p+0)-->*p
	printf("%d\n", sizeof(&p));       // 4/8  &p也是地址,(32位是4,64位是8)字节,&p是二级指针
	printf("%d\n", sizeof(&p + 1));   // 4/8  &p是地址,+1后还是地址,(32位是4,64位是8)字节,&p + 1,是p的地址+1,在内存中跳过p变量后的地址
	printf("%d\n", sizeof(&p[0] + 1));// 4/8  p[0]就是a,&p[0]就是a的地址,&p[0]+1就是b的地址,(32位是4,64位是8)字节
	return 0;
}
  • 4.2(strlen版):
#include<stdio.h>
#include<string.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));        // 6    p中存放的是'a'的地址,strlen(p)就是从'a'的位置向后求字符串的长度,长度是6
	printf("%d\n", strlen(p + 1));    // 5    p+1是'b'的地址,从b的位置开始求字符串长度是5
	//printf("%d\n", strlen(*p));     // err  strlen需要的是一个地址,从这个地址开始向后找字符, 直到\0,统计字符的个数。
    //但是*p是数组的首元素,也就是'a',这是传给strlen的就是'a'的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突
	//printf("%d\n", strlen(p[0]));   // err  理由同上
	printf("%d\n", strlen(&p));       // 随机值 p中存放的是'a'的地址,&p放的是p的地址,在p的地址中strlen找不到\0,所以随机值
	printf("%d\n", strlen(&p + 1));   // 随机值 理由类似上部
	printf("%d\n", strlen(&p[0] + 1));// 5    p[0] -> *(p+0) -> *p ->'a' ,&p[0]就是首字符的地址,&p[0]+1就是第二个字符的地址从第2 字符的位置向后数字符串,长度是5
	return 0;
}
  • 画图解释:

2、二维数组

#include<stdio.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));           //48  数组名单独放置sizeof内部,计算的是整个数组的大小,3*4*4=48字节
	printf("%d\n", sizeof(a[0][0]));     //4  a[0][0]表示第一行第一个元素的大小,类型是int,大小为4字节
	printf("%d\n", sizeof(a[0]));        //16  a[0]表示第一行的数组名,a[0]作为数组名单独放在sizeof内部,计算的是第一行数组的大小:16字节
	printf("%d\n", sizeof(a[0] + 1));    //4/8  a[0]作为第一行的数组名,没有&,没有单独放在sizeof内部,所以a[0]表示的就是首元素的地址,即a[0][0]的地址,a[0]+1就是第一行第二个元素的地址,(32位是4,64位是8)字节
	printf("%d\n", sizeof(*(a[0] + 1))); //4 既然解引用了,就是第一行第二个元素的大小4字节
	printf("%d\n", sizeof(a + 1));       //4/8  a是二维数组的数组名,没有&,没有单独放在sizeof内部,a表示首元素的地址,即第一行的地址,a+1就是第二行地址。(32位是4,64位是8)字节,是类型为int(*)[4]的数组指针。
	printf("%d\n", sizeof(*(a + 1)));    //16 *(a+1)就是第二行,相当于第二行的数组名,*(a+1)-->a[1],sizeof(*(a+1))计算的是第二行的大小,16字节
	printf("%d\n", sizeof(&a[0] + 1));   //4/8  a[0]是第一行的地址,&a[0]是第1行的地址,&a[0] + 1就是第二行的地址,(32位是4,64位是8)字节
	printf("%d\n", sizeof(*(&a[0] + 1)));//16 *(&a[0] + 1)就相当于第二行,也就是a[1],sizeof(a[1]),大小是16字节
	printf("%d\n", sizeof(*a));          //16 a二维数组的数组名,没有&,没有单独放在sizeof内部,a表示首元素的地址,*a就是二维数组的首元素,也就是第一行。*a-->*(a+0)-->a[0]
	printf("%d\n", sizeof(a[3]));        //16 感觉a[3]是越界了,但是没关系,依旧把它当成是求某行的大小,16字节
	return 0;
}

猜你喜欢

转载自blog.csdn.net/bit_zyx/article/details/122570258