一,指针定义:

1,讲解

指针变量用来记录地址数据,没有记录有效地址的指针变量不可以使用。

定义一个变量A和一个指针B,此时变量A存放在内存1000区间,将变量A赋值给指针变量B,此时指针变量B所接收到的并不是A的数值,而是A的内存区间地址1000。

int  data=200;
int *pp;
pp=&data;
printf("*pp=%d\n",*pp);
//------------------------
int num;
num=pp;
printf("num=%d\n",num);

指针变量可以用来表示捆绑的存储区。

指针也分类型,不同类型的指针适合记录不同类型存储区的地址

可以在一条语句里声明多个同类型的指针变量,每个指针变量名称前都应该加*号。

2,无效指针可以分成以下两种

(1)空指针里记录空地址(NULL),这个地址的数值就是数字0

(2)除了空指针以外的无效指针都叫做野指针

程序中禁止出现野指针,指针变量必须初始化。指针变量初始化的时候*没有参与赋值过。

3,指针定义

指针变量的取值范围取值0~4G,是一种数据类型(无符号整数,代表了内存编号)。它可以用来定义变量(与int、long一样),与int、long不同的它存储整数代表了内存的编号,通过这个变量可以访问对应编号的内存。

定义指针在变量名前名加上*即可:int a=10; int *b=a;

4,指针注意事项:空指针
变量指针的值等于NULL,这种指针叫空指针。不能对空指针解引用,一定会出现段错误。当操作重启时会跳转NULL地址,进行重启,因此NULL存储操作系统用于重启的数据。NULL在C语言中是一种错误标志,如果函数的返回值是指针类型,结果一旦NULL表示函数执行出错或失败。
 (1)如何避免空指针造成的段错误?

使用来历不明(函数的参数)的指针前先进行检查,if(NULL == p)。

(2)野指针:指针变量的值不确定,使用野指针不一定会出错。
int* p; // 野指针
使用野指针的后果:段错误。注意:野指针是无法分辨的,所以比空指针危害更。
如何避免野指针造成的错误?
所有的野指针都人制造出来的,只要人人都不制造野指针就会有野指针造成的错误。

定义指针变量时一定要初始化。不返回局部变量的地址。

指针变量所指向的内存初始释放后要及时赋值为空(堆内存)。

二,指针的作用

1、堆内存无法取名字(无法使用标识符与堆内存建立联系),必须配合指针。

2、函数之间的参数是值传递(内存拷贝),使用指针可以优化参数的传递效率(需要对变量进行保护)。因为C语言采用的是值传递(内存拷贝),会随着变量字节数的增加而降低运行效率而传递变量的地址永远只拷贝4或8字节。

void func(const int* p);但使用指针变量的值可能会被修改,可以配合const。

3、函数之间是相互独立的,有时协同配合需要共享变量(全局变量过多会造成命名冲突,不会被释放浪费内存),函数之间传递变量的地址可以达到共享变量的效果。

三,指针的好处:

(1)指针可以直接访问内存地址,可以提高效率

在讲解数组的时候说过,访问数组元素有两种访问形式,一种是下标法,一种是指针法。下标法其实是对指针法的一种封装。当使用下标法访问数组元素的时候,在程序运行的时候最后还是要转换成指针进行访问。所以直接使用指针访问效率会更高。

(2)在C语言中一些复杂的数据结构可以通过指针来实现。在C语言中的一些复杂结构,比如链表、树二叉树、红黑树等数据结构都是用指针进行构建。

(3)在C语言中函数传参是值传递的,函数的形参是不可以修改变量值,但是通过指针却可以。 函数传参是不可修改变量的值,但是指针就可以。

#include <stdio.h>  //运行结果(p)[0] =2
int main(void)
{int i = 0,j = 0;int array[3][2] = // 定义一个二维数组{{0,1},{2,3},{4,5},};int (*p)[2] = array; // 定义一个数组指针并指针二维数组的首地址p++;                 // 数组指针加1,表示指指针向下移动一行。printf("(p)[0] = %d\r\n",*(p)[0]);return 0;
}

四,指针的用法与举例:

1,指针定义:类型* 变量名_p;

