【进阶指针一】字符数组&数组指针&指针数组(上)

简介: 【进阶指针一】字符数组&数组指针&指针数组

1.初阶指针内容回顾


1.内存被划分为小的内存单元,每个内存单元都有一个编号,这个内存编号就是所谓的地址,也被叫做指针(内存编号=地址=指针)。


2.指针变量是一个变量,存放的是地址,地址能够唯一标识一块内存单元。


3.指针变量大小是固定的4/8个字节(32/64位平台上)。


4.指针变量类型决定了(1)指针在+-整数时的跳过多少个字节;(2)指针在解引用的时候访问的权限。


2.字符指针

2-1 字符指针长什么样?

int main()
{
    //代码一:
  char ch = 'a';
  char* p1 = &ch;
  printf("字符'a'的地址:>%p\n", p1);
  printf("对指针解引用得到的是指针指向的那个目标:>%c\n", *p1);
  printf("\n\n\n");
    //代码二:
  char* p2 = "hello world";
  printf("字符'h'的地址:>%p\n", p2);
  printf("对指针解引用得到的是指针指向的那个目标:>%c\n", *p2);
  printf("%s\n", p2);
  return 0;
}


a70e18a63f664f3cba822da703e9a079.png

2-2 误区:


误以为代码2中p2指针变量是存放着字符串,实际上p2所指向的是字符串"abcdef”中首个字符'a'的地址(原因有两点:1.指针变量在x86位(32位机器下)是4个字节,但是"abcdef“有7个字符,一个指针只能存放一个地址;2.通过指针解引用打印出'a'),同时因为字符串"abcdef"在内存(字符常量区)中的空间是连续的,所以只要拿到字符串首个元素'a'的地址就可以访问到整个字符串的内容。


2-3  代码一和代码二的异同:


1. 同:


(1)指针类型:p1和p2都是字符指针变量,都是存放的是字符a的地址。


(2)打印字符'a:打印出'a'都是通过拿到字符指针变量内存放的地址进行解引用,得到的都是指针变量所指向的那个变量。


2. 异


(1)字符'a'的存储位置:代码1中的'a'存放在栈区,代码2中的'a'存放在字符常量区(通过下方截图可以证明)


f2aa645d44b14b8a819dce269baf2604.png


2-4 关于字符常量区:


8af7a3bd1d434ec4900fcdd26101ebda.png

对于上图的解释3:


- 既然位于字符常量区的"abcdef"是不允许修改的


那么在p2指向这块内存空间的时候就会产生隐患,一旦通过解引用试图修改就会造成程序的运行时错误,程序瘫痪;


- 因此使用const修饰(也就是const char* p2="abcdef")来阻止对指针解引用试图修改的行为 ,及时给出编译时错误,程序压根编译不通过。


2-5 一道为了区分栈区和字符常量区&&字符数组和字符指针的面试题:


int main()
{
  const char* ptr1 = "abcdef";
  const char* ptr2 = "abcdef";
  char arr1[] = "abcdef";
  char arr2[] = "abcdef";
  if (ptr1 == ptr2)
  {
    printf("ptr1==ptr2\n");//bingo
  }
  else
  {
    printf("ptr1!=ptr2\n");//error
  }
  if (arr1 == arr2)
  {
    printf("arr1==arr2\n");//error
  }
  else
  {
    printf("arr1!=arr2\n");//bingo
  }
  return 0;
}

237514c5562d4271b0623bfd1a7d2348.png

23b8cbf0cba94265a26d70267b98876b.png

3.指针数组

其实下面要讲的指针数组和数组指针都是一种类型(类似整型,double,float)

3-1 指针数组长什么样捏?

//整型数组
int arr1[5]={1,2,3,4,5};//存放整型的数组
//字符数组
char arr2[5]={'a','b','c,''d','\0'};//存放字符的数组
//指针数组:指针是修饰,数组是名词,主角
int* arr3[5]={&arr1[0],&arr1[1],&arr1[2] ,&arr1[3] ,&arr1[4]};//存放指针的数组
//指针数组的意义:看着食之无味,弃之可惜
//实际上作用大着捏,我们指针数组的意义和普通数组的意义类似,
//都是对方便对相同类型元素(在这里的类型元素是指针)统一处理:比如修改和打印


3-2 初级使用(或者说给你看一下基本使用):

int main()
{
  //简单用法:
  int a = 10;
  int b = 20;
  int c = 30;
  //没有数组指针的情况
  int* p1 = &a;
  int* p2 = &b;
  int* p3 = &c;
  //有数组指针的情况
  int* arr[3] = { &a,&b,&c };
  for (int i = 0; i < 3; i++)
  {
    printf("%d\n", *(arr[i]));
  }
  return 0;
}

8944d4eda67c43a596462ea58655a47c.png


cf7fa4e436024a2694bfca5dd02c62e1.png

3-3这才是指针数组的正确使用方法!【指针数组模拟打印二维数组】

这和arr[3][5]的区别在于arr[3][5]在内存中中每一个元素的地址都是连续的,而指针数组模拟的二维数组这种方式的地址不是连续的。

int main()
{
  int arr1[5] = { 1,2,3,4,5 };
  int arr2[5] = { 2,3,4,5,6 };
  int arr3[5] = { 3,4,5,6,7 };
  int* arr[3] = { arr1,arr2,arr3 };
  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; j < 5; j++)
    {
            //printf("%d\t",arr[i][j]);//way1
            //printf("%d\t", *(arr[i] + j));//way2
              printf("%d\t",*(*(arr+i)+j);//way3
            //实际上way1和way2在编译器翻译过程中会自动转换为way3
    }
    printf("\n");
  }
  return 0;
}

a4802821b8c644658c5ff485fab53f21.png

c56f530348aa4c00a152f141a6f0e5cd.png


目录
相关文章
|
17天前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
30 3
|
16天前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
29 2
|
25天前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
29 1
|
1月前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
1月前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
1月前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
1月前
魔法指针 之 二级指针 指针数组
魔法指针 之 二级指针 指针数组
19 1
|
1月前
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
18 0
|
1月前
|
编译器 C语言
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
|
3月前
|
搜索推荐 C语言
指针与数组
指针与数组
59 9