嵌入式C语言学习——基于Linux与GCC(二)

系列文章目录

一.C语言常用关键字及运算符操作



内存四区

C/C++语言的内存四区(栈区,堆区,全局区,代码区)(附图详解)
在这里插入图片描述

指针

指针概述

指针:内存类型资源地址、门牌号的代名词
指针变量:存放指针这个概念的盒子/存放地址
C语言*p、p以及&p的区别

简单来说 “ * ”是解引用操作符 “ & ”是取地址运算符
p存放的是地址,而*p是让程序去p储存的那个地址中取出数据,&p就是取指针p的地址

补; 在C 语言中 * 号有三个用途,分别是:
1.乘号,用做乘法运算,例如5*6
2.申明一个指针,在定义指针变量时使用,例如int *p;
3.间接运算符,取得指针所指向的内存中的值,例如printf(“%d”,*p);

c语言编译器对指针这个特殊的概念,有两个疑问?
1.分配一个盒子,盒子要多大?
在32bit的系统中,指针就4个字节,(可以表示2^32个地址,4GB的内存空间)
2.盒子里存放的的地址,所指向的内存的读取方法是什么?
char *p 一次读取1字节,8bit
int *p; 一次读取4字节,32bit
在这里插入图片描述

eg1:
#include<stdio.h>
int main()
{
	int *p_1;
	int *p_2;
	printf("the p_1 is %u,the p_2 is %u",sizeof(p_1),sizeof(p_2))	
}
结果:the p_1 is 8,the p_2 is 8   (64位处理器,8字节)

p1 = 0x1122;在32位CPU中,这个地址是不合法的
指针指向内存空间,一定要保证合法性。

eg2:
#include<stdio.h>
int main()
{
        int a = 0x12345678;
        int *p_1;
        p_1 = &a; //a的首地址(低位地址)赋给 p_1
        printf("the p_1 is %x\n",*p_1);
}
结果:the p_1 is 12345678
eg3:
#include<stdio.h>
int main()
{
        int a = 0x12345678;
        int *p_1;
        p_1 = &a; //a的首地址(低位地址)赋给 p_1
        printf("the p_1 is %x\n",*p_1); //%x是16进制输出
}
结果:the p_1 is 78

0x12是高位
在这里插入图片描述
0x78是低位

#include<stdio.h>
int main()
{
        float a = 1.2;
        char *p_1;
        p_1 = &a;
        printf("the p_1 is %x\n",*p_1);
}

结果:the p_1 is ffffff9a //输出不是9a
修改:unsigned char *p_1 即可  //printf()把一些位当成了符号位

指针 + 修饰符

内存属性:
1.内存操作的大小
2.内存的可读可写性
指针指向的内存属性是什么?弄错会导致段错误。

const

常量、只读、不能变
char *p;

const char *p;     //地址指向的内存只读不可写,是字符串。并且注意地址是可变的。
char const *p;
char * const p;   //对固定地址进行读写,是硬件资源,地址固定,LCD
char *p const
const char * const p;    //地址和内容都不可变,对固定的地址只读,ROM
eg:
char *p = "hello world\n"; 编译器看到字符串默认是const型,空间只读不可写,字符串首地址给p
printf("the one is %x\n",*p);看字符串的第一个字符的ascii码
*p = 'a';  向p的地址指向的内存空间中进行写操作//会造成段错误、Segmentation fault、指针指向的内容被非法访问
printf("the %s\n",p);  //输出字符串

字符串是以地址的方式储存的,所以打印字符产只需要输入首地址,读到结束符\0结束

注:int printf(const char *format, ...);
上面例子第一行应该改为 const char *p = "hello world\n"
此时编译器会给出警告,并不会给出段错误。
char buf[] = {"hello world!\n"};  {}中的内容在静态区,只读不可写,但是将其值逐个赋给buf[],储存在可读写的区域。
char *p_2 = buf;//buf的首地址给p_2
*p_2 = 'a'; 将首地址中的内容改为'a'
printf("the %s\n",p_2);
结果:the aello world

volatile

防止优化指向内存地址
目的是去看硬件设备(eg:键盘)中的真实值,

volatile char *p;
while(*p == 0x10);
xxxx;

typedef

别名
char *p;
什么类型 变量名称;

char *name_t;     //name_t是一个指针,指向了一个char类型的内存
------
typedef char *name_t;  //name_t是一个指针类型的名称,指向了一个char类型的内存
name_t abc;

指针+运算符

+、-、++、–

指针的加法运算,实际上加的是一个单位,单位的大小可以使用sizeof()

 int *p =0x12;
 p+1 -->[0x12+1*(sizeof(*p)) ] -->0x16
 ---------------------------------------
 char *p =0x12;
  p+1 -->[0x12+1*(sizeof(*p)) ] -->0x13
p++ / p- -;  p 的地址自加1,并将新的地址更新到p
与p+1的区别:p+1只查看不更新

[ ]

变量名[n]
n:ID 标签
地址内容的标签访问方式

p+n 得到的是以p为基地址加n个单位得到的地址
p[n] 得到的是以p为基地址加n个单位得到的地址中的内容

#include<stdio.h>
int main()
{
        int a = 0x12345678;
        int b = 0x99991199;

        int *p1 = &b;
        char *p2 = (char *)&b;//强制类型转换

        printf("the p1+1,addr:%x,data:%x,data:%x,data:%x,data:%x\n",p1,*(p1+1),p1[0],p1[1],*p1+1,p1[10]);
        printf("the p2+1:%x\n",p2[1]);
}

结果:
the p1+1,add:881e7ae0,data:12345678,data:99991199,data;12345678,data:9999119a
the p2+1:11

上面例子说明定义的变量a、b的地址是有关系的,并且指针是可以越界访问的

多级指针

数组

数组空间

字符空间及地址

结构体、共用体

定义、字节对齐

位域

内存分布图

段错误分析

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值