嵌入式C:指针(一)

一、关于内存的相关概念

存储器:存储数据器件
外存
        外存又叫外部存储器,长期存放数据,掉电不丢失数据
        常见的外存设备:硬盘、flash、rom、u盘、光盘、磁带
内存
        内存又叫内部存储器,暂时存放数据,掉电数据丢失
        常见的内存设备:ram、DDR
        就是用来加载数据的
物理内存:
        实实在在存在的存储设备
虚拟内存:
        操作系统虚拟出来的内存,当一个进程被创建的时候,或者程序运行的时候都会
        分配虚拟内存,虚拟内存和物理内存之间存在映射关系。
        操作系统会在物理内存和虚拟内存之间做映射。
         在32位系统下,每个进程(运行着的程序)的寻址范围是4G,0x00 00 00 00 ~0xff ff ff ff
在写应用程序的,咱们看到的都是虚拟地址。
        在运行程序的时候,操作系统会将 虚拟内存进行分区。
1.堆
        在动态申请内存的时候,在堆里开辟内存。
2.栈
        主要存放局部变量(在函数内部,或复合语句内部定义的变量)。
3.静态全局区
        (1):未初始化的静态全局区
                静态变量(定义的时候,前面加static修饰),或全局变量 ,没有初始化的,存在
此区
        (2):初始化的静态全局区
                全局变量、静态变量,赋过初值的,存放在此区
4.代码区
        存放程序的代码
5.文字常量区
        存放常量的。
        内存以字节为单位来存储数据的,咱们可以将程序中的虚拟寻址空间,看成一个很大的一维的字符数组

二、指针的相关概念

操作系统给每个存储单元分配了一个编号,从0x00 00 00 00 ~0xff ff ff ff
这个编号被称之为地址
指针就是地址
指针变量:是个变量,是个指针变量,即这个变量用来存放一个地址编号
在32位平台下,地址总线是32位的,所以地址是32位编号,所以指针变量是32位的即4个
字节。
注意:
1:无论什么类型的地址,都是存储单元的编号,在32位平台下都是4个字节,
即任何类型的指针变量都是4个字节大小
2:对应类型的指针变量,只能存放对应类型的变量的地址
举例:整型的指针变量,只能存放整型变量的地址
扩展
        字符变量 char ch; ch占1个字节,它有一个地址编号,这个地址编号就是ch的地址
        整型变量 int a; a占4个字节,它占有4个字节的存储单元,有4个地址编号。
        Int a=0x00 00 23 4f;

三、指针的定义方法

1.简单的指针
数据类型 * 指针变量名;
int * p;//定义了一个指针变量p
在定义指针变量的时候 * 是用来修饰变量的,说明变量p是个指针变量。
变量名是 p
2.关于指针的运算符
& 取地址 、 *取值 &:
        获取一个变量的地址
*:
        在定义一个指针变量时,起到标识作用,标识定义的是一个指针变量
除此之外其他地方都表示获取一个指针变量保存的地址里面的内容

 

#include <stdio.h>

int main()
{
    //定义一个普通变量
    int a = 100;
    //定义一个指针变量
    int *p;

    //给指针变量赋值
    //将a的地址保存在p中
    p = &a;

    printf("a = %d %d\n", a, *p);
    printf("&a = %p %p\n", &a, p);

    return 0;
}

运行结果:

扩展:如果在一行中定义多个指针变量, 每个指针变量前面都需要加*来修饰
int *p,*q;//定义了两个整型的指针变量p和q
int * p,q;//定义了一个整型指针变量p,和整型的变量q
3、指针大小
在32位系统下,所有类型的指针都是4个字节
因为不管地址内的空间多大,但是地址编号的长度是一样的,所以在32位操作系统中,地
址都是四个字节

 

#include <stdio.h>

int main()
{
    char *a;
    short *b;
    int *c;
    long *d;
    float *e;
    double *f;

    printf("sizeof(a) = %d\n", sizeof(a));
    printf("sizeof(b) = %d\n", sizeof(b));
    printf("sizeof(c) = %d\n", sizeof(c));
    printf("sizeof(d) = %d\n", sizeof(d));
    printf("sizeof(e) = %d\n", sizeof(e));
    printf("sizeof(f) = %d\n", sizeof(f));

    return 0;
}

运行结果:

 

四、指针的分类

