网址:Linux嵌入式ARM开发教程第一阶段_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili https://www.bilibili.com/video/av15875305/?spm_id_from=333.788.videocard.1
-
指针: 指针概述
指针+修饰符 const、voliatile、typedef
指针+运算符
多级指针数组: 数组空间
字符空间及地址结构体、共用体: 定义、字节对齐
位域
内存分布图
段错误分析
1.指针概述
内存类型资源地址、门牌号的代名词
指针
指针变量:存放指针这个概念的盒子
int a; *p
C语言编译器对指针这个特殊的概念,有2个疑问?
1.分配一个盒子,盒子要多大?
在32bit系统中,指针就4个字节
2.盒子里存放的地址所指向内存的读取方法是什么?
举例:
int *p;
int *p1;
char *p2; unsigned char *p2;
float b = 1.2;
int a = 0x12345678; 大端小端 0x12 0x34 ...取最低位地址
p = &b;
p1 = &a;
p2 = &a; *p2 = 78
printf("the p1 is %u, the p2 is %u\n", sizeof(p1), sizeof(p2));
printf("the p1 is %x\n",*p1);
指针指向内存空间,一定要保证合法性
2.指针+修饰符
const
常量、只读【不能变】
内存属性:
1、内存操作的大小
2、内存的变化性,可写可读
char *p;
const char *p;【T】 等价 char const *p; p可以指向任意,p内容只读
字符串 "hello world"
char * const p;【T】 等价 char *p const; p指向内容可变,指向地址固定
硬件资源 LCD
const char * const p;指向固定,指向内容不可变
ROM内容
volatile
防止优化指向内存地址
typedef
char *p;
什么类型 变量名称
int (*p[10])(int,void(*p)(int));
char *name_t; name_t是一个指针,指向一个char类型的内容
typedef char *name_t; name_t是一个指针类型的名称,指向了一个char类型的内存
name_t abc;
3.指针+运算符
+、-
int p = xxx [0x12]
p+1 [0x12+1(sizeof(*p))]
指针的加法、减法运算,实际上加的是一个单位,单位的大小可以使用sizeof(p[0])
++、--
p++ p-- 更新地址
[]
变量名[n]
n:ID 标签
地址内容的标签访问方式
例子:
int a = 0x12345678;
int b = 0x99991199;
int *p1 = &b;
char *p2 = (char *)&b;
printf("the p1+1 is %x,%x,%x\n",*(p1+1),p1[1],*p1+1);
printf("the p2+1 is %x\n",p2[1]);
越界操作
const int a = 0x12345678;
int b = 0x11223344;
//a = 100;
int *p = &b;
p[1] = 0x100;
printf("the a is %x\n",a);
逻辑操作符
int *p1;
int *p2;
p1>p2
*p1>*p2
1)跟一个特殊值进行比较 0x0:地址的无效值,结束标志
if( p == 0x0 )
NULL
2)指针必须是同类型比较才有意义
4.多级指针
int **p;
存放地址的地址空间
把两个或多个不连续的指针变量用指针连在一起,更有顺序逻辑性
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++){
printf("the argv[%d] is %s\n",i,argv[i]);
}
return 0;
}
测试: ./build hello 123 456
二级指针使用模板
#include <stdio.h>
int main(int argc, char **argv)
{
int i = 0;
while(argv[i] != NULL){
printf("the argv is %s\n",argv[i]);
i++;
}
return 0;
}
5.数组的定义及初始化
内存分配的一种形式
数组的定义及初始化
定义一个空间:
1、大小
2、读取方式
数组类型 数组名[m] m的作用域是在申请的时候
数组名是一个常量符号,一定不要放到=号的左边
例:char buf[100];
buf = "hello world";
int a[100];
越界
a[10]
6.数组空间的初始化
空间的赋值
按照标签逐一处理
int a[10]; [0 - 9]
C语言本身,CPU内部本身一般不支持空间和空间的拷贝
int a[10] = {10,20,30} ====>a[0] = 10; a[1] = 20; a[2] = 30;
数组空间的初始化和变量的初始化本质不同,尤其在嵌入式的裸机开发中,空间的初始化往往需要库函数的辅助
char buf[10] = {'a','b','c'};
buf当成普通内存来看,没有问题
buf当成一个字符串来看,最后加上一个'\0' 0
字符串的重要属性,结尾一定有个'\0'
char buf[10] = {"abc"};
char buf[10] = "abc";
buf[2] = 'e'; 可以
char *p = "abc"; p指向常量
p[2] = 'e'; 错误
char buf[10] = "abc";
buf = "hello world" 错误
第二次内存初始化,赋值?
应逐一处理
buf[0] = 'h'; buf[1] = 'e' ... buf[n] = 'd'; buf[n+1] = 0;
strcpy,strncpy
strcpy:严重内存泄露函数,只有出现0才停止拷贝,超出内存的怎么办?会把其他的覆盖
strncpy:对拷贝的数量有限制。
一块空间,当成字符空间,提供了一套字符拷贝函数
字符拷贝函数的原则:
内存空间和内存空间的逐一赋值的功能的一个封装体
一旦空间中出现了0这个特殊值,函数就即将结束。
char buf[10] = "abc";
buf = "hello world";
strcpy(buf,"hello world");
字符空间:ASCll码编码来解码的空间
非字符空间:数据采集 0x00-0xff 8bit
开辟一个存储这些数据盒子
char buf[10]; -->string
unsigned char buf[10]; -->data
拷贝三要素:
1、src 2、dest 3、个数
memcpy
int buf[10];
int sensor_buf[100];
memcpy(buf,sensor_buf,10*sizeof(int));
unsigned char buf[10];
unsigned char sensor_buf[100]; // 00 00 00 23 45 78
strncpy(buf,sensor_buf,10); 出现0就停止,拷贝不了后面的数据
memcpy(buf,sensor_buf,10*sizeof(unsigned char));
7.指针与数组
char * a[100];
sizeof(a) = 100 * 4;
8.多维数组
数组名的保存
定义一个指针,指向int a[10]的首地址
定义一个指针,指向int b[5][6]的首地址
int a[10];
int b[5][6];
int *p1 = a;
int **p2 =b; 错误
int (*p2)[6] = b;
int *p; int *p[5];
int a; int a[5];
int *p[5];
int(*p[5]);
int b[2][3][4];
int (*p)[3][4];
9.结构体、共用体定义与字节对齐
字节对齐
char a;
int b;
1+4=5
效率,希望牺牲一点空间换取时间的效率
最终结构体的大小一定是4的倍数
结构体里成员变量的顺序不一致也会影响到他的大小
#include <stdio.h>
struct abc{
char a;
short e;
int b;
};
struct my{
char a;
int b;
short e;
};
int main()
{
struct abc buf;
struct my buf1;
printf("the buf is %lu:%lu\n",sizeof(buf),sizeof(buf1));
}
10.内存分布图概述
内存的属性:
(1)大小
(2)在哪里
int a;默认方式
编译 --->汇编 ---> 链接
内存分布
*.o build
内核空间 应用程序不许访问
-----------------------------3G
栈空间 局部变量 RW
运行时的堆空间 malloc
全局的数据空间(初始化的,未初始化的) static RW data bss
只读数据段 “hello world” 字符串常量 R TEXT
代码段 code R TEXT
0x0;
#include <stdio.h>
int main()
{
static int a;
unsigned char *p;
char *p1 = “hello world”;
const int b = 0x12345678;
a = 0x10;
printf("1234the p1 is %s\n", p1);
print("the string address is %p\n", "hello world");
p1[3] = 'a';
printf("the p1 is %s\n", p1);
printf("the a is%p\n", &a);
printf("the is %p\n", main);
p = (unsigned char *)main;
}
-
只读空间
静态空间,整个程序结束时释放内存,生存周期最长栈空间
运行时,函数内部使用的变量,函数一旦返回,就释放,生存周期是函数内堆空间
运行时,可以自由,自我管理分配合释放的空间,生存周期是由程序员来决定分配:
malloc(),一旦成功,返回分配好的地址给我们,只需要接受,对于这个新地址的读法,由程序员灵活把握,输入参数指定分配的大小,单位就是B。char *p;
p = (char *)malloc(100);
if(p == NULL){
error
}void fun()
{
char *p;
p = (char *)malloc(100);//申请内存后没有释放,内存泄漏
return ;
}int a[5]; malloc(5*sizeof(int))
释放:
free§;