C语言指针

一、指针简介

指针(Pointer)是C语言的一个重要知识点,其使用灵活、功能强大,是C语言的灵魂 指针与底层硬件联系紧密,使用指针可操作数据的地址,实现数据的间接访问

1.1计算机存储机制

位,字节

字节 byte 位 bit

位等价于比特(bit),同一个单位,最小的单位

1位=1比特;1字节=8位(两个16进制的数)在十六进制表示中,每个十六进制数字可以表示4个比特     1字=16位;1字=2字节

int a = 0x12345678;    /*int类型占4个字节*/

short b = 0x5A6B;/*short类型2个字节*/

char c[ ] = {0x33, 0x34, 0x35};/*char类型数据一个字节*/

补充:

小端分配(Little Endian)是一种数据存储方式,它将多字节数据类型的最低有效字节存储在内存的最低地址处,而最高有效字节存储在最高地址处。这种存储方式的名称源于计算机处理信息的方式与书写语言的差异。在西方书写中,我们习惯从左到右进行书写,而在计算机内部处理数据时,数据通常是从右到左进行处理的。因此,在小端分配中,数据的低位部分在存储器中的地址是比高位部分的地址更小的。

例如,对于一个 32 位整数变量,其值为 0x12345678,该变量在小端分配存储方式下的存储方式如下:

地址0x40000x40010x40020x4003
数据内容0x780x560x340x12

可以看到,在小端分配中,该变量的最低有效字节 0x78 存储在内存地址 0x4000 处,而最高有效字节 0x12 则存储在地址 0x4003 处。(高位高放,低位低放)右边为低,左边为高

注意:

变量定义的时候不分配地址,初始化的时候才给分配地址;

数组必须连续存储,若数组内部元素都跨字节,那么元素间顺序(大端)存,元素内按小端存

1.2定义指针

指针即指针变量,用于存放其他数据单元(变量/数组/结构体/函数等)的首地址。若指针存放了某个数据单元的首地址,则这个指针指向了这个数据单元,若指针存放的值是0,则这个指针为空指针

定义一个指针变量:

64位系统最多有 2^64个字节  所以变量最小宽度占8字节 64个位

#include<stdio.h>

int mian(void)
{
    int a;
    int *p,p1;  //p是一个指向int类型的指针变量;p1是一个整型

    printf("%d\n",sizeof(a));   //int 4  char 1
    printf("%d\n",sizeof(p));   //int 8  char 8

   //数据类型的大小和指针类型大小没有关系,指针类型大小与系统位数有关。所以int a是4位,int *p是8位
    
    
}

1.3指针的操作

#include <stdio.h>

int main(void)
{

    int a = 0x66;

    int *p;
    p = &a;
//   也可以写成 int *p = &a;
    
    printf("%x\n",a);   //66
    printf("%x\n",p);	//62fe47
    printf("%x\n",*p);	//66
    

    p++;
    printf("%x\n",p);	//62fe48(加了一个数据宽度,int为4字节)


    return 0;
}

1.4数组与指针

例:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{

    int *a;
    a = malloc(3*4);    <-----> //    char a[] = {0x33, 0x34, 0x35};
    *a = 0x33;
    *(a+1) = 0x34;
    *(a+2) = 0x35;
   
 //   char *p;
//    p = a;
    
    printf("a[0]=%x\n",a[0]);   //33   <--> printf("*p=%x\n",*p);
    printf("a[1]=%x\n",a[1]);	//34        printf("*(p+1)=%x\n",*p+1);右边说明数组名就是指针
    printf("a[2]=%x\n",a[2]);	//35        printf("*(p+2)=%x\n",*p+2);
    
    printf("*a=%x\n",*a);  		    //33
    printf("*(a+1)=%x\n",*(a+1));	//34
    printf("*(a+2)=%x\n",*(a+2));	//35
    
    return 0;
}

二、指针应用

 

2.1传递参数 

值传递(安全,但是占用内存)

#include <stdio.h>

void fun(int param)

{
    param=0x88;
    printf("%x\n",param);  //88
}

int main(void)
{
    int a = 0x66;

    fun(a);
    printf("%x\n",a);//66 形参不影响实参

    return 0;
}

指针传递(传递大容量的参数)此处子函数修改值会影响主函数,用const

#include <stdio.h>

int FindMax(const int *array,int Count)  //用const,只读
{
    int i;
    int max = array[0];
    for(i=1;i<Count;i++)
    {
        if(array[i]>max)
        {
            max = array[i];
        }
    }
    return max;
}

int main(void)
{
    int a[] = {1,2,3,5,4,3};
    int Max;
    Max = FindMax(a,6);
    printf("Max=%d\n",Max);
  
    return 0;
}

 

指针传递:(指针传递输出参数,可实现多返回值函数的设计)

 

#include <stdio.h>

void FindMaxAndCount(int *max,int *count,const int *array,int length)  //用const,只读
{
    int i;
    *max = array[0];
    *count = 1;
    for(i=1;i<length;i++)
    {
        if(array[i]>*max)
        {
            *max = array[i];
            *count = 1;
        }
        else if(array[i] == *max)
        {
            (*count)++;
        }
    }
 }

int main(void)
{
    int a[] = {1,2,5,5,4,3};
    int Max;
    int Count;
    FindMaxAndCount(&Max,&Count,a,6);
    printf("Max=%d\n",Max);		//5
    printf("Count=%d\n",Count);	//2
  
    return 0;
}

