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

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

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


目录
相关文章
|
3天前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
3天前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
3天前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
2天前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
4天前
|
C语言
【C语言】:详解函数指针变量,函数指针数组及转移表
【C语言】:详解函数指针变量,函数指针数组及转移表
10 2
|
4天前
|
C语言
【C语言】:详解指针数组,数组指针及(二维)数组传参(2)
【C语言】:详解指针数组,数组指针及(二维)数组传参(2)
8 1
|
4天前
|
Serverless C语言
【C语言】:对(一维)数组与指针的深入理解(1)
【C语言】:对(一维)数组与指针的深入理解(1)
8 1
|
1天前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
6 0
|
1天前
|
存储 C语言
C语言中的多级指针、指针数组与数组指针
C语言中的多级指针、指针数组与数组指针
5 0
|
1天前
|
存储 C语言
C语言数组指针详解与应用
C语言数组指针详解与应用
8 0