指针的进阶【上篇】

简介: 指针的进阶【上篇】

📀1.字符指针

int main()
{
  char ch = 'w';
  char* pc = &ch;// pc就是字符指针
  char* p = "abcdef";// 把字符串首元素地址放在p中
  *p = 'w';
  return 0;
}

👉表达式的值是首元素的地址

👉但是这段代码运行起来会崩掉,调试看一下👇

48b41300b04a4dc6a8e76e8b8738af6e.png

👉因为这里的 “abcdef” 是常量字符串,不能被修改

int main()
{
  char arr[] = "abcdef";
  char* p = arr; // p指向的是arr数组首元素地址,arr数组是可以修改的
  *p = 'w';
  printf("%s\n", arr);// wbcdef
  return 0;
} 

4f112583d4c54424a0b159fd5b89d44d.png

这里就可以很好的运行,因为p指向的是arr数组首元素地址,arr数组是可以修改的

👉字符指针不仅仅可以指向字符,还可以指向字符串,但其实指向的还是字符串首字符,但是可以顺藤摸瓜找到整个字符串的字符,指向数组也是一样的


💡看一道例题👇

int main()
{
  char str1[] = "hello programming.";
  char str2[] = "hello programming.";
  const char* str3 = "hello programming.";
  const char* str4 = "hello programming.";
  if (str1 == str2)
    printf("str1 and str2 are same\n");
  else
    printf("str1 and str2 are not same\n");
  if(str3 == str4)
    printf("str3 and str4 are same\n");
  else
    printf("str3 and str4 are not same\n");
  return 0;
}

输出的两个结果分别是什么呢?

9592176e03c94875b6fc06ccc3c89b02.png

🔔这里str3和str4指向的是同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。


📀2.指针数组

👉类比一下:

字符数组 ---- 存放字符的数组

char arr1[10];

整型数组 ---- 存放整型的数组

int arr2[5];

指针数组 ---- 存放的就是指针

eg:存放字符指针的数组 ---- 字符指针数组

char* arr3[5];

eg:存放整型指针的数组 ---- 整形指针数组

int* arr4[6];

举个栗子🌰:

eg1:👇

int main()
{
  char* arr[] = { "abcdef","hehehe","666" };
  int i = 0;
  for (i = 0; i < 3; i++)
  {
    printf("%s\n", arr[i]);
  }
  return 0;
}

efcde9a5bd194902a9c833ec8c8b314b.png

eg2:👇

一维数组模拟一个二维数组

int main()
{
  int arr1[] = { 1,2,3,4,5 };
  int arr2[] = { 2,3,4,5,6 };
  int arr3[] = { 3,4,5,6,7 };
  //arr是一个存放整型指针的数组
  int* arr[] = { arr1,arr2,arr3 };
  int i = 0;
  for (i = 0; i < 3; i++) //行
  {
    int j = 0;
    for (j = 0; j < 5; j++) //列
    {
      printf("%d ", *(arr[i] + j));
    //  printf("%d ", arr[i][j]);
    }
    printf("\n");
  }
  return 0;
}

050b23ba4da54009b3292ee805e306b5.png


📀3.数组指针

💿3.1.数组指针的定义

👉类比一下:

整型指针 ---- 指向整型的指针

int a = 10;

int* p = &a;

字符指针 ---- 指向字符的指针

char ch = ’w‘;

char* pc = &ch;

数组指针 ---- 指向数组的指针 ---- 存放的是数组的地址

int arr[10];

int ( * pa)[10] = &arr; 取出的是数组的地址

char arr[10];

char ( * pc)[10] = &arr;

int* arr[5];

int * (*p)[5] = &arr;


💿3.2. &数组名VS数组名

💡数组名绝大部分情况下是数组首元素的地址

💡有两个例外:

1. sizeof (数组名)------ sizeof 内部单独放一个数组名的时候,数组名表示的是整个数组,计算得到的是数组的总大小

2. &arr ------ 这里的数组名表示整个数组,取出的是整个数组的地址,从地址值的的角度来讲,和数组首元素的地址是一样的,但是意义不一样

int main()
{
  int arr[10] = { 0 };
  printf("%p\n", sizeof(arr));
  printf("%p\n", arr);
  printf("%p\n", &arr[0]);
  printf("%p\n", &arr);
  return 0;

6ca3787aaa6849519362962d8316a92a.png

在看一下这段代码及解析👇

int main()
{
  int arr[10] = { 0 };
  //printf("%p\n", sizeof(arr));
  printf("%p\n", arr);//int*
  printf("%p\n", arr+1);//4
  printf("%p\n", &arr[0]);//int*
  printf("%p\n", &arr[0]+1);//4
  printf("%p\n", &arr);//int(*)[10]
  printf("%p\n", &arr+1);//40
  int(*p)[10] = &arr;//p是一个数组指针
   //int(*)[10]
  return 0;
}

d883160e7f394c21ae6ff833064548e1.png

👉根据第一段代码我们发现,其实 &arr 和 arr,虽然值是一样的,但是意义应该不一样的

👉实际上: &arr 表示的是数组的地址,而不是数组首元素的地址(细品)

👉第二段代码中 &arr 的类型是:int (*)[10],是一种数组指针类型,数组指针的地址+1,跳过整个数组大小, 所以&arr+1 相对于&arr 的差值是40


💿3.3.数组指针的使用

我们直接上代码和注释(请细品🍔)👇

int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  int i = 0;
  int sz = sizeof(arr) / sizeof(arr[0]);
  //使用指针来访问
  //int* p = arr;
  //for (i = 0; i < sz; i++)
  //{
  //  printf("%d ", *(p + i));
  //}
  int(*p)[10] = &arr;
  //p ---- &arr
  //*p ---- *&arr
  //*p ---- arr
  for (i = 0; i < sz; i++)
  {
    printf("%d ", *((*p) + i));
  }
  return 0;
}

a2bd0d6d617b452b855fe314d67131ee.png

//一维数组传参,形参是数组
void print(int arr[10], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
}
//一维数组传参,形参是指针
void print(int *arr, int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    //printf("%d ", arr[i]);
    printf("%d ", *(arr+i));
  }
  printf("\n");
}
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  print(arr, sz);
  return 0;
}

e8d501bbc96247b0b9e8ece4bcf45b55.png

void print(int arr[3][5], int r, int c)
{
  int i = 0;
  for (i = 0; i < r; i++)
  {
    int j = 0;
    for (j = 0; j < c; j++)
    {
      printf("%d ",arr[i][j]);
    }
    printf("\n");
  }
}
void print(int(*arr)[5], int r, int c)
{
  int i = 0;
  for (i = 0; i < r; i++)
  {
    int j = 0;
    for (j = 0; j < c; j++)
    {
      printf("%d ", *(*(arr + i) + j));//arr[i]
    }
    printf("\n");
  }
}
int main()
{
  int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
  //二维数组的数组名,也表示首元素地址
  //二维数组的首元素是第一行
  //首元素的地址就是第一行的地址,是一个一维数组的地址
  print(arr, 3, 5);
  return 0;
}

20579e71153e4222ab60790655b514f9.png

目录
相关文章
|
5月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
5月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
5月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
5月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
5月前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
5月前
|
搜索推荐
指针进阶(2)
指针进阶(2)
47 4
|
5月前
指针进阶(3)
指针进阶(3)
41 1
|
5月前
|
C++
指针进阶(1)
指针进阶(1)
43 1
|
5月前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
42 2
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
49 0