系列文章目录
一.C语言常用关键字及运算符操作
文章目录
- 系列文章目录
- 内存四区
- 指针
- 指针概述
- 指针 + 修饰符
- const
- volatile
- typedef
- 指针+运算符
- 多级指针
- 数组
- 数组空间
- 字符空间及地址
- 结构体、共用体
- 定义、字节对齐
- 位域
- 内存分布图
- 段错误分析
内存四区
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_1printf("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_1printf("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个单位得到的地址中的内容