C语言——高阶指针

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 指针的指针

数组

   inta[10];

int a[10]; //a代表的是数组首元素的地址a+1 步长 4&a+1 步长 40 ;&a代表整个数组的地址;指针也是一种数据类型,指针的步长就看他指向内存空间的类型; 所以内存空间加1就是地址偏移40

#define  _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>

#include <string.h>

#include <stdio.h>

voidmain(void)

{

   inta[10]; //a代表的是数组首元素的地址  &a代表整个数组的地址  a+1 4  &a+1步长 40 .

   //

   {

       //定义一个数组类型

       typedefint(myTypeArray)[10]; //

       myTypeArraymyArray;

       myArray[0] =10;

       myArray[1] =11;

       printf("%d \n", myArray[0]);

       printf("%d \n", myArray[1]);

   }

   {

       //定义一个指针数组类型

       typedefint(*PTypeArray)[10];  //int *p

       PTypeArraymyPArray; //sizeof(int) *10

       myPArray=&a;

       //int b = 10;

       //int *p = NULL;

       //p = &b;

       (*myPArray)[0] =20;

       printf("a[0]: %d \n", a[0]);

   }

   {

       //定义一个指向 数组类型的指针 数组类的指针

       int(*MyPointer)[10]; //变量 告诉C编译器 给我分配内存

       MyPointer=&a;

       (*MyPointer)[0] =40;

       printf("a[0]: %d \n", a[0]);

   }

   printf("hello...\n");

   system("pause");

   return;

}

1、为什么需要指针?

指针解决了一些编程中基本的问题。

第一,指针的使用使得不同区域的代码可以轻易的共享内存数据。当然你也可以通过数据的复制达到相同的效果,但是这样往往效率不太好,因为诸如结构体等大型数据,占用的字节数多,复制很消耗性能。但使用指针就可以很好的避免这个问题,因为任何类型的指针占用的字节数都是一样的(根据平台不同,有4字节或者8字节或者其他可能)。

第二,指针使得一些复杂的链接性的数据结构的构建成为可能,比如链表,链式二叉树等等。

第三,有些操作必须使用指针。如操作申请的堆内存。还有:C语言中的一切函数调用中,值传递都是“按值传递”的,如果我们要在函数中修改被传递过来的对象,就必须通过这个对象的指针来完成。

2、指针是什么?

指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。由于内存中的每一个字节都有一个唯一的编号,因此,在程序中使用的变量,常量,甚至数函数等数据,当他们被载入到内存中后,都有自己唯一的一个编号,这个编号就是这个数据的地址。指针就是这样形成的。

charch='a';

int  num=97;

我们可以大致画出变量ch和num在内存模型中的存储。(假设 char占1个字节,int占4字节)

3、指针与变量的关系

用来保存 指针 的变量,就是指针变量。如果指针变量p1保存了变量 num的地址,则就说:p1指向了变量num,也可以说p1指向了num所在的内存块 ,这种指向关系,在图中一般用 箭头表示。

intmain(void)

{

   intnum=97;

   int*p1  =&num;

   char*p2= (char*)(&num);

   printf("%d\n",*p1);    //输出  97

   putchar(*p2);          //输出  a

   return0;

}

指针的值:很好理解,如上面的num 变量 ,其地址的值就是0028FF40 ,因此 p1的值就是0028FF40。数据的地址用于在内存中定位和标识这个数据,因为任何2个内存不重叠的不同数据的地址都是不同的。

指针的类型:指针的类型决定了这个指针指向的内存的字节数并如何解释这些字节信息。一般指针变量的类型要和它指向的数据的类型匹配。

由于num的地址是0028FF40,因此p1 和 p2的值都是0028FF40

*p1 : 将从地址0028FF40 开始解析,因为p1是int类型指针,int占4字节,因此向后连续取4个字节,并将这4个字节的二进制数据解析为一个整数 97。

*p2 : 将从地址0028FF40 开始解析,因为p2是char类型指针,char占1字节,因此向后连续取1个字节,并将这1个字节的二进制数据解析为一个字符,即’a’。

同样的地址,因为指针的类型不同,对它指向的内存的解释就不同,得到的就是不同的数据。

4、指针类型

5、数组指针和指针数组