#include <stdio.h>
int main(void)
{int *a;       // 定义整形指针变量int b = 10;   // 定义整形变量b a = &b;       // 将b变量的地址赋值给指针aprintf("*a = %d\r\n",*a);    // 打印出指针变量a的值printf("a  = 0x%x\r\n",a);  // 打印出指针变量a的地址printf("&b = 0x%x\r\n",&b); // 打印出变量b的地址return 0;
}

(1)指针变量与普通变量一样默认值不确定,一般初始化为NULL。

未初始化与非法指针:指针在定义时必须初始化,否则就会成为野指针

(2)指针变量的用法与普通变量不同,一般以p结尾加以区分。

(3)指针变量的类型决定了通过指针变量访问内存时访问几个字节。

(4)指针变量不能连续定义(一个*只能定义出一个指针变量):

int* p1,p2; // p是指针,p2是int类型变量

int *p1,*p2; // p1和p2都是指针变量

赋值:指针变量 = 内存编号。   变量名_p = 地址;

内存编号要能够访问,如果编号错误可能会造成段错误。void*可以与任意类型指针进行自动转换(C++中不行)。要保障地址与物理内存有对应关系(映射过),否则有段错误。

int* p = malloc(4);

int* p = # // 引用内存

访问:*指针变量 //解引用----访问指针变量

根据指针变量中存储的内存编号去访问对应的内存。如果之前赋值的内存编号有误,这个步骤会出现段错误。访问的字节由指针类型决定。     int* p = #                   *p <=> num;

#include<stdio.h>
#include<stdlib.h>
int main()
{int *p=(int *)malloc(sizeof(int)*5);//因为malloc函数的返回值为void*,所以需要强制类型转换为对应类型。if (p == NULL){printf("内存开辟失败\n");}else{printf("内存开辟成功\n");//使用指针for(int i=0;i<5;i++){*(p+i)=i+1;printf("*(p+%d)=%d\n",i,*(p+i));}//使用结束,释放内存(后面介绍)free(p);p = NULL;}
}

2,指针运算

指针变量中存储的就是整数,因此为整型数据能使用的运算符指针变量基本都能使用,但不是所有运算都有意义。
指针+整数 = 指针+宽度*整数
指针-整数 = 指针-宽度*整数 // 指针进行前后移动
指针-指针 = (指针-指针)/宽度 // 两个指针之间相隔多少个元素
指针 >、<、<=、>= 指针 可以判断两个谁在前谁在后。

#include<stdio.h>
int main()
{int brr[8]={8,7,6,5,4,3,2,1};int *p_num=brr;for(int i=0;i<8;i++){printf("*(p_num+%d)=%d\n",i,*(p_num+i));} double data=3.567;double *p_data=&data;printf("*p_data=%g\n",*p_data);//---------------------------------char *p[5]={"China", "Russia", "England", "France", "America"};for(int k=0;k<5;k++){printf("*(p+%d)=%s\n",k,*(p+k));printf("%s\n",p[k]);//p[k]  <----->  arr[k]  printf("%p\n",&p[k]); }
}

指针的运算:只允许两种方式,一种是指针自加或自减,一种是指针减指针。

#include <stdio.h>
int main(void)
{int array[] = {0,1,2,3,4};int *a = &array[3];printf("a* = %d\r\n",*a);a++;printf("a* = %d\r\n",*a);a--;printf("a* = %d\r\n",*a);return 0;
}

3,指针和数组名称的区别

.数组名就是个特殊的地址,也能当指针使用,数组名是个常量(数组名与数组第一个元素的首地址是对应关系,普通指针是指向关系)。数组名可以使用指针的解引用,而指针变量也可以使用数组的[];arr[i] <=> *(arr+i)。数组当函数的参数就脱变成了指针变量,长度丢失,安全性也变小void func(int * const arr,size_t len);

(1).数组名称不可以被赋值,指针可以被赋值

(2)对数组名称做sizeof计算和对指针做sizeof计算结果不同

(3)对数组名称取地址和对指针变量取地址结果不同

4,数组指针与指针数组:

(1)指针数组:指针数组存放的是指针变量,由多个指针变量结合成一个数组。指针数组的表现形式为char *p[10],根据C语言的优先级,p先跟[]结合,p[10]是一个数组,然后p[10]再跟*结合,变成了*p[10]的指针数组,根据前面的char类型,所以这个是一个存放char* 类型的指针数组。