2.2 传递返回值

#include <stdio.h>

/****************/
int Time[]={23,59,55};
int *GetTime(void)//返回值是int*类型,即返回值就是整型指针类型
{
    return Time;
}
/****************/

int main(void)
{
    int *pt;//定义一个指针变量
    pt = GetTime();  //GetTime的返回值是Time的首地址,用pt指针接一下
    printf("pt[0]=%d\n",pt[0]);
    printf("pt[1]=%d\n",pt[1]);    
    printf("pt[2]=%d\n",pt[2]);
    
    return 0;
}

综合:

#include <stdio.h>

int main(void)
{
    //用指针传递参数和体现模块的“句柄”
//    FILE *f = fopen("F:\\test.txt","w");
//    fputc('A',f);	//在f写个字符A
//    fputs('HelloWorld!',f);	//在f写个HelloWorld!
    
    char a;
    char s[10];
    FILE *f = fopen("F:\\test.txt","r");
    
    a = fgetc(f);  //普通的值传递
    fgets(s,15,f); //返回的输出参数
    fclose(f);
    printf("%c",a);
    peintf(s);
    
    return 0;
}

2.3单片机中应用

1)访问硬件指定内存下的数据,如设备ID号等

#include <REGX52.H>
#include "LCD1602.h"

void main()
{
//	unsigned char *p;  //定义一个指针变量
    unsigned char code *p;  //定义一个指针变量(加code,访问程序存储空间)
    
    LCD_Init();
	LCD_ShowString(1,1,"Hello");
    
    //直接读取ID号存放的RAM区
//    p = (unsighed char *)0xF1;  //强制转换,跨级赋值
//    LCD_ShowHexNum(2,1,*p,2);//*p是取内容
//    LCD_ShowHexNum(2,3,*(p+1),2);
//    LCD_ShowHexNum(2,5,*(p+2),2);
//    LCD_ShowHexNum(2,7,*(p+3),2);
//    LCD_ShowHexNum(2,9,*(p+4),2);
//    LCD_ShowHexNum(2,11,*(p+5),2);
//    LCD_ShowHexNum(2,13,*(p+6),2);
    
    //ID号存放在程序的地址读取,加code访问程序存储空间
    p = (unsighne char code *)0x1FF9;  //强制转换
    LCD_ShowHexNum(2,1,*p,2);
    LCD_ShowHexNum(2,3,*(p+1),2);
    LCD_ShowHexNum(2,5,*(p+2),2);
    LCD_ShowHexNum(2,7,*(p+3),2);
    LCD_ShowHexNum(2,9,*(p+4),2);
    LCD_ShowHexNum(2,11,*(p+5),2);
    LCD_ShowHexNum(2,13,*(p+6),2);

	while(1)
	{

	}
}

 

2)将复杂格式的数据转换为字节,方便通信与存储

#include <stdio.h>

/****************************/
unsigned char AirData[20];
void SendData(const unsigned char *data, unsigned char count)
{
    unsigned char i;
    for(i=0;i<count;i++)
    {
        AirData[i]=data[i];
    }
}

void ReceiveData(unsigned char *data,unsigned char count)
{
     unsigned char i;
    for(i=0;i<count;i++)
    {
        data[i]=AirData[i];
    } 
}
/****************************/

int main(void)
{
   
    /*****************************/
    unsigned char i;
    unsigned char DataSend[]={0x12,0x34,0x56,0x78};
   
    SendData(DataSend,4);
    printf("\nAirData=");
    for(i=0;i<20;i++)
    {
        printf("%x ",AirData[i]);
    }  
    /*****************************/小数

     float num = 12.345;
     unsigned char *p;
     p = (unsigned char *)&num;
     SendData(p,4)


    unsigned char DataReceive[4];
    float *fp;
    ReceiveData(DataReceive,4);
    fp = (float *)DataReceive;//强制类型转换
    printf("\nnum=%f",*fp);
    /*****************************/
        
    return 0;
}

补充:结构体指针

结构体指针是指一个指向结构体的指针,它可以用于访问和修改结构体中的成员变量。在 C 语言中,结构体指针的定义和初始化形式如下:

struct person {
    char* name;
    int age;
};

struct person p; // 定义结构体变量
struct person *pp; // 定义结构体指针变量

pp = &p; // 将结构体指针变量设置为结构体变量的地址
pp->name = "Tom"; // 使用 -> 运算符访问结构体指针成员变量
pp->age = 20;

其中,&p 表示取结构体变量 p 的地址,pp 表示指向结构体 person 的指针,pp->name 表示访问结构体指针成员变量 namepp->age 表示访问结构体指针成员变量 age

另外,在定义结构体指针时,也可以在指针类型前加上关键字 typedef,以便更方便地使用结构体指针:



typedef struct {
    char* name;
    int age;
} person;

person p; // 定义结构体变量
person *pp = &p; // 定义结构体指针变量并初始化为结构体变量的地址
pp->name = "Tom"; // 访问结构体指针成员变量
pp->age = 20;

在这段代码中,person 是一个结构体类型别名,它等价于上面定义的 struct person。定义结构体变量时可以直接使用别名 person,定义结构体指针时也可以直接使用 person *

 

  • 26
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值