按指针指向的数据的类型来分
1:字符指针
字符型数据的地址
char *p;//定义了一个字符指针变量,只能存放字符型数据的地址编号
char ch;
p= &ch;
2:短整型指针
short int *p;//定义了一个短整型的指针变量p,只能存放短整型变量的地址
short int a;
p =&a;
3: 整型指针
int *p;//定义了一个整型的指针变量p,只能存放整型变量的地址
int a;
p =&a;
注:多字节变量,占多个存储单元,每个存储单元都有地址编号,
c语言规定,存储单元编号最小的那个编号,是多字节变量的地址编号。
4: 长整型指针
long int *p;//定义了一个长整型的指针变量p,只能存放长整型变量的地址
long int a;
p =&a;
5: float 型的指针
float *p;//定义了一个float型的指针变量p,只能存放float型变量的地址
float a;
p =&a;//double型的指针
double *p;//定义了一个double型的指针变量p,只能存放double型变量的地址
double a;
p =&a;
7:函数指针
8、结构体指针
9、指针的指针
10、数组指针
总结:无论什么类型的指针变量,在32位系统下,都是4个字节,只能存放对应类型的变量的
地址编号。

五、指针和变量的关系

指针可以存放变量的地址编号
在程序中,引用变量的方法
1:直接通过变量的名称
int a;
a=100;
2:可以通过指针变量来引用变量
int *p;//在定义的时候,*不是取值的意思,而是修饰的意思,修饰p是个指针变量
p=&a;//取a的地址给p赋值,p保存了a的地址,也可以说p指向了a
*p= 100;//在调用的时候*是取值的意思,*指针变量 等价于指针指向的变量
注:指针变量在定义的时候可以初始化
int a;
int *p=&a;//用a的地址,给p赋值,因为p是指针变量
指针就是用来存放变量的地址的。
*+指针变量 就相当于指针指向的变量
指针变量只能保存开辟好空间的地址,不能随意保存地址
#include <stdio.h>

int main(int argc, char *argv[])
{
    int *p1,*p2,temp,a,b;
    p1=&a;
    p2=&b;

    printf("请输入:a b的值:\n");
    scanf("%d %d", p1, p2);//给p1和p2指向的变量赋值

    temp = *p1; //用p1指向的变量(a)给temp赋值
    *p1 = *p2; //用p2指向的变量(b)给p1指向的变量(a)赋值
    *p2 = temp;//temp给p2指向的变量(b)赋值

    printf("a=%d b=%d\n",a,b);
    printf("*p1=%d *p2=%d\n",*p1,*p2);
    
    return 0;
}

 运行结果:

扩展:
对应类型的指针,只能保存对应类型数据的地址,
如果想让不同类型的指针相互赋值的时候,需要强制类型转换

 

#include <stdio.h>

int main()
{
    int a=0x1234,b=0x5678;
    char *p1,*p2;
    printf("%#x %#x\n",a,b);
    p1=(char *)&a;
    p2=(char *)&b;
    printf("%#x %#x\n",*p1,*p2);
    p1++;
    p2++;
    printf("%#x %#x\n",*p1,*p2);
    //这里就是因为地址存储的问题,以后会讲得到
    
    return 0;
}

运行结果:

注意:
1:*+指针 取值,取几个字节,由指针类型决定的指针为字符指针则取一个字节,
指针为整型指针则取4个字节,指针为double型指针则取8个字节。
2:指针++ 指向下个对应类型的数据
字符指针++ ,指向下个字符数据,指针存放的地址编号加1
整型指针++,指向下个整型数据,指针存放的地址编号加4

六、指针和数组元素之间的关系

6.1 数组元素与指针的基本关系
变量存放在内存中,有地址编号,咱们定义的数组,是多个相同类型的变量的集合,
每个变量都占内存空间,都有地址编号
指针变量当然可以存放数组元素的地址
int a[10];
//int *p =&a[0];
int *p;
p=&a[0]; //指针变量p保存了数组a中第0个元素的地址,即a[0]的地址
6.2 数组元素的引用方法
方法1: 数组名[下标]
int a[10];
a[2]=100;
方法2:指针名加下标
int a[10];
int *p;
p=a;
p[2]=100;//因为p和a等价
补充:c语言规定:数组的名字就是数组的首地址,即第0个元素的地址,是个常量。
注意:p和a的不同,p是指针变量,而a是个常量。所以可以用等号给p赋值,但不能给a赋
值。
例如:int a[10]; a++就是错误的,因为a是数组名是一个地址常量
方法3:通过指针运算加取值的方法来引用数组的元素
int a[10];
int *p;
p=a;
*(p+2)=100;//也是可以的,相当于a[2]=100 
解释:p是第0个元素的地址,p+2是 a[2]这个元素的地址。
对第二个元素的地址取值,即a[2]
#include <stdio.h>
int main()
{
    int a[5]={0,1,2,3,4};
    int *p;
    p=a;

    //只要将数组名赋值给同类型的指针变量,则此时的指针变量与数组名可
    //以用相同的方法操作数组
    printf("a[2]=%d\n",a[2]);
    printf("p[2]=%d\n",p[2]);

    //*(a + n) <==> *(p + n) <==> a[n] <==> p[n]
    printf("*(p+2) = %d\n",*(p+2));
    printf("*(a+2) = %d\n",*(a+2));
    
    printf("p=%p\n",p);
    printf("p+2=%p\n",p+2);
    printf("&a[0] = %p\n", &a[0]);
    printf("&a[2] = %p\n", &a[2]);
    return 0;
}