数组指针(指针):专门用来指向数组的指针。
int arr[10];
int (*p)[10] = arr;
int* p = &num;

#include <stdio.h>
int main(void)
{int i = 0;char *p[] = {"hello world","123456","abcdefg",};for(i = 0;i < 3;i++){printf("p[%d] = %s\r\n",i,p[i]);}return 0;
}

(2).指针数组(数组):一个数组里存储的数据类型是指针。把无序的离散数据,归纳到一起。

数组指针的形式是int (*p)[2],根据优先级p先跟星号结合,变成*p,然后再跟[]结合,变成数组指针。数组指针它是一个指针,指向数组。数组指针通常用来访问一个二维数组。
int* arr[3]; <=> int *p1,*p2,*p3;

#include <stdio.h>  //运行结果(p)[0] =2
int main(void)
{int i = 0,j = 0;int array[3][2] = // 定义一个二维数组{{0,1},{2,3},{4,5},};int (*p)[2] = array; // 定义一个数组指针并指针二维数组的首地址p++;                 // 数组指针加1,表示指指针向下移动一行。printf("(p)[0] = %d\r\n",*(p)[0]);return 0;
}

5,函数指针和指针函数

(1)函数指针: 指向函数的指针(不能解引用)

指向函数的指针:在C语言中函数名代表该函数的首地址,既然函数有地址,那么也可以用指针来指向函数,这种指针叫做函数指针。

#include <stdio.h>
typedef void (*pfunc)(void); // 定义一个函数指针,类型为void ()(void)
void printf_fun(void)
{printf("hello world\r\n");
}
int main(void)
{pfunc pf = printf_fun; // 定义一个函数指针并指向一个函数printf("0x%x\r\n",printf_fun);printf("0x%x\r\n",pf);pf();  // 通过指针调用函数return 0;
}

int sum(int x,int y){return x+y;}  //定义一个函数
int main()
{
int a=5;int b=6;
int (*p)(int,int); //定义一个函数指针,(*p)()是函数指针的标志。
p=sum;             /*指针赋值,这个值就是指向的这个函数。这个和一般指针赋值有所区别,类似于数组名相当于首地址的意思,可以不用取址符&      函数名(SUM )本身有指向函数首地址指针的意义*/
int result=(*p)(a,b);
printf("The result is %d\n",result);
}

(2)指针函数:略

6,二级指针:指向指针的指针,用**p来表示

(1)二级指针可以用来记录指针存储区的地址,只能记录普通存储区地址的指针叫一级指针声明二级指针的时候需要写两个*

(2)在二级指针变量前加**可以表示捆绑的普通变量存储区或里面的数字。

在二级指针变量前加*可以表示捆绑的一级指针存储区或里面的地址数据。

单独使用二级指针变量名称可以表示二级指针本身的存储区或里面的地址数据。

(3)二级指针可以用来代表指针数组,但是不可以代表二维数组。

无类型指针有可能代表一级指针也可能代表二级指针。

二级指针作为函数的形式参数可以让被调用函数使用其他函数的指针类型存储

/*二级指针演示*/
#include <stdio.h>
int main(int argc, char **argv)
{int num = 0;for (num = 0;num <= argc - 1;num++) {printf("%s\n", *(argv + num));}return 0;
}

7,const 指针

跨函数使用存储区必须通过指针实现:数组做形式参数的时候真正的形式参数其实是一个指针。

(1)指针存储区可以用来存放函数的返回值

(2)可以采用这种做法让一个函数使用另外一个函数的静态局部变量存储区

(3)不可以把普通局部变量的地址作为返回值使用

(4)可以在声明指针变量的时候使用const关键字

(5)可以在声明指针变量的时候把const关键字写在最前边

(6)不可以通过这种指针对它捆绑的存储区进行赋值

所有用来实现跨函数使用存储区的指针都尽量用这种方法加const关键字。

可以在声明指针变量的时候在指针变量名称前加const关键字。

这种指针本身不可以被赋值,但是可以通过指针对它的捆绑存储区进行赋值。

