- 初始指针
使用指针来进行交换值
#include<stdio.h>
void change(int *a,int *b){
int tmp=*a;
*a = *b;
*b = tmp;
}
int main(){
int a=5,b=3;
change(&a,&b);
printf("num a = %d\nnum b = %d\n",a,b);
return 0;
}```
- gdb调试工具
`brew install gdb`
调试的时候,生成可以调试的版本,`gcc -g main.c -o main.out`
`gdb ./main.out`对程序进行调试,Mac里面必须是这样`sudo gdb ./main.out`才能对程序进行调试。
`l`列出源代码,按回车继续刚才的命令
`break 12`断点放在12行
`start`单步调试
`n`下一步
`p a`打印出a的变量值
`q`退出
`s`进入函数里面
`bt`查看函数堆栈
`f 1`跳到1这个栈里面
- 计算机中的数据表示方法
计算机中内存中最小单位是字节,1Byte字节=8bit位
- 内存管理
操作系统统一管理,32bit系统,最大使用4G内存,由寻址空间决定的,地址总线是32位,寻址空间是32位,也就是给内存编号只能有32位。
地址总线可以存在多种状态,2^32个状态,所以就是2^32字节,4GB,64位操作系统,64位的地址总线,所以内存足够了,操作系统会给内存地址进行编号,编号就是唯一的内存字节的地址,一个字节存放8个二进制位的数据。
64位操作系统中,用户应用程序使用的内存只要有前面的48位就够了,其他的内存空间是给操作系统内核使用的
高位内存:系统内核->栈->堆->数据段->代码段:低位内存
代码编译后的二进制数据加载到内存中,代码段
声明的全局变量和一些常量在数据段
中间的区域是自由可分配的内存
- 变量和指针的本质
静态变量,静态局部变量,作用域是当前函数,从定义位置,到其所在的{}结束位置,生命周期是从程序运行到程序退出,贯穿整个运行时间,下次函数调用的时候,静态局部变量不会再次初始化,而是沿用上次函数退出时的值。
静态全局变量,作用域为当前文件,从定义位置到文件结尾,声明周期为从程序运行到程序退出,贯穿整个运行时间,但是动态全局变量的作用域是整个项目,即最终编译成可执行文件的所有文件均可以使用动态全局变量。
C语言语法是不允许直接操作代码段的,代码段也是有地址的,除了代码编译后存在代码段外,代码的状态信息是存在内存的栈区域。
C语言是强类型,静态类型的。
变量的本质是一个代号,标识符,代表的是某个地址空间
指针本身也是一个变量,保存的数据是地址,指针变量的地址也就是指针的指针。指针的本质是保存内存地址。
- 操作系统对内存的管理
编译器的优化功能,对源代码进行优化,将同一类型的变量内存地址分配在一块,使得程序执行更快。64位系统中指针是8个字节,因为地址总线是64位的。
栈的内存空间保存了程序运行时候的状态。
代码段的内存地址是向上增长分配的,然后栈段的内存地址是从大往小进行分配的。
- 函数栈以及数据段内存
栈里最先分配地址的函数内存地址更大一些,静态变量,常量还有全局变量默认是在数据段中,静态变量属于某个函数特定的,一个函数被多次调用,但是都在数据段中。
- 函数指针与指针指向的数据访问
`int (*pquadrate)(int a) = &quadrate;`定义一个函数指针
`int s = (*pquadrate)(a);`使用这个函数指针,()表示地址指向某个函数整体,然后后面调用传参数a。如果指向栈内存,数据段内存表示直接去变量里面的值,指向代码段,就是一片代码块。
- 示例代码
include<stdio.h>
int global = 0;
int rect(int a,int b){
static int count = 0;
count++;
global++;
int s = a * b;
return s;
}
int quadrate(int a){
static int count = 0;
count++;
global++;
int s = rect(a,a);
return s;
}
int main(){
int a = 3;
int b = 4;
int *pa = &a;
int *pb = &b;
int pglobal = &global;
int (pquadrate)(int a) = &quadrate;
int s = quadrate(a);
printf("%d\n",s);
}```
- 数组申明的内存排列
x/3d 0x7fffffffde14
从这个地址开始显示3个十进制,默认是按照4字节显示
这里经过gcc优化,b的地址在最前面,其次是a,但是i的地址在$10 = (int *) 0x7fff5fbffc54
, b的地址$9 = (int *) 0x7fff5fbffc60
,a的地址$8 = (int *) 0x7fff5fbffc64
,array的地址$12 = (int (*)[3]) 0x7fff5fbffc6c
,说明这些变量之间的地址分配还不是连续的,但是数组间的地址分配是连续的。
#include<stdio.h>
int main(){
int a = 3;
int b = 2;
int array[3];//必须是常量
array[0] = 1;
array[1] = 10;
array[2] = 100;
int *p = &b;
int i;
for(i = 0;i < 6;i++){
printf("*p = %d\n",*p);
p++;
}
printf("------------------------\n");
p = &b;
for(i = 0;i<6;i++){
printf("p[%d]=%d\n",i,p[i]);
}
return 0;
}```
- 指针运算
`p++`定义了p是int类型,所以大小是4字节,自增就是到下一个4字节的地址。
`p[1]`表示把p向下偏移4个字节
指针是变量,数组是指针常量,数组本身也是地址。
- 字符数组和指针字符串
include<stdio.h>
int main(){
char str[] = "hello";
char *str2 = "world";
char str3[10];
printf("input the value\n");
scanf("%s",str3);
printf("str is %s\n",str);
printf("str2 is %s\n",str2);
printf("str3 is %s\n",str3);
}```
str2在代码段,str2是指向这个地址而已,字符类型的指针,字符数组str3本身就是内存地址。str2指向字符串的指针,不能向里面scanf,str2是存的world字符串的地址,在代码段的地址,不能被修改,而str是字符数组的地址,str地址是在栈里面,字符数组是以\0为结尾。x/6cb 0x7ffffffde00
打印6个字符,单字节显示。
栈和堆内存才能被写入。
- 字符数组
str[3]='\0'
表示字符串结束位置,str2指向的是常量字符串,所以不能被修改
网友评论