cHomePage - juedaiyuer/researchNote GitHub Wiki
C语言的回顾,重要目的在于熟悉Linux平台下,C语言的开发
掌握其平台下GDB调试
-C语言没有专门的布尔型
#include<stdio.h> //该语句是一条预处理语句 int main() //主函数为C语言的唯一入口 {
}
- 转义字符
- C语言不存在字符串变量,字符串只能存在于字符数组中
- 前置++ 先计算,后取值;
格式化输出语句
- %d 带符号十进制整数
- %c 单个字符
- %s 字符串
- %f 6位小数
自动类型转换
- 字节小的可以向字节大的自动转换,但是字节大的不能向字节小的自动转换
- char类型转换为int类型,遵循ASCII码
char->int->double
强制类型转换
- 转换后只是在本次运算中临时性转换
- 不遵循四舍五入的原则
goto
- goto 语句标号;
- 跳转到带有语句标号的语句
##指针##
简单的交换函数,能够说明意义
#include<stdio.h>
void change(int a,int b)
{
int tmp = a;
a = b;
b=tmp;
}
int main()
{
int a=5;
int b=3;
change(a,b);
printf("num a=%d\n num b=%d\n",a,b);
}
#include<stdio.h>
void change(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b=tmp;
}
int main()
{
int a=5;
int b=3;
change(&a,&b);
printf("num a=%d\n num b=%d\n",a,b);
}
其实第一个程序而言,之所以失败的原因,变量的生存周期问题,局部变量仅在函数体内生效;
gdb
生成可调试的程序
gcc -g main.c -o main.out
gdb
- l 显示代码;未显示完全,可以再次输入 l,或者回车,回车的功能:执行上一次的指令(gdb)
- start 单步调试,从main函数开始
- p 打印变量的值,也可以打印函数的地址信息(栈)
- s 进入函数体,相当于step into ; n只能在一个函数体内部执行{},单纯的下一步
- bt 查看堆栈
- f num 跳转
计算机中的数据表示方法
- 一个字节(byte)=8bit
- 二进制,十进制,十六进制 ; 一个十六进制的数字可以表示有位二进制
- 32位操作系统支持4G内存 ; 地址总线32位,寻址空间32位
2^32=(2^10)(2^10)(2^10)4K=102410244K=10244M=4G
2^30=G
2^40=T
PB,EB
64Linux内存分配
- 绿色区域为自由可分配内存
- 程序编译完成后,储存在磁盘中,运行的时候加载到内存
- C语言语法不允许我们直接操作代码段
- C语言中,一个整型32位,一个字节8位,一个整型4个字节
- 32位 一个指针占4个字节 ; 64位 一个指针占8个字节
地址增减
代码段:先声明,地址小.
栈:先加载,地址大.
函数栈
数组申明的内存排列
- x (gdb) examime命令:查看内存地址中的值
指针运算
- 指针偏移运算,效果很好
- pointer+3 ; pointer[3]
字符数组
-
C语言中字符数组以\0结尾
-
一个字符一个字节
char str[] ="hello"; //变量初始化 ,保存在数据段,加载到内存后,在栈空间内可以进行更改操作 char *str = "hello"; //常量 ,保存在代码段 ,加载到内存后,不可以进行操作
##预处理##
- gcc -E 命令 (.c->.i)
- 跳转代码尾部 :$ (vim)
- 展开头文件,宏替换
宏
#define r 10
- 宏替换,单纯指字符串的替换
- 宏通常用于常量,数组buffer
宏函数
#define N(n) n*10
- 宏可以传递参数
typedef
- 通俗解释:起别名
- typedef int tni ;
- type int p q ; q my = null; (int 的别名为q)
- typedef预处理之后,有别于宏替换,它不做任何替换
举例
size_t 相当于 typedef unsigned long size_t
作用域
- typedef 如何在函数体内,仅在该函数体内有效
- 宏是全局有效
##结构体##
- 模型有着太多的参数,数组实现比较困难,因为数组只能保存同一类型的数据,这个时候就需要结构体的出现
- 结构体内存:涉及字节对齐的处理,而不是简单的成员字节相加,空间换取时间的类型
- 大小计算:最后成员的偏移量+最后成员大小+末尾填充字节数
- 偏移量:该成员的起始地址-结构体的首地址
- 字节对齐准则:每个成员相对于结构体首地址的偏移量必须是当前成员所占内存大小的整数倍,如果不是则加填充字节
- 上面的步骤完成之后所得到的和如果不是该结构体成员最大者的整数倍,则在最后成员填充字节
struct weapon
{
char name[20];
int atk;
int price;
}
struct weapon w1={"weapon",100,3500}; //初始化成员列表
printf("%s\n",w1.name); //成员的访问,点.成员运算符优先级最高
struct weapon *w; //结构体指针
w = &w1;
w->name; // 相等于(*w).name
struct weapon w2[2]={"AK",200,4500,"M4",200,4500}; //结构体数组
struct *p ;
p = w2;
p->name; //数组元素w2[0].name
p++; //指针偏移,指向w2[1],偏移量为一个结构体占据的空间(注意理解这句哦...)
##公用体##
-
所有成员共享同一个内存,初始化的时候只能使用一个,关键字union定义
-
内存:成员中内存最大的占据内存
-
内存地址:所有成员都是相同的
printf %p 输出一个指针的数据格式
##位运算##
补码
&运算
- 迅速清零
- 保留一个数据的指定位
- 判断奇偶性 a&1 =1 奇数 a&1 = 0 偶数
奇数的二进制最低位是1
| 运算
- 设定数据的指定位置
^异或运算
-
定位反转
-
数值交换
a=a^b; b=b^a; a=a^b;
左移右移
- 左移:高位舍弃,低位补0
- 左移:二倍乘运算,2^n
##递归函数##
- 调用自身