指针进阶(一)上

简介: 指针进阶(一)

前言


指针的概念在之前的文章里已经讲解过了,其本质就是变量的地址。


  • 内存中的每个字节都会有自己的地址,每个字节的地址都能够用指针变量进行接收。
  • 指针变量的大小是4/8个字节,32位平台上占用4字节,64位平台上占用8个字节。
  • 指针变量是有类型的,指针变量的类型决定了指针±整数的步长,指针类型决定的指针变量的权限。
  • 相同类型的指针变量之间的减法运算的结果是:这两个指针指向的两个元素间的元素个数。(与高地址减去低地址还是低地址减去高地址无关)


eccda804bf5fe1303d3d5dc0672c6aa3_94713d344d444715ba3d2eef07c86ca8.png


1.字符指针


首先介绍字符指针,这是一种常见的使用方式:


int main()
{
  char ch = 'w';
  char* pc = &ch;
  *pc = 'h';
  return 0;
}

还有一种使用方式如下:


int main()
{
     const char* pstr = "hello bit.";
     printf("%p\n", pstr);
     printf("%p\n",pstr+1);
     return 0;
}


这里第3行代码是将整个字符串放到了pstr变量中了吗?并不是的。通过打印其地址,可观察到,pstr变量只是存放的字符串首字符的地址。


c1fcb2a615cb1a38b6608b6fe58da87b_af709d49a8bc49b1a6b4ee2fdf42c5ed.png


来个小测试吧:


//这段代码的运行结果是什么?
#include <stdio.h>
int main()
{
     char str1[] = "hello bit.";
     char str2[] = "hello bit.";
     const char *str3 = "hello bit.";
     const char *str4 = "hello bit.";
     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;
}


运行结果:


56dc974ddd96c20c888d7f3a1c7f2ea5_7b5cf3a3e74b424a87f6a2f13ec42760.png


原因分析:这里由于str1和str2都是数组,这两个数组无论其内容是否相同,只要成功被创建,都会在栈区开辟一块空间,由于这两个数组的开辟空间是独立的,所以其地址也是不同的,str1和str2分别存储这两个字符串的首地址,所以str1和str2的值不同。但是str3和str4是两个指针变量,他们都存储同一个字符串的首地址,内存中也没有必要为这个相同的常量字符串开辟两块空间,即C/C++会把常量字符串存储到单独的一个内存区域,所以str3和str4的值是一样的。


2.指针数组


所谓指针数组,本质上就是一个存放指针的数组。


char* arr[10];//存放一级字符指针的数组
int* arr[10];//存放一级整形指针的数组
char** arr[10];//存放二级字符指针的数组


3. 数组指针


数组指针本质上是指针。


int *pint;是指向int数据类型的指针


float *pf;是指向float类型的指针


那么数组指针就是指向数组的指针,存放数组的起始地址。


下面两个哪个是数组指针呢?


int (*parr)[10];


int *parr[10];


其中 int(*parr)[10];才是数组指针的正确写法。而 int *parr[10];这种写法,parr变量会先和[]结合,这样子parr变量就被翻译成了数组名了,明显不符合要求。


数组指针的写法说明:parr先和*结合,说明parr是个指针变量,接着去掉*parr这部分,剩下的部分就是该指针指向的元素的类型,指向有10个元素的整形数组。


注意:[]的结合性是高于*的,所以需要一个小括号保证变量名先与*结合。


4 &数组名和数组名的异同


对于所有的数组而言,数组名代表的是数组首元素的地址


int arr[10];


对于这个整型数组来讲,arr和&arr有什么区别呢?


先看一段代码:


#include <stdio.h>
int main()
{
 int arr[10] = {0};
 printf("%p\n", arr);
 printf("%p\n", &arr);
 return 0;
}


d2cd3b444737f51eea84efa5d4ec494a_962bdf0fbb7a45ad9575a51f9e176b29.png


可见运行结果是相同的,但是他们真的一样吗?

再来看一段代码:


#include <stdio.h>
int main()
{
     int arr[10] = { 0 };
     printf("arr = %p\n", arr);
     printf("&arr= %p\n", &arr);
     printf("arr+1 = %p\n", arr+1);
     printf("&arr+1= %p\n", &arr+1);
     return 0;
}


b1937b540c4438bd872baf2f69f5c0d4_24ce547ef53b4fbf8fbd3da92932785f.png


虽然这两个的值相同,但是他们的类型是不一样的,对其进行加减操作便可知晓。


arr是数组名,代表的是数组首元素的地址,也就是int数据类型的地址,即arr的类型是int*型,要用int*接收, int *p = arr;


&arr取出的是整个数组的地址,也就是int [10]的地址,即&arr的类型是 int(*)[10],要用int(*)[10]接收, int (*p)[10] = &arr;


d67e45dfff437f940b4ab675321e7af9_1f3c0b7d5bfe4efa8afbfd8edec0e28a.png


通过警告信息来看,=右边的类型是int(*)[10],可再次佐证我们的说法.


4.1 数组指针的用法


数组指针可以用于接收数组的地址,如下:


int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  int(*p)[10] = &arr;
  for (int i = 0; i < 10; i++)
  {
  printf("%d ",(*p)[i]);
  }
  return 0;
}

be9b4d9b4201eb61004c5386bc67989a_60804844244e4a5d981b5589eba2c6b4.png


但是一般不这样使用。通常利用数组指针接收二维数组传参:


void print(int(*p)[3],int col,int row)
{
  int i = 0;
  for (i = 0; i < col; i++)
  {
  int j = 0;
  for (j = 0; j < row; j++)
  {
    printf("%d ", p[i][j]);
  }
  printf("\n");
  }
}
int main()
{
  int arr[2][3] = {1,2,3,4,5,6};
  print(arr,2,3);
  return 0;
}


69f0ba43d5a3892c96b763af63ff14ee_cf9f779fda974fbea55da589d845a9df.png


我们通常可以将二维数组看做一维数组,这个一维数组的每个元素也是一个一维数组,那么就可以很好的解释上面这段代码了,主函数向print函数传参时,传递的是二维数组的数组名,这个数组名代表的二维数组首元素的地址,也就是一维数组的地址,那么在print函数的形参部分,可以选择使用二维数组接收,即 int arr[2][3];进行接收。也可以选择使用数组指针进行接收,即 int (*p)[3];进行接收。


这里[]内为什么写的是3而不是2呢?因为这里接收的一维数组的地址,该二维数组的每个元素都是含有三个元素的一维数组。


看看下面这段代码的含义吧


int arr[5];//整型数组
int *parr1[10];//整型指针数组
int (*parr2)[10];//整型数组指针
int (*parr3[10])[5];//整型数组指针数组


int (*parr2)[10];:先看变量名,先与*结合,说明parr2是个指针,接着将*parr2去掉,剩下的就是该指针指向的元素类型,即 int [10];即该指针指向一个含有10个元素的整型数组。


int (*parr3[10])[5];:先看parr3这个变量,它先于[]结合,说明parr3是个数组,将parr3[10]去掉,剩下部分就是数组元素类型,即 int(*)[5],所以数组的元素类型就是 int(*)[5];(整型指针数组)。


相关文章
|
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)
37 1
|
5月前
|
C++
指针进阶(1)
指针进阶(1)
42 1
|
5月前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
41 2
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
45 0