声明指针变量时可以使用void作为类型名称这种指针叫做无类型指针,这种指针可以和任意类型存储区捆绑无法通过这种指针知道捆绑存储区的类型,不可以在这种指针前面直接加*也不可以用这种指针进行加减整数的计算。这种指针必须首先强制转换成有类型指针然后才能使用这种指针通常用来作为函数的形式参数。

  const int * p; // 不能通过解引用去修改指针所指向的内存的数据(1)保护函数的参数(2)当指针指向的是只读数据,也应该加上const防止出现段错误。int const * p; // 同上int* const p; // 不能修改指针变量的值,可以防止指针变量意外变成野指针const int* const p; // 既保存指针所指针的内存,也保护指针变量int const * const p; // 同上

运行:

*p_num=10
请输入一个数字:1
*p_num是1
*ptr=10

8, 结构体,和指针的区别

struct MyStruct
{
int a;
int b;
int c;
}MyStruct ss={20,30,40};//声明了结构对象ss,并把ss的三个成员初始化为20,30和40。
MyStruct *ptr=&ss;//声明了一个指向结构对象 ss的指针。类型是MyStruct*,它指向的类型是MyStruct。
int *pstr=(int*)&ss;//声明了一个指向结构对象 ss的指针。它的类型和它指向的类型和ptr是不同的。

A,问怎样通过指针ptr来访问ss的三个成员变量?答案:

ptr->a;

ptr->b;

ptr->c;

B,问怎样通过指针pstr来访问ss的三个成员变量?答案:

*pstr;//访问了ss的成员a。

*(pstr+1);//访问了ss的成员 b。

*(pstr+2)//访问了ss的成员c。

让我们看看怎样通过指针来访问数组的各个单元:

9,常量指针与变量指针:左数右指

const int* p; //p可变,p指向的内容不可变

int const* p; //p可变,p指向的内容不可变

int* const p; //p不可变,p指向的内容可变

const int* const p;//p和p指向的内容都不可变8,

五,用法实战

1,结构体里面的指针

typedef struct

{

float data[MTD_DATA_MAX];

//结果数据(复数)设置最大内存64*2?根据“结果数据的脉冲数”与“结果数据的距离数”动态申请内存?

int32_t doppler_index_scope[2];                 //多普勒序号

}mtd_param_packet_t;

typedef struct

{

float data[MTD_DATA_MAX];

float time;

int32_t index_scope[2];

}mtd_param_packet_t;

int point_process( const mtd_param_pool_t  *mtd_param_pool)

{

结构体指针定义:mtd_param_packet_t *mtd_data_packet_sum = NULL;

给指针赋值:mtd_data_packet_sum = (mtd_param_packet_t*)mtd_param_pool->sum_packet;

指针定义:float *mtd_data_sum = NULL;

给指针赋值:mtd_data_sum = (float*)mtd_data_packet_sum->data;

}

typedef struct
{radar_pl_cfg_t          pl_cfg;                         radar_ps_cfg_t          ps_cfg;radar_exe_cfg_t         exe_cfg;
}single_radar_param_t;typedef struct
{uint32_t    fsad;uint32_t    fsbb;
}single_wave_param_t;typedef struct
{single_radar_param_t        *current_radar_param_set;      single_wave_param_t         *current_wave_param_set;    pl_config_t                 *pl_time_line_config;
}process_param_t;process_param下面的结构体current_radar_param_set下面的ps_cfg:给指针赋值(加了取地址符号&,因为 radar_ps_cfg_t    ps_cfg这里是结构体定变量定义):radar_ps_cfg = (radar_ps_cfg_t*)&process_param->current_radar_param_set->ps_cfg;
给指针赋值(直接用(pl_time_line_config_t*)进行赋值,因为pl_config_t   *pl_time_line_config这里是指针定义):pl_time_line_config = (pl_config_t*)process_param->pl_time_line_config;

