1、学习前沿2、指针基础3、指针与地址4、数据交换5、const关键字6、C程序内存布局
程序所占内存的分类
1、学习前沿指针的大小与数据类型无关,只与系统的位数有关。
32位的操作系统,指针长度为4字节;64位的操作系统,指针长度为8个字节。指针是用来存放地址的。LSB和MSB------内存存储数据的两种方式
LSB:Least Significant Bit. “最低有效位”------小端字节序
MSB:Most Significant Bit. “最高有效位”------大端字节序
一般系统默认的内存存储方式为小端字节序。
虚拟地址空间
当创建一个进程时,操作系统会为该进程分配一个4GB的虚拟地址空间。(以32 位的操作系统为例,一个指针长度是 4 字节,4字节指针的寻址能力是从 0x0000 0000~0xFFFF FFFF)。
每个进程都会有一个自己的 4GB 虚拟地址空间。这 4GB 的地址空间是“虚拟”的,并不是真实存在的。
2、指针基础
*:取值运算符
&:取地址符
解析:
int main (int argc, char **argv) //int argc:参数个数;char **argv:指向指针的指针
{
int a;
int *p=&a; //定义p是一个指向int类型的指针
char ch='a';
char *p=&ch; //定义p是指向char类型的指针
char *str="hello";
char **p=&str; //定义*p是指向char *类型的指针
}
代码演示:
#includeint main(int argc, char **argv) { int a = 10; int b = 20; int *p = &a; int **pp = &p; printf("&a = %pn", &a); printf("p = %pn", p); printf("*pp = %pn",*pp); printf("a = %dn", a); printf("*p = %dn", *p); printf("n"); printf("&p = %pn", &p); printf("pp = %pn", pp); printf("&a = %pn", &a); printf("p = %pn", p); printf("a = %dn", a); printf("**pp = %dn",**pp); }
代码解析:
int a =10 :
在内存中开辟了一段内存空间,大小为4个字节(int类型4个字节);a表示这段内存单元,&a表示这段内存单元的地址;10以16进制(0x0000000a)的形式存储在那段内存单元中。
&a:
&a是int *类型。
&p:
&p是int **类型。
int *p = &a:
定义指针p指向a,p的内存单元存放a的地址。
int **pp = &p:
指针pp指向指针p,pp的内存单元存放指针p的地址。
执行结果:
&a = 0x7fff27afb130 p = 0x7fff27afb130 *pp = 0x7fff27afb130 a = 10 *p = 10 &p = 0x7fff27afb138 pp = 0x7fff27afb138 &a = 0x7fff27afb130 p = 0x7fff27afb130 a = 10 **pp = 10
结果解析:
*p:
p表示取指针p的内存单元存储的值,由于p的内存单元存储了a的地址,所以p取了a的值[^1]。**pp
**pp表示取*pp的值,*pp取指针pp的内存单元储存的值,由于pp存储的是p的地址,所以*pp取p的内存单元存储的值[^1]。又由于p的内存单元存储了a的地址,所以**pp取了a的值[^2]。
拓展:
如果a = 20;a出现在等号的左边,就是把20这个值写到a的内存单元里面去。
如果b = a;a出现在等号的右边,就是把a的内存单元的值取出来给b。
通过*p改变a的值:*p = 20;
通过**pp改变a的值:**pp = 20;
代码演示:
#includeint main(void) { int a = 0x12345678; int *pint = &a; char *pchar = (char *)&a; short *pshort = (short *)&a; printf("*pint = 0x%x, *pchar = 0x%02x, *pshort = 0x%hxn", *pint, *pchar, *pshort); printf("&a = %p, &pint = %p, &pchar = %p, &pshort = %pn", &a, &pint, &pchar, &pshort); pint++; pchar++; pshort++; printf("*pint = 0x%x, *pchar = 0x%02x, *pshort = 0x%hxn", *pint, *pchar, *pshort); }
代码解析:
char *pchar = (char *)&a:
因为a是int类型的,所以要强制转换为char *类型。
short *pshort = (short *)&a:
因为a是int类型的,所以要强制转换为short *类型。
执行结果:
*pint = 0x12345678, *pchar = 0x78, *pshort = 0x5678 &a = 0x7ffe171b01dc, &pint = 0x7ffe171b01e0, &pchar = 0x7ffe171b01e8, &pshort = 0x7ffe171b01f0 *pint = 0x171b01e0, *pchar = 0x56, *pshort = 0x1234
结果解释:
一般系统默认的内存存储空间为小端字节序。
*pchar = 0x78:
因为char只有1个字节,所以只输出78[^1]。
*pshort = 0x5678:
因为short只有2个字节,所以只输出5678[^1]。
pchar++:
有效位自加1个字节。
所以*pchar = 0x56[^2]。
pshort++:
有效位自加2个字节。
所以*pshort = 0x1234[^2]。
代码演示:
int main()
{
int a = 8;
int b = 10;
printf("before: a = %d, b = %dn", a, b);
swap(a,b);
printf("after: a = %d, b = %dn", a, b);
printf("before: a = %d, b = %dn", a, b);
pswap(&a,&b);
printf("after: a = %d, b = %dn", a, b);
}
int swap(int a,int b)
{
int temp;
temp = a;
a = b;
b = temp;
}
int pswap(int *p1, int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
运行结果:
before: a = 8, b = 10 after: a = 8, b = 10 before: a = 8, b = 10 after: a = 10, b = 8
结果解释:
调用swap函数交换不成功,是因为函数是按值传递,把a,b传过去在函数swap里面交换了,却只在函数swap里生效,没有改变main里面的a,b。
通过调用pswap(&a,&b)函数后,
定义:
const定义的是常量,值不能被改变。
const int a = 100
const 和指针变量一起使用时,可以限制指针变量本身,也可以限制指针指向的数据。
const 和指针一起使用会有3种不同的顺序,如下所示:
const int *p1 // int const *p1 = &a; int * const p2 = &a; const int * const p3 = &a;
第一种情况指针所指向的数据*p1是只读的不能修改,指针p1本身的值可以修改。
*p1 = 30;//不合法 p1 = &b;//合法 a = 20;//不合法
第二种情况指针本身的值p2是只读的不能修改,指针所指的数据*p2可以修改。
*p2 = 30;//合法 p2 = &b;//合法
第三种情况指针本身的值p3和它指向的数据*p3都有是只读的,不能修改。
*p3 = 30;//不合法 p3 = &b;//不合法
由此可见:指针可操作两个内存空间,一个是自己的内存空间,另一个是指向的内存空间。
6、C程序内存布局 程序所占内存的分类当程序没有运行,只有文本段(代码段)和数据段。系统空间:每个程序都有4GB的虚拟内存空间(32位的操作系统)参数区,堆区,栈区,数据段是用来存放数据的。栈区的空间是由上往下增长的。堆区的空间是由下往上增长的。参数区:
参数区放命令行传给main()函数的参数:argc,argv。栈区:
栈区存放局部变量,当它在花括号内,就在栈区占一段内存空间,用完后,这段内存就被释放了。
局部变量:
定义:花括号内所以定义的变量是局部变量,只能在本花括号使用。
int main(void)
{
int stack_var;
const int rodata_var = 50;
static int s_var;
char *ptr = "hello world";
char arr[] = "hello";
}
未定义的局部变量,其值是随机值。
未初始化的静态局部变量,其值为0。
堆区:
malloc()动态类型分配内存,在内存中分配一段内存使用。
int *p = (malloc)100; free (p); p = NULL;
free(p),是放弃了指针对这个内存的占用,放弃之后,内存的值会改写成随机值。但是指针本身并没有被删除!指针仍然指向原来的那块内存!因此在free掉指针后,还要把指针指向null,即p = NULL。
数据段:
数据区存放全局变量、静态变量以及文字常量。
全局变量:
定义:在花括号外定义的变量,是全局变量。
#includeint g_data_var = 20; int g_bss_var; static int s_bss_var;
已初始化的全局变量,可以被所有其他c文件或本C文件中的函数调用,如果另一个c文件想调用全局变量,要用extern声明。
extern int g_data_var;
未初始化的全局变量,其值为0,可以被所有其他c文件或本C文件中的函数调用。
未初始化的静态全局变量,其值为0,static关键字声明的函数或变量,只能被本C文件调用。
文字常量区:
char *ptr = "hello world";
*p指向"hello world","hello world"在数据段的文字常量区,不可改变,报段错误。
*(str+1) = 'a' //segment fault
数组arr在栈区,可以改。
arr[1] = 'a'
指针和数组同等的写法:
*(str+1) = 'a' str[1] = 'a' arr[1] = 'a' *(arr+1) = 'a'
代码演示:
#include#include int g_data_var = 20; //已初始化的全局变量 int g_bss_var; //未初始化的全局变量 static int s_bss_var; //未初始化的静态全局变量 int main(int argc, char **argv) { int stack_var; //未初始化局部变量 const int c_rodata_var = 50; //常量 static int s_data_var = 30; //静态局部变量 static int s_bss_var; char *str = "hello world"; //局部变量 char arr[] = "hello"; //局部变量 char *ptr = NULL; ptr = malloc(100); printf("g_bss_var: %d stack_var: %d s_bss_var: %dn", g_bss_var, stack_var, s_bss_var); printf("arr address: %pn", arr); printf("str address: %p str point address: %pn", &str, str); printf("c_rodata_var address: %pn", &c_rodata_var); printf("stack_var address: %pn", &stack_var); printf("ptr address: %p ptr point address: %pn", &ptr, ptr); printf("g_bss_var address: %pn", &g_bss_var); printf("s_bss_var address: %pn", &s_bss_var); printf("g_data_var address: %pn", &g_data_var); printf("s_data_var address: %pn", &s_data_var); free(ptr); ptr = NULL; return 0; }
g(global):全局变量
s(static):静态变量
data:已初始化
bss:未初始化
stack:在栈区中
rodata:常量
执行结果:
g_bss_var: 0 stack_var: 0 s_bss_var: 0 arr address: 0x7ffc3e0d0052 str address: 0x7ffc3e0d0040 str point address: 0x561485266948 c_rodata_var address: 0x7ffc3e0d003c stack_var address: 0x7ffc3e0d0038 ptr address: 0x7ffc3e0d0048 ptr point address: 0x5614863c3260 g_bss_var address: 0x561485467024 s_bss_var address: 0x561485467020 g_data_var address: 0x561485467010 s_data_var address: 0x561485467014
&**后续会更新《指针再复习》,全是硬货,等着你们来实操~~~~~~**



