C语言
1.进制转换
十进制(逢10进1):0-9
二进制(逢2进1):0-1
八进制(逢8进1):0-7
十六进制(逢16进1):0-15
注意:为了区分不同进制:八进制前面加0---076
十六进制前面加0x---0x76
转换
1.1其他进制转十进制:对应的数字乘以其他进制的位数次幂
二进制转十进制:1011---->1*2^0+1*2^1+0*2^2+1*2^3 11(1248)
八进制转十进制:076--->6*8^0+7*8^1
十六进制转十进制:0xafc--->12*16^0+15*16^1+10*16^2
1.2十进制转其他进制:除以其他进制倒取余数
1.3二进制转八进制:每一个八进制可以用三位二进制数进行表示(421)
0 --- 000
1 --- 001
2 --- 010
3 --- 011
4 --- 100
5 --- 101
6 --- 110
7 --- 111
1.4 二进制和十六进制的转换:每一个十六进制可以用四位二进制去表示(8421)
0 --- 0000 1 --- 0001 2 --- 0010 3 --- 0011 4 --- 0100 5 --- 0101 6 ---- 0110 7 ---- 0111
8 --- 1000 9 --- 1001 a --- 1010 b --- 1011 c --- 1100 d --- 1101 e ----1110 f --- 1111
2.数据类型以及大小
2.1 long
只有long32位和64位操作系统字节大小不同,其他数据类型均一样
long 32os是4字节
64os是8字节
2.2 有符号数和无符号数
有符号数:signed ---->正数和负数
符号位:最高位为符号位,0表示正数,1表示负数
10 --- 0000 1010
-10 --- 1000 1010
无符号数:unsigned ---->正数
3 转义字符
转义字符是一种特殊的字符序列
例如:/n 换行
/t 水平制表
4.变量
定义变量:<存储类型> 数据类型 变量名;
int a;
数据类型:决定开辟空间的大小
存储类型:决定开辟的空间在哪个分区
一共有四种存储类型:static auto extern register
static:既可以修饰全局变量,也可以修饰局部变量,修饰的变量放在静态区
auto:默认情况下就是auto,只能用来修饰局部变量,修饰的变量存放在栈区
extern:只能修饰全局变量,修饰的变量存放在静态区
register:只能修饰局部变量,修饰的变量存放在寄存器中
4.1 初始化
定义变量的时候就给变量赋值
int a = 9; //初始化
int b; //定义变量
b = 3; //赋值
注意:1.全局变量未初始化存放在静态区.bss,初始化在存放在静态区.data
2.局部变量未初始化和初始化都存放在栈区
3.全局变量不初始化,其值为0;局部变量不初始化,其值为随机值
4.static修饰全局变量限制作用域,只能在本文件中使用
static修饰局部变量时延长局部变量的生命周期(延长至从定义开始到整个程序结束),局部变量没有初始化,其值为0,初始化且只能初始化一次
5.数据类型转换
5.1 强制类型转换(自己转)
变量前面加个括号直接转
5.2 隐式类型转换(编译器进行转换)
6.运算符
优先级依次递减:单算移关与,异或逻条赋
6.1单---单目运算符
a++ ++a --a a--
6.2算---算数运算符
+ - * / % ++ --
注意:%---取模运算,求余数 %不能用与浮点数
/---除法运算,取整
++a; //先自加再赋值
a++; //先赋值后自加
6.3移---移位(左移、右移)
位运算符:& | ~ << >> ^
~ 取反运算符
左移---<<
无符号数(只有正数)---高位丢弃低位补0
有符号数---符号位不变,高位丢弃,低位补0
右移--->>
无符号数---低位丢弃,高位补0
有符号数---符号位不变,低位丢弃,高位补1
6.4关---关系运算符
> < >= <= == !=
关系运算符:比较的结果是真或假
注意:判断相对时,编程习惯将常量放在左边
if(9 == a)
6.5与---与运算符
&
6.6异或---异或运算符
^ 异或运算符
相同为0,不同为1
6.7逻---逻辑运算符
&& || !
截断法则
6.9赋---赋值运算符
=
6.10 sizeof运算符
使用方法:
sizeof(数据类型);//用法1
sizeof(变量名);//用法2
作用:求对应数据类型或者变量名所占内存空间的大小
6.11 三目运算符
表达式1?表达式2:表达式3
6.12 逗号运算符
(表达式1,表达式2,表达式3,......表达式n)
从左往右依次计算每个表达式的值,将表达式n的值作为整个表达式的值
注意:必须依次计算,防止前面的表达式改变了表达式n中的变量的值
逗号的优先级最低,因此在使用的时候需要加上括号
7.输入输出
7.1输出printf
整型
%d----以整型形式进行输出
%ld----以long整型形式输出
%lld----以long long整型形式输出
%hd----以short整型形式输出
%u----以无符号整型形式输出
%o----以八进制整型形式输出
%x、%X----以十六进制整型形式输出
#:自动在八进制和十六进制之间加上前缀
字符型
%c----以字符形式输出
浮点型
%f----以浮点形式输出
%lf----以双精度浮点型输出
%g----以指数形式和浮点形式中较短的方式进行输出
%e---以指数的形式进行输出
%.nf----保留小数点n位进行输出
%m.nf
m----指定我们输出的域宽,当m>0,默认右对齐,当m<0,默认左对齐
当m的值大于数据的实际长度时,补空格,m小于数据的实际长度时,原样输出
注意:默认左对齐,加上负号表示右对齐
7.2输入scanf
scanf("%d",&a);
注意:
1.scanf格式控制串,不要加修饰语,如果要加,要原样输出
2.如果输入“%d%d”时,要给多个变量进行赋值,在格式控制串中,没有多余的修饰语时,可以以空格,回车,tab键作为第一个变量结束的标志
3.全部输入结束,必须以回车作为结束符
4.如果以“%c%c”输入多个字符时,不能有回车,空格,tab键,因为空格,回车,tab键也是一个字符
解决方法
1.在%c和%c之间加上逗号或者空格
2.加上%*c,*表示抑制符(吃掉一个字符)
3.%*nc---吃掉n个字符
7.3 字符输入输出函数
字符输入函数
getchar()----返回值输入字符的ascii码值
字符输出函数
putchar()---参数输出的字符的ascii码值
8.三大结构
8.1 顺序结构
程序中的语句按照一定的先后顺序去运行
8.2 选择结构
选择正确的条件结果再进行运行输出
if else选择结构
单分支结构
双分支结构
多分支结构
switch case结构
switch(表达式)
{
case 标号1:
语句1;
break;
case 标号2:
语句2;
break;
......
case 标号n:
语句n;
break;
default:
最终语句;
}
注意:
1.表达式不能为float类型
2.标号必须为常量
8.3 循环结构
循环三要素:循环的起始条件,循环的终止条件,循环变量的变化
for循环
for(表达式1;表达式2;表达式3)
{
循环体;
}
注意:
表达式1:可以省略,但需要在循环体外给循环变量一个初始值
表达式2:可以省略----会导致死循环
表达式3:可以省略,但需要在循环体内实现循环变量的变化
三个表达式都可以省略,但是分号不可以省略
for循环嵌套
while循环
while(表达式) //循环终止条件
{
循环体;
(包含循环变量的变换)
}
注意:while循环的循环体包含循环变量的变化
do while循环
do
{
循环体;
(包含循环变量的变化)
}while(表达式);
while和dowhile的区别:
while先执行再判断,循环体最少执行0次
do while先执行再判断,语句至少执行1次
break和continue的区别
二者都是跳出循环的作用
break
跳出switch case语句
跳出循环(离他最近的循环)
continue
跳出本次循环,进入下一次循环
死循环
while(1)
{
循环体;
}
for( ; ; )
{
循环体;
}
goto语句
无条件跳转语句
标号:
goto 标号;//当执行到这条语句时,程序自动跳转至标号处
9.数组
9.1 定义数组
概念:一组数据类型相同的元素的集合
<存储类型> 数据类型 数组名[元素个数]
int arr[5];
//arr的数据类型是int[5]
//存储类型:auto static extern register
特点:元素的数据类型相同
地址连续
注意:
打印地址的格式化符---%p
数组的数据类型---去掉变量名,剩下的就是数据类型
sizeof在64位linux系统下打印时,应使用%ld
数组名的特点:
1.代表数组首元素的地址
2.代表整个数组
注意:数组元素的个数必须是整数型,不能是浮点数。数组元素个数是一个确定的值,不能是一个变量
9.2 数组初始化
全部初始化
int arr[5] = {1,2,3,4,5};//全部初始化方法一
int brr[] = {1,2,3,4,5};//全部初始化方法二
在定义数组时,给所有元素赋值
只有在全部初始化的时候,才能省略元素个数,此时元素个数由输入决定
部分初始化
在定义数组时,给部分元素赋值
数组清零
int arr[6] = {0};//清零
数组的默认值
1.局部变量的数组不初始化,其值为随机值
2.static修饰的局部变量的数组不初始化,其值为0(静态区里的.bss)
3.全局变量的数组不初始化,其值为0
访问
9.3. 冒泡排序
从左往右,依次比较,如果前一个元素比后一个元素大,需要互换位置,反之元素位置不变
9.4 字符数组
概念:存储元素类型为字符的集合
每一个元素的数据类型为char
<存储类型> 数据类型 数组名[元素个数];
char str[5];
//分配5个大小为1字节的空间,给这片空间起名为str
计算字符数组所占空间大小 = sizeof(char)*元素个数
字符数组的本质---字符串
打印字符串的格式化符%s
字符数组清零
char str[5] = {0};
char str[5] = {'\0'};
9.5 字符串输出函数
puts(参数);
//函数功能:打印输出字符串,遇到'\0'结束打印,并自动换行
//函数参数:需要打印的字符串的起始地址(字符数组名)
9.6 字符串输入函数
gets(参数);
//函数功能:从键盘得到字符数据存放到字符数组中,并自动'\0'
//函数参数:电脑去保存字符的数组名
//注意:该函数不会进行越界检查,注意访问越界问题
总结
gets和scanf对比
1.scanf以回车、空格、tab键作为输入结束符,gets以回车作为结束符
2.scanf输入完成后不会清空缓冲区,里面遗留回车、空格tab键,gets会清空缓冲区
3.gets函数发现缓冲区有数据,会直接拿过来使用,否则,要求键入
4.scanf只能以键入方式输入数据
puts和printf
1.puts函数输出的时候自动换行,printf函数不会自动换行
9.7 字符串处理函数
使用的时候需要引入头文件
#include <string.h> //C库的头文件
1.求字符串长度
strlen();//求出的值不包含‘\0’
2.字符串拷贝函数
strcpy(str1,str2);//str1的长度要大于str2 遇到'\0'停止拷贝
strncpy(str1,str2,3);//将str2的前三个字符拷贝到str1中 遇到'\0'停止拷贝
3.字符串连接函数
strcat(str1,str2);//str1的空间要足够大
strncat(str1,str2,n);//将str2中的前n位连接到str1
4.字符串比较函数
strcmp(str1,str2); //比较两个参数的大小
//函数返回值
return value > 0; //参数1 > 参数2
return value < 0; //参数1 < 参数2
return value = 0; //参数1 = 参数2
9.8 二维数组
二维数组:一组元素集合在一起(元素:一维数组)
本质:元素为一维数组的数据
<存储类型> 数据类型 数组名[行数][列数];
int arr[2][3];
//定义了一个二维数组,该数组有2个元素,每一个元素都是一个有3个int类型元素的一维数组
//行数:有几个一维数组(二维数组有几个元素)
//列数:一维数组有几个元素
二维数组所占内存空间大小 = sizeof(最里面元素的数据类型)*最里面元素
初始化
全部初始化
int arr[2][3] = {1,2,3,4,5,6};
int arr[2][3] = {{1,2,3},{4,5,6}};
注意:行数可以省略,因为确认了一维数组中最里面的元素,所以编译器可以计算出一维数组的个数
列数不可以省略,会产生歧义
部分初始化
int arr[2][3] = {1,2};
int arr[2][3] = {{1},{4,5}};
访问
二维字符数组
char str[2][3]
10.函数
概念:具有一定功能的模块代码
为什么要有函数:提高代码复用率 可以让程序变得模块化
分类
10.1 库函数
使用的时候要加头文件
#include <stdio.h>
#include <string.h>
printf scanf strlen strcpy gets等等
10.2 自定义函数
调用自定义函数
函数名(实参);
注意:1.实参的数据类型和个数必须和形参一一对应(调用的时候将实参的值传给形参)
2.实参可以是一个变量、常量、表达式,必须是一个确定的值
3.实参和形参是两片独立的空间
4.传参实际上是将实参的值拷贝给形参
5.形参是局部变量,在函数调用的时候被定义(开辟空间),函数调用结束之后释放空间
10.3 函数声明
如果自定义的函数在main函数之后,就需要加上声明
将函数名复制加分号就是函数声明
11.指针
指针是一个数据类型,是一个保存地址的数据类型
指针的大小:32OS 4字节 64OS 8字节
11.1定义指针
<存储类型> 数据类型 指针名;
int * p;
//一个指向int类型变量的指针
//编译器分配8字节,起名为p,存放int类型变量的地址
int *p; //p的数据类型是int *
注意:指针变量中只能保存它指向同中数据类型的变量的地址
11.2 野指针
不知道指向的指针(局部指针,未初始化,随机指向)
要避免野指针----先指向NULL,0号地址
11.3 空指针
0号地址:没有指向的指针(NULL)
注意:禁止操作
特点:不读不写(这片空间不能保存别的地址,只能保存NULL,即就是不能指向,但别的指正可以指向它)
实现两数交换
调用函数的时候,需要操作地址里面的值,需要传地址
11.4 二级指针
概念
指针的指针(保存指针的地址)
二级指针的内存空间:用来保存一级指针的地址
int **p;
总结
1.指针指向的数据类型:去掉*和指针名,剩下的就是指向的数据类型
2.指针的数据类型:去掉指针名,剩下的就是指针的数据类型
3.指针所能访问到的空间的大小,由其指定的数据类型决定
11.5 指针与一维数组
指针常量的偏移量取决于指针指向的数据类型的大小
总结:
1.p+n 相当于指针p向地址增大方向移动n个数据(数据大小为sizeof(指向的数据类型))p为指针常量或者指针变量
实际变化:p+sizeof(p指向的数据类型)*n
2. p-n相当于指针p向地址减小方向移动n个数据(数据大小 = sizeof(指向的数据类型)) p为指针常量或者指针变量
实际变化:p+sizeof(p指向的数据类型)*n
3.p++ 指针p向地址增大方向移动1个数据(数据大小为sizeof(指向的数据类型))p为指针变量
4.p--:指针p向地址减小方向移动1个数据(数据大小 = sizeof(指向的数据类型)) p为指针变 量!!
5.p-q:p和q的指针类型要匹配,两个指针之间相差的数据个数(数据大小 = sizeof(指向的数据类型))
(十六进制p-q的差值)/sizeof(指向的数据类型)
注意:1.指针的算术运算需要操作连续的空间地址才有意义
2.p是指针变量,可以++或者--(指针常量不可以++或者--)
指针常量与一维数组的关系
指针变量与一维数组的关系
数组在子函数中弱化为指针(数组名---指针常量)
void input(int *p,int m)
void input(int a[],int m)
//可以在子函数中像main函数一样操作数组,操作的是同一片地址
指针常量与二维数组的关系
总结:
1.a &a a[0] &a[0] &a[0][0] 都表示首地址,但其意义不同
a 指针常量整个二维数组名
&a 与a含义相同
a[0] 指针常量整个一维数组名
&a[0] 与a[0]含义相同
&a[0][0] 与a[0]含义相同
2.a[0]是int *类型,指向的是一个int类型,不是二级指针
3.a指向a[0],a[0]指向a[0][0]
11.6 数组指针
指向数组的指针
int (*p)[3];
数组指针p的数据类型:int (*) [3]
数组指针p指向的数据类型:int [3]
数组指针与一维数组的关系
数组指针对其+1,直接移动一整个一维数组,指向数组底部,容易产生数组越界问题,因此一般不使用数组指针操作一维数组。
11.7 数组指针与二维数组的关系
11.8 指针数组
本质:数组
概念:由指针组合起来的数组,数组中的元素都是指针类型
定义
<存储类型> 数据类型 数组名[元素个数]
int * arr[5];
//[]的优先级高于*
指针数据arr的数据类型:int* [5]
指针数组保存的数据类型:int *
11.9 指针数组与二维数组关系
11.10 const
const修饰变量:只读(不可写)
const修饰指针---左数右指
数---数值不可修改
指---指向不可修改
const int *p;常量指针,指向常量的指针,数值不可以改变
int const *p;指针常量,定义一个指针,将该指针定义为常量,指向不可以改变
const int * const p;
int const *const p;
p指针的指向和数值都不可改变
11.11 main函数传参
12.GDB调试工具
调试步骤
1.编译的时候加参数
gcc -g error.c -o error
2.设置断点
b main
b 行号
3.gdb加可执行文件
gdb error
4.运行
r 运行
其他参数
n(next) 不进入子函数
s(step) 进入子函数
p(printf)a(要打印的值) 打印出来某一个指定值
c(continue) 可以直接跳出循环,进入下一步
q(quit) 退出