2,字符转义:把C0换成CC,DD;把CC换成CC AA

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define SRC_MAX_LEN (2*1024)
#define DEST_MAX_LEN (2*1024+2)int parsing(const unsigned char *src_data, int src_len, unsigned char *dest_data, int *dest_len)
{if(src_len > SRC_MAX_LEN){printf("[%s %d] 非法数据\n", __FUNCTION__, __LINE__);return -1;}int pos = 0;dest_data[pos++] = 0xCC;for(int i = 0; i < src_len; i++){if(0xC0 == src_data[i]){dest_data[pos++] = 0xCC;dest_data[pos++] = 0xDD;}else if(0xCC == src_data[i]){dest_data[pos++] = 0xCC;dest_data[pos++] = 0xAA;}else{dest_data[pos++] = src_data[i];}}dest_data[pos++] = 0xC0;*dest_len = pos;return 0;
}int main()
{unsigned char src_data[SRC_MAX_LEN] = {0x11, 0x22, 0xC0, 0x33, 0xDB, 0x44, 0xC0, 0xC0, 0xDB, 0xDB};int src_len = strlen(src_data);unsigned char *dest_data = NULL;int dest_len;dest_data = (unsigned char *)calloc(DEST_MAX_LEN, sizeof(unsigned char));parsing(src_data, src_len, dest_data, &dest_len);printf("src(长度:%d) ", src_len);for(int i = 0; i < src_len; i++){printf("%02x ", src_data[i]);}printf("\n");printf("dest(长度:%d) ", dest_len);for(int i = 0; i < dest_len; i++){printf("%02x ", dest_data[i]);}printf("\n");return 0;
}

3,字符反转义:把DB DC换成C0,把DB DD换成DB

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define SRC_MAX_LEN (2*1024)
#define DEST_MAX_LEN (2*1024+2)
int flag_dc=0,flag_dd=0;
int backparsing(const unsigned char *src_data, int src_len, unsigned char *dest_data, int *dest_len)
{if(src_len > SRC_MAX_LEN){printf("[%s %d] 非法数据\n", __FUNCTION__, __LINE__);return -1;}int pos = 0;if( (*src_data==0xC0) && ((*src_data+src_len-1)==0xC0)) ){for(int i = 0; i < src_len; i++){if((0xDB == src_data[i])&&(0xDC == src_data[i+1])){dest_data[pos++] = 0xC0;flag_dc=1;}else if((0xDB == src_data[i])&&(0xDD == src_data[i+1])){dest_data[pos++] = 0xDB;flag_dd=1;}else{if(flag_dc||flag_dd){flag_dc=0;flag_dd=0;}else{dest_data[pos++] = src_data[i];}      }}}else{printf("非法数据\n");}*dest_len = pos;return 0;
}int main()
{unsigned char src_data[SRC_MAX_LEN] = {0xc0,0x11, 0xdb, 0xdd, 0x33, 0xDB, 0xDC, 0x77, 0xC0, 0xDB, 0xDc,0x22,0xc0};int src_len = strlen(src_data);unsigned char *dest_data = NULL;int dest_len;dest_data = (unsigned char *)calloc(DEST_MAX_LEN, sizeof(unsigned char));printf("src(长度:%d) ", src_len);for(int i = 0; i < src_len; i++){printf("%02x ", src_data[i]);}printf("\n");backparsing(src_data, src_len, dest_data, &dest_len);printf("dest(长度:%d) ", dest_len);for(int i = 0; i < dest_len; i++){printf("%02x ", dest_data[i]);}printf("\n");return 0;
}