“数组指针”和“指针数组”,只要在名词中间加上“的”字,就知道中心了——

数组的指针:是一个指针,什么样的指针呢?指向数组的指针。

指针的数组:是一个数组,什么样的数组呢?装着指针的数组。

然后,需要明确一个优先级顺序:()>[]>*,所以:

(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;

*p[n]:根据优先级,先看[],则p是一个数组,再结合,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。

根据上面两个分析,可以看出,p是什么,则词组的中心词就是什么,即数组“指针”和指针“数组”。

int*p1[5]//指针的数组

int (*p2)[5]//数组的指针

首先,对于语句int* p1[5],因为“[]”的优先级要比 * 要高,所以 p1 先与“[]”结合,构成一个数组的定义,数组名为 p1,而“int”修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 5 个指向 int 类型数据的指针,如图 1 所示,因此,它是一个指针数组。其次,对于语句int ( p2)[5],“()”的优先级比“[]”高,“*”号和 p2 构成一个指针的定义,指针变量名为 p2,而 int 修饰的是数组的内容,即数组的每个元素。也就是说,p2 是一个指针,它指向一个包含 5 个 int 类型数据的数组,如图 2 所示。很显然,它是一个数组指针,数组在这里并没有名字,是个匿名数组。由此可见,对指针数组来说,首先它是一个数组,数组的元素都是指针,也就是说该数组存储的是指针,数组占多少个字节由数组本身决定;而对数组指针来说,首先它是一个指针,它指向一个数组,也就是说它是指向数组的指针,在 32 位系统下永远占 4 字节,至于它指向的数组占多少字节,这个不能够确定,要看具体情况。

5.1、 数组指针 (*p)[n]

#include "stdafx.h"

 

 

intmain()

{

   //一维数组

   inta[5] = { 1, 2, 3, 4, 5 };

   //步长为5的数组指针,即数组里有5个元素

   int (*p)[5];

   //把数组a的地址赋给p,则p为数组a的地址,则*p表示数组a本身

   p=&a;

 

   //%p输出地址, %d输出十进制

   //\n回车

   //在C中,在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址,它的类型取决于数组元素的类型。

   printf("%p\n", a); //输出数组名,一般用数组的首元素地址来标识一个数组,则输出数组首元素地址

   printf("%p\n", p); //根据上面,p为数组a的地址,输出数组a的地址

   printf("%p\n", *p); //*p表示数组a本身,一般用数组的首元素地址来标识一个数组

   printf("%p\n", &a[0]); //a[0]的地址

   printf("%p\n", &a[1]); //a[1]的地址

   printf("%p\n", p[0]); //数组首元素的地址

   printf("%d\n", **p); //*p为数组a本身,即为数组a首元素地址,则*(*p)为值,当*p为数组首元素地址时,**p表示首元素的值1

   printf("%d\n", *p[0]); //根据优先级,p[0] 表示首元素地址,则*p[0]表示首元素本身,即首元素的值1

   printf("%d\n", *p[1]); //为一个绝对值很大的负数,不表示a[1]...表示什么我还不知道

 

   

 

   //将二维数组赋给指针

   intb[3][4];

   int(*pp)[4]; //定义一个数组指针,指向含4个元素的一维数组

   pp=b; //将该二维数组的首地址赋给pp,也就是b[0]或&b[0],二维数组中pp=b和pp=&b[0]是等价的

   pp++; //pp=pp+1,该语句执行过后pp的指向从行b[0][]变为了行b[1][],pp=&b[1]

 

   intk;

   scanf_s("%d", &k);

 

   return0;

}

 

根据上面二维数组可以得出,数组指针也称指向一维数组的指针,所以数组指针也称行指针。

5.2、指针数组 *p[n]

指针数组:是数组——装着指针的数组。

看下面的例子进行理解:

数组指针:是指针——指向数组的指针。

看下面的例子进行理解

#include "stdafx.h"

 

 

intmain()

{

   inta=1;

   intb=2;

   int*p[2];

   p[0] =&a;

   p[1] =&b;

 

   printf("%p\n", p[0]); //a的地址

   printf("%p\n", &a); //a的地址

   printf("%p\n", p[1]); //b的地址

   printf("%p\n", &b); //b的地址

   printf("%d\n", *p[0]); //p[0]表示a的地址,则*p[0]表示a的值

   printf("%d\n", *p[1]); //p[1]表示b的地址,则*p[1]表示b的值

 

 

   //将二维数组赋给指针数组

   int*pp[3]; //一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2],所以要分别赋值

   intc[3][4];

   for (inti=0; i<3; i++)

       pp[i] =c[i];

 

   intk;

   scanf_s("%d", &k);

 

   return0;

}

 

最后,从上文来看:

数组指针是一个指针变量,占有内存中一个指针的存储空间;

指针数组是多个指针变量,以数组的形式存储在内存中,占有多个指针的存储空间。

6、举例1

typedefstruct

{

   unsignedshortad[3][5][100];

} photo_sample_data_stru;            

photo_sample_data_stru  *Photo_Sample_Read_Base_Point,Photo_Sample_Read_data ;

unsignedshortdata_0_0_x[100],data_0_1_x[100];

unsignedshort   *Photo_Sample_Point0,*Photo_Sample_Point1;

uint32_taddr;

voiddata_init(void)

{

   uint16_tPhoto_Sample_Line,photo_sample_time;

   for(Photo_Sample_Line=0;Photo_Sample_Line<5;Photo_Sample_Line++)

   {

       for(photo_sample_time=0;photo_sample_time<100;photo_sample_time++)

       {

           Photo_Sample_Read_Base_Point->ad[0][Photo_Sample_Line][photo_sample_time]=photo_sample_time; //第一路;

           Photo_Sample_Read_Base_Point->ad[1][Photo_Sample_Line][photo_sample_time]=photo_sample_time; //第二路;

           Photo_Sample_Read_Base_Point->ad[2][Photo_Sample_Line][photo_sample_time]=photo_sample_time; //第三路;

       }

   }

}

voidmain()

{

   intnum=2021;

   printf("num addr = 0x%x\r\n",(int)&num);

   printf("num  = %d\r\n",num);

   printf("\r\n");

   

   Photo_Sample_Read_Base_Point=&Photo_Sample_Read_data;

   data_init();

   printf("Photo_Sample_Read_Base_Point addr = 0x%x\r\n",(int)(Photo_Sample_Read_Base_Point));

   printf("Photo_Sample_Read_Base_Point  = %d\r\n",(int)(Photo_Sample_Read_Base_Point->ad[0][0][0]));

   printf("\r\n");

   

   

   Photo_Sample_Point0=Photo_Sample_Read_Base_Point->ad[0][0];

   printf("Photo_Sample_Point0 addr = 0x%x\r\n",(int)Photo_Sample_Point0);

   for( i=0;i<10;i++)

   {

       data_0_0_x[i]=Photo_Sample_Point0[i];

       printf("Photo_Sample_Point0[%d] = 0x%x \r\n",i,Photo_Sample_Point0[i]);

   }

   printf("\r\n");

   

   Photo_Sample_Point1=Photo_Sample_Read_Base_Point->ad[0][1];

   printf("Photo_Sample_Point1 addr = 0x%x\r\n",(int)Photo_Sample_Point1);

   for( i=0;i<10;i++)

   {

       printf("Photo_Sample_Point1[%d] = 0x%x\r\n",i,Photo_Sample_Point1[i]);

       data_0_1_x[i]=Photo_Sample_Point1[i];

   }

   printf("\r\n");

}

先看输出结果:

分析1:Photo_Sample_Read_Base_Point是指向Photo_Sample_Read_data的指针。Photo_Sample_Read_Base_Point地址是0x1000034C

分析2:Photo_Sample_Point0,Photo_Sample_Point1这两个指针,以及指针给数组赋值。Photo_Sample_Point0 addr = 0x1000034cPhoto_Sample_Point1 addr = 0x10000414

Photo_Sample_Point0[i] 实际为Photo_Sample_Read_data.ad[0][0][i]

Photo_Sample_Point1[i] 实际为Photo_Sample_Read_data.ad[0][1][i]

7、举例2:

typedef struct

{

unsigned char photo_ad_data[20][2];    

} photo_sample_stru;                      

photo_sample_stru         *photo_data_point[6];        

static photo_sample_stru   pmt_Data_Load[6];

static unsigned int Data_Loc_o;

static unsigned int Data_Loc_p;

void main()

{

for (Data_Loc_o=0;Data_Loc_o<6;Data_Loc_o++)  //  清空数据缓冲区  

{

photo_data_point[Data_Loc_o] =  &pmt_Data_Load[Data_Loc_o];

  //pmt_first =  photo_data_point[0];

for (Data_Loc_p=0;Data_Loc_p<20;Data_Loc_p++)                    

{

  photo_data_point[Data_Loc_o]->photo_ad_data[Data_Loc_p][0] = 0;

  photo_data_point[Data_Loc_o]->photo_ad_data[Data_Loc_p][1] = 0;

   

}

}

}

结果如下:分析: 我们下面看出,photo_sample_stru *photo_data_point[6]; 是指向photo_sample_stru 类型的 指针数组(即指针的数组)。利用指针把pmt_Data_Load里面数据清零。

8、举例3

#define MAX_SEG         100

#define MAX_CYCLE       10 //最大循环个数的宏定义


typedef  uint8_t UCHAR ;

typedef struct

{

  short           RunNow;                       //运行标志(正常开机,断电后重启)

  short           RunEnd;                       //运行结束标志

  short           FolderName[12];                //目录名

  short           FileName[12];                  //文件名

  short           SaveYear;                      //年(文件的保存时间)

  short           SaveMonth;                     //月(文件的保存时间)

  short           SaveDate;                      //日(文件的保存时间)

  short           SaveHour;                      //时(文件的保存时间)

  short           SaveMinute;                    //分(文件的保存时间)

  short           SaveSecond;                    //秒(文件的保存时间)

  short           HotlidSet;                      //热盖设置

  short           VolumeSet;                     //样本容量

  short           ModeSet;                       //运行的模式

  short           TestModeSet;                   //模拟模式

  short           FirstPause;                    //首节暂停

  short           EditSeg;                       //节点个数

  short           EditCycle;                     //循环个数

  short           TempSet[MAX_SEG];              //节点温度

  short           HourSet[MAX_SEG];              //节点时间---时

  short           MinuteSet[MAX_SEG];            //节点时间---分钟

  short           SecondSet[MAX_SEG];            //节点时间---秒

  short           SpeedSet[MAX_SEG];             //速度

  short           TempCYCSet[MAX_SEG];           //每个循环节点提升温度

  short           MinuteCYCSet[MAX_SEG];         //分――每个循环节点增加时间

  short           SecondCYCSet[MAX_SEG];         //秒――每个循环节点增加时间

  short           GradSet[MAX_SEG];              //梯度

  short           CycleSet[MAX_CYCLE];           //每个循环次数

  short           CycleBeginSet[MAX_CYCLE];      //循环开始节点

  short           CycleEndSet[MAX_CYCLE];        //循环终止节点

  short           GradExtSet[6][MAX_SEG];        //独立运行信息

  //short           AloneSet[MAX_SEG];             //分区设置

  short           TubeVolSet;                    //试管体积

  short           TubeTypeSet;                   //试管类型

  short           Fill[580];             //用于填充,结构总长度2Kwords

}StructFile;


typedef struct

{

   unsigned long    File_Add;//地址

   short   Seg;

   short   cyc_inside;

   short   cyc_outside;

   short   outside_flag;

   short   OverShootFlag;

   short   OverTime;

   short   Now_Temp;

}StructCalTime;


StructCalTime *Cal_Point;

StructCalTime Cal_TimeA;


void main()

{

uint8_t *u8_point;

u8_point = (uint8_t*)(&Cal_TimeA.File_Add);

for(uint16_t i=1;i<sizeof(StructCalTime);i++)

*(u8_point+i+4)=i;//赋值



Cal_TimeA.File_Add=(unsigned long)(&Cal_TimeA);//取地址

Cal_RunFile = *((StructFile*)(Cal_TimeA.File_Add));//重指向


// Cal_RunFile = *((StructFile*)((unsigned long)(&Cal_TimeA)));//直接赋值

}

目录
相关文章
|
16天前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
70 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
16天前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
44 9
|
16天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
40 7
|
26天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
92 13
|
19天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
19天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
61 3
|
20天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
19天前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
33 1
|
23天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
23天前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。