运行结果:

七、指针的运算

7.1 指针可以加一个整数
往下指几个它指向的变量,结果还是个地址
前提:指针指向数组的时候,加一个整数才有意义
//指针可以加一个整数,往下指几个它指向的变量,结果还是个地址
void test1()
{
    int a[10];
    int *p, *q;
    //p和q间隔8个字节,意味着加一个整数最终移动的字节数与指针变量的类型也有关系
    p = a;
    q = p + 2;

    printf("p = %p\n", p);
    printf("q = %p\n", q);

    return ;
}
int main()
{
    test()
    return 0;
}

运行结果:

7.2 两个相同类型指针可以比较大小
前提: 只有两个 相同类型的指针 指向 同一个数组的元素 的时候,比较大小才有意义
指向前面元素的指针 小于 指向后面 元素的指针

 

void test2()
{
    int a[10];
    int *p,*q;
    p=&a[1];
    q=&a[6];
    if(p<q)
    {
        printf("p < q\n");
    }
    else if(p>q)
    {
        printf("p > q\n");
    }
    else
    {
    printf("p = q\n");
    }
}
int main()
{
    test2();
    return 0;
}

运行结果:

7.3 两个相同类型的指针可以做减法
前提: 必须是 两个相同类型的指针 指向 同一个数组的元素 的时候,做减法才有意义
做减法的结果是,两个指针指向的中间有多少个元素

 

#include<stdio.h>
void test3()
{
    int a[10];
    int *p,*q;
    p=&a[0];
    q=&a[3];
    printf("%d\n",q‐p);
}
int main()
{
    test3();
    return 0;
}

运行结果:3

7.4 两个相同类型的指针可以相互赋值
注意:只有相同类型的指针才可以相互赋值(void *类型的除外)
#include<stdio.h>
void test4()
{
    int a = 100;
    int *p, *q;
    p = &a;

    printf("a = %d %d\n", a, *p);

    q = p;
    printf("*q = %d\n", *q);

    *q = 999;
    printf("a = %d\n", a);
}
int main()
{
    test4();
    return 0;
}

 运行结果:

八、指针数组

1、指针和数组的关系
1:指针可以保存数组元素的地址
2:可以定义一个数组,数组中有 若干个相同类型指针变量 ,这个数组被称为指针数组
指针数组的概念:
指针数组本身是个数组,是个指针数组 ,是若干个相同类型的指针变量构成的集合
注意:一般遇到这样的叠词,本质就是后者
2、指针数组的定义方法: 类型说明符 * 数组名 [元素个数];

 

int * p[10];//定义了一个整型的指针数组p,有10个元素p[0]~p[9],每个元素都是int*类型的变量
int a;
p[1]=&a;
int b[10];
p[2]=&b[3];
//p[2]、*(p+2)是等价的,都是指针数组中的第2个元素
3、指针数组的分类
字符指针数组char *p[10]、短整型指针数组、整型的指针数组、长整型的指针数组
float型的指针数组、double型的指针数组
结构体指针数组、函数指针数组
#include <stdio.h>

int main()
{
    //大多数情况下,指针数组都用来保存多个字符串
    char *name[5] = {"Follw me","BASIC","Greatwall","FORTRAN","Computer"};
    int i;
    for(i=0;i<5;i++)
    {
        printf("%s\n",name[i]);
    }

    return 0;
}

在这个示例中,char *name[5] 声明了一个包含5个元素的指针数组,每个元素都是一个指向字符的指针。然后,每个元素被初始化为不同的字符串常量。

通过循环遍历数组,可以逐个打印出存储在指针数组中的字符串。在循环中,printf("%s\n", name[i]) 语句会打印出第 i 个元素所指向的字符串。

这种使用指针数组存储多个字符串的方法在 C 语言中很常见,特别是在需要处理多个字符串时,通过指针数组可以方便地管理和访问这些字符串。在这个示例中,循环打印了数组中的每个字符串,分别输出了 "Follw me"、"BASIC"、"Greatwall"、"FORTRAN" 和 "Computer"。

运行结果:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值