C语言指针用法完善篇相关推荐

  1. c语言指针用法及实际应用详解,通俗易懂超详细

    c语言指针用法及实际应用详解,通俗易懂超详细! \\\插播一条:文章末尾有惊喜哟~/// 今天给大家来讲解一下指针. 我会由浅到深,最后联合实际应用讲解,让大家学会指针的同时,知道大佬们都用指针来干嘛 ...

  2. c语言指针用法有哪些

    c语言指针用法: 一,指针定义: 指针变量的取值范围取值0~4G,是一种数据类型(无符号整数,代表了内存编号).它可以用来定义变量(与int.long一样),与int.long不同的它存储整数代表了内 ...

  3. c语言指针用法及实际应用详解,通俗易懂超详细!

    大家好,我是无际. 今天给大家来讲解一下指针. 我会由浅到深,最后结合实际应用讲解,让大家学会指针的同时,知道大佬们都用指针来干嘛! 长文预警!全文大约5200多字,学指针看这篇文章就够了! 很多人跟 ...

  4. C语言指针这一篇够了(一万二千字,包含指针与数组,函数指针等详解)

    目录 零.前言 一.指针的定义 二.指针类型的意义 1.指针类型决定了指针解引用时一次访问几个字节. 2.指针类型决定了指针加减整数时的步长 三.野指针 1.未初始化的指针 2.指针的越界访问 3.指 ...

  5. c语言---指针结构体篇

    [前言]本系列(初阶)适用于初学者课前预习或者课后复习资料,包含了大部分基础知识点梳理与代码例方便看官理解,有问题请指出.本人邮箱地址:p772307283@outlook.com 可爱捏 目录 1. ...

  6. c语言函数与指针,C语言指针与函数篇

    1:数组与指针 数组的定义与访问: int a[10]  /*定义10个变量的整形数组*/ float f[20] /*定义20个变量的浮点形数组*/ char s[5] /*定义5个变量的字符形数组 ...

  7. C语言指针面试题解析(万字超多题,每题都有详解)

    目录 零.前言 1.整型数组 2.字符数组 1.strlen函数 2.arr[]={'a','b','c'....}型 1.sizeof()计算 2.strlen()计算 3.char arr[]=& ...

  8. C语言入门之指针用法教程

    C语言入门之指针用法教程 这篇文章主要介绍了C语言入门之指针用法教程,主要对C语言中指针的本质及常见用法做了较为通俗易懂的分析,是后续深入学习C语言的基础,需要的朋友可以参考下 undefined u ...

  9. 关于C语言指针的用法

    近来有些时间,在开发过程中调试bug的时候,经常会遇到指针乱用或者,用了不free的现象,我这里写了个例子,把我的个人看法给有同样疑惑的朋友共勉,如果有错的地方,请指正,以一个人person为对象,展 ...

  10. c语言获取指针分配的字节数,c语言指针知识点总结(共6篇).docx

    c语言指针知识点总结(共6篇) C语言指针教学中的知识点分析与总结 摘要:分析指针的基本概念及指针在数组.函数.字符串.动态存储分配等方面的应用,提出指针教学过程中易混淆概念及注意事项,对初学者深入理 ...

最新文章

  1. 神经网络波动方程∂f(x)/ ∂x=f(-x)f(x)的另一组玻色子解
  2. 三十九、SPSS神器界面功能介绍,计算变量和个案计数和加权
  3. 判断目录是否存在并创建mkdir
  4. asp.net 之高速缓存
  5. JetBrains - IDEA 常用快捷键汇总
  6. 我对STL的一些看法(五)初识关联容器
  7. 锻炼编程能力的10个游戏:通关既巅峰!
  8. Mysql中default分区,MySQL中的分区(六)KEY分区
  9. 关于C语言中文件的基本操作
  10. Expected value at 1:0 异常解决方法
  11. 基于润和hi3516 dv300开发板,体验鸿蒙3.0 L1小型系统拍照Sample
  12. 最新!2021全球Top 1000计算机科学家h指数发布,中国53人上榜!Bengio总榜第二,韩家炜居华人首位...
  13. 阿里知产研究院报告:侵犯知识产权行为的罪与罚 | 湖畔新知汇
  14. mfc利用SQL、DAO调用access数据库
  15. python简易爬虫获取A股上证所有股票历史数据
  16. STM32-RCC的功能和使用
  17. 【Adapter模式】C++设计模式——适配器
  18. 梅姨一定想不到 中国人最爱的英国货竟然是一本童书
  19. 好文回顾:中国游戏编年史 中国游戏的二十年(5)
  20. 2020 java Mybatis 面试题及答案(最全版本持续更新)

热门文章

  1. 27个懒人正规快速赚钱项目
  2. 解决raise ValueError(Sample larger than population)问题
  3. P6364 1024 程序员节发橙子 ( 正序 反序遍历不降序 )
  4. php分页设计美化,国产PHP框架之ThinkPHP各模块开发系列十七,美化分页显示
  5. liveness探测mysql_Kubernetes 服务中 Liveness 和 Readiness 探测
  6. H3C S5820V2 MSR36-20
  7. 《改变心理学的40项研究》第二章 知觉与意识
  8. 视频素材-高质量缥缈雾气雾霾特效合成动画 Lens Distortions – Fog II
  9. 计算机系统运行太慢,电脑系统启动变慢是什么原因造成的以及解决方法
  10. python手机价格预测论文_基于Python的微博发表意向预测研究