<笔试题>指针和数组

简介: 目录1、一维数组 1.1、整型数组 1.2、字符数组2、二维数组

1、一维数组

      1.1、整型数组

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

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


sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节

&数组名 - 数组名表示整个数组,取出的是数组的地址

除上面两种特殊情况外,所有的数组名表示数组首元素地址

再对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 版):image.png
#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版):

image.png

#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 版):image.png
#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版):image.png
#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 版):
1.
#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;
}
  • 画图解释:image.png

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;
}
相关文章
|
4天前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
9 1
|
13天前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
13天前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
13天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
19天前
魔法指针 之 二级指针 指针数组
魔法指针 之 二级指针 指针数组
15 1
|
22天前
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
16 0
|
28天前
|
编译器 C语言
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
|
3月前
|
搜索推荐 C语言
指针与数组
指针与数组
56 9
|
3月前
|
算法 Java
双指针在数组遍历中的应用
文章深入探讨了双指针技术在数组遍历中的应用,通过实战例子详细解释了快慢指针和首尾指针的不同用法,并提供了解决LeetCode相关问题的Java代码实现。
|
3月前
|
存储 程序员 C语言
指针的高级应用:指针数组、数组指针、函数指针等。
指针的高级应用:指针数组、数组指针、函数指针等。
97 0