1.准备VMware-workstation10
2.安装ubuntu-14.04.5-desktop-i386.iso
可以使用云服务器
1️⃣文件目录
linux文件系统是一个树形的分层组织结构
linux文件的目录结构参照FHS(Filesystem Hierarchy Standard)标准,所以不同版本的linux的目录结构也相似
bin:binary英文的缩写
boot:存放的都是系统启动时要用到的程序
dev: 包含了所有linux系统中使用的外部设备
etc:存放了系统管理时要用到的各种配置文件和子目录
lib:存放系统动态连接共享库的
home:普通目录的主目录
root:根目录(超级用户)的主目录
2️⃣pwd命令
查看目前文件夹所在的路径
3️⃣ls命令
查看当前文件夹下面有什么文件
可以用man ls看ls怎么使用
ls -l
:查看权限
ls -a
:显示隐藏文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a0SGXdGz-1669348716017)(C:\Users\timoraty.000\AppData\Roaming\Typora\typora-user-images\image-20221123214101364.png)]
ls -R
:目录里面还有目录会递归显示
4️⃣文件的权限
权限类型 | 应用于目录 | 应用于任何其他类型的文件 |
---|---|---|
读® | 授予读取目录或子目录内容的权限 | 授予查看文件的权限 |
写(w) | 授予创建、修改或删除文件或子目录的权限 | 授予写入权限,允许修改文件 |
执行(x) | 授予进入目录的权限 | 允许用户运行程序 |
- | 无权限 | 无权限 |
权限分为(创建者 同组用户 其他用户)
5️⃣查看文件内容
6️⃣cp复制命令
cp [选项] 被复制的文件名 复制后的文件名 复制到的位置
cp test.c test4.c /home/linux
-i 覆盖时交互提示
-r 对文件夹递归。用于复制多个文件夹
7️⃣mv移动
mv 文件名 移动到的路径
mv test.c ../
把test.c移动到上一级
8️⃣创建和删除文件
vi是linux中最基本的编辑器,但是vi编辑器在系统管理,服务器配置工作中永远都是无可替代的。
命令 | 功能 |
---|---|
a | append进入编辑状态,当前光标移动到行末,比如加分号的时候 |
A | 代码的尾部插入,可以写在后面的注释 |
i | 进入编辑状态,光标位置不变 |
I | 光标移动到代码的首处,便于加注释 |
ESC | 进入命令状态 |
:! Command | 执行外部命令,比如:!pwd |
o | open,进入编辑状态,下面加空行 |
O | 上面加入空行 |
命令 | 功能 |
---|---|
:q | 退出没有修改的文件 |
:q! | 强制退出,且不保存修改的部分 |
:w | 保存文件,但不退出 |
:x | 保存文件并退出 |
:w File | 另存为file给出的文件名,不退出 |
:r File | 读入file指定的文件内容插入 |
[n]yy | 复制连续n行到缓冲区 |
p | 粘贴在这一行的下方 |
P | 粘贴在这一行的上方 |
[n]x | 删除从光标开始的连续n个字符,并且复制到缓冲区 |
u | 取消上一次操作 |
冯诺依曼模型:存储器,输入,输出,运算器,控制器
存储器分为内存(断电就没)和外存(长期保存)和寄存器(cpu内部的快速存储器)
为了实现一个特定目标而预先设计的一组可以操作的工作步骤,存在磁盘上,可以被加载到内存中执行
机器语言–汇编语言–高级语言
编辑–编译/链接—执行/调试
数值表示:二进制,十进制,十六进制的转换
非数值表示:文字符号图像,可以转化为ascll编码/二进制编码
gcc 文件名
./a.out
或者
/gcc test.c -o test2 -Wall
./test2
-o 表示输出的文件 -wall表示语法错误用警告显示出来
查看函数名和所在的文件
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ cat printTest.c
#include
int main()
{
int m=20;
printf("%s %s %c %d\n",__FILE__,__FUNCTION__,__LINE__,m);
return 0;
}
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ gcc printTest.c -o printTest
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ ./printTest
printTest.c main 20
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$
数据类型的分类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AEPWsUgR-1669348716018)(C:\Users\timoraty.000\AppData\Roaming\Typora\typora-user-images\image-20221124082213999.png)]
true和false表示真1和假0
非0为真,0为假
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ cat boolTest.c
#include
#include
int main()
{
bool a=-1;
if(a){
printf("true %d\n",a);
}else{
printf("false %d\n",a);
}
return 0;
}
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ gcc boolTest.c -o boolTest -Wall
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ ./boolTest
true 1
每个字符有一个对应的ascll码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G3MRK0l1-1669348716019)(C:\Users\timoraty.000\AppData\Roaming\Typora\typora-user-images\image-20221124085916726.png)]
类型名称 | 值域 |
---|---|
char | -128~127 |
signed char | -128~127 |
unsigned char | 0-255 |
类型名称 | 长度 | 值域 |
---|---|---|
short | 2 | -32768~32767 |
unsigned short | 2 | 0~65535 |
int | 4 | -2147483638~2147483647 |
unsigned int | 4 | 0~4292967295 |
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ ./intTest
1 1 2 4
char:-128~127
short:-32768-32767
int:-2147483648~2147483647
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ cat intTest.c
#include
#include
int main(int argc,char *argv[])
{
printf("%ld %ld %ld %ld\n",sizeof(_Bool),sizeof(char),sizeof(short),sizeof(int));
printf("char:%d~%d\n",SCHAR_MIN,SCHAR_MAX);
printf("short:%d-%d\n",SHRT_MIN,SHRT_MAX);
printf("int:%d~%d\n",INT_MIN,INT_MAX);
return 0;
}
常量是指再程序运行期间其数值不发生变化的数据
1️⃣整形常量
可以是十进制,八进制和十六进制数
十进制用%d输出
八进制06434,用%o输出
十六进制 0xd1c,用%x输出
2️⃣浮点常量,又称实数,一般有小数的部分
3.5,用%f输出
3️⃣指数常量
指数形式的实数一般是由位数部分、字母e或E和指数部分组成,当一个实数的符号为正号时,可以省略不写
1.176e+10表示1.176*10^10
一般表示特别大和特别小的数
用%e输出
4️⃣字符常量
‘a’[ascii码97],‘9’ ,‘A’[ascii码65]
可以把字符常量看作是一个字节的整数
5️⃣字符串常量
“Hello”,用%s输出
6️⃣标识常量
标识常量是指标识符代替常量使用的一种常量,其名称是一个标识符
#define <标识常量名称> <常量>
#define MAX 50
只会替换,不会做处理,想要做加减乘除运算的话,可以巧妙用括号
可以用gcc -E define.c -o define.i
vi define.i
来看编译之后的代码
变量名由字母数字下划线组成,不能用数字开头,不能和c关键字重名
在程序运行时,变量占的存储空间的大小由数据类型决定
变量在内存中的首地址,成为变量的地址
变量使用时,必须预先说明它们的存储类型和数据类型
<存储类型> <数据类型> <变量名>
存储类型:关键字auto,register,static,extern
只能再某个程序范围使用,通常在函数体内或者函数的复合语句中使用,默认是随机值,默认可以省略
寄存器型,是将变量放入CPU寄存器中,这样可以加快程序的运行速度。如果申请不到就使用一般内存,同auto。必须是cpu所接受的类型,并且不能取地址&(地址用%p输出)
静态存储类型的变量,可以在函数体内,也可以在函数体外。默认是0,每次累加是可以记录的,比如这里,a=5,第二次进来的时候,不会给他赋值5,而是从上一次的a的值开始累加,所以输出6789
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ cat staticTest.c
#include
int main()
{
for(int i=0;i<5;i++)
{
static int a=5;
a++;
printf("%d\n",a);
}
return 0;
}
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ ./staticTest
6
7
8
9
10
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$
因为static变量是用固定地址存放的,而不是用堆栈来存放的
只要程序没结束,就不会被销毁,下次调用该函数的时候不再重新声明,而是保留上次的值
用extern声明,可以用其他文件中的函数或者程序段中的全局变量。static修饰的变量没法被其他文件中通过extern使用
eryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ cat externTest1.c
int a=12;
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ cat externTest2.c
#include
extern int a;
int main()
{
printf("a=%d\n",a);
return 0;
}
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ ./extern
a=12
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ gcc externTest1.c externTest2.c -o extern
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ ./extern
a=12
类型:±*/% ++ –
注意:float/double不能取余
类型:> >= < <= == !=
类型:![取反] 、&&[与,有0就停止]、 ||[或,有1就停止]
运算符 | 功能说明 | 举例 |
---|---|---|
~ | 位逻辑取反 | ~a |
& | 位逻辑与(全1得1) | a&b |
| | 位逻辑或(有1得1) | a|b |
^ | 位逻辑异或(相同为0,相异为1) | a^b |
>> | 右移位 | a>>4 |
<< | 左移位 | b<<4 |
c语言中没有io语句,io操作由函数实现
#include
格式:putchar©
参数:c为字符常量,变量或者表达式
功能:把字符输出到显示器上面
返回值:正常为字符
格式:printf(“格式控制串”,输出表)
功能:按指定格式向显示器输出数据
格式控制串:普通字符远样输出,格式说明%后的字符用来指定输出的格式
格式符 | 作用 |
---|---|
i,d | 十进制整数 |
x,X | 十六进制无符号整数 |
o | 八进制无符号整数 |
u | 无符号十进制整数 |
c | 单一字符 |
s | 字符串 |
e,E | 指数形式浮点小数 |
f | 小数形式浮点小数 |
g | e和f中较短的一种 |
%% | 百分号本身 |
附加格式说明符
m | 输出数据域宽,数据长度小于m,左补空格 |
---|---|
.n | 对实数,指定小数点后位数,对字符串,指定实际输出位数 |
- | 输出数据在域内左对齐 |
+ | 在有符号正数前面显示+号 |
0 | 输出数值时指定左边不使用的空位置自动填0 |
# | 八进制和十六进制前面显示0,0x |
l | 在d,o,x,u前面,指定输出精度为long型 |
l | 在e,f,g前面,指定输出精度为double型 |
printf("%8d,%2d\n",a,a);
printf("%f,%8f,%8.1f",f,f,f);//8.1f输出8位,且小数点后面一位
字符串输出函数puts
修饰符 | 功能 |
---|---|
h | 用于d,o,x前面,指定输入为short整形数 |
l | 用于d,o,x前面,指定输入为long型整数,用于e,f前面,指定输入为double型数 |
m | 指定输入数据的宽度,遇到空格或者不可转换字符结束 |
* | 抑制符,指定输入项后不赋给变量 |
用%c读入的时候,空格和转义字符作为有效字符输入
遇到空格、tab、回车、非法输入、宽度结束数据输入
switch(表达式)
{
case 常量表达式1:语句块1;break;
case 常量表达式2:语句块2;break;
...
case 常量表达式n:语句块n;break;
default:语句块n+1;break;
}
每个常量表达式的值bixu各不相同,否则会出现矛盾
每个表达式的值与case后面的常量表达式相等时,就执行此case后面的语句
switch中表达式可以是整型、字符型表达式或者枚举
case常量:只起语句标号的作用
break是用来跳出循环体的
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ cat loop.c
#include
int main(int argc,const char * argv[])
{
int i=1;
int sum=0;
_loop:
if(i<=100){
sum=sum+i;
i++;
goto _loop;
}
printf("%d\n",sum);
return 0;
}
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ gcc loop.c
beryl@beryl-virtual-machine:~/Documents/chap01_linux/demo01$ ./a.out
5050
当函数有很多个出口,使用goto语句把这些出口集中到一处很方便,特别是函数中有许多重复的清理工作的时候。
略
先判断再执行
略
先执行do里面的再判断
略
break
continue
return
数组是构造数据类型之一
数组是一个具有一定顺序关系的若干个变量的集合,组成数组的各个变量成为数组的元素
数组中各元素的数据类型要求相同,用数组名和下标确定,数组可以是一维的,也可以是多维的
int a[5]={1,2,3,4,5};
内存是一维的,行序优先
char c[10];
strlen:求长度
strcpy:拷贝函数
strcat:字符串连接函数
strcmp:字符串比较函数
strncpy:复制指定长度字符串
strncat:附加指定长度字符串
strcasecmp:忽略大小写比较字符串
strncmp:比较指定长度字符串
strchr:在字符串中查找指定字符
strstr:查找字符串
isalpha:检查是否为字母字符
isupper:检查是否为大写字母字符
islower:检查是否为小写字母字符
isdigit:检查是否为数字
在计算机内存中,每个字节单元,都有一个编号,称为地址
编译或者函数调用的时候,为对应的变量分配内存单元,这个内存单元会有对应的地址,对应地址的空间可以存放对应的变量,所以每个变量都有地址
在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,称为指针变量。可以简单理解为地址=指针=指针变量
一般形式:<存储类型> <数据类型> * <指针变量名>; 如char * p;
指针的存储类型是指针变量本身的存储类型
指针说明时指定的数据类型,而不是指针本身的数据类型。说的是指针指向的变量的数据类型,简称指针数据类型。
比如char *p; p放的是一个地址,这个地址里面存的数据时字符型的
指针在说明的同时,也可以被赋予初值,称为指针的初始化
//把变量a的地址作为初值赋给pa
int a=0;
int *pa=&a;
指针变量也有自己的地址,指针变量存放的是地址
指针的指针指向指针
指针指向的内存区域的数据称为指针的目标,如果他指向的区域是程序中的一个变量的内存空间,则这个变量称为指针的目标变量,简称指针的目标。
int *px=&a;//此时px=&a,*px=a=*(&a);
指针的赋值运算指的是通过赋值运算符向指针变量送一个地址值
向一个指针变量赋值时,送的值必须是地址常量或指针变量,不能是普通的整数(除了赋零之外)
得把一个普通变量的地址赋值给具有相同数据类型的指针
double x=15,*px;
px=&x;
也可以把一个已有地址值的指针赋值给具有相同数据类型的另一个指针变量(两个指针之间也可以赋值)
所以指针既可以是地址,也可以是另一个指针
同一个操作系统,指针占的字节数相同,比如32位(相当于32个1,也就是有0-2^32-1个数字,也就是4G个小单元,32bit=4个字节)所以32位操作系统一般占4个字节,64位占8字节(64bit=8B)
指针运算是以指针变量所存放的地址量作为运算量而进行的运算
指针运算的实质就是地址的计算
指针运算的种类是有限的,它只能进行赋值运算、算术运算和关系运算
运算符 | 计算形式 | 意义 |
---|---|---|
+ | px+n | 指针向地址大的方向移动n个数据 |
- | px-n | 指针向地址小的方向移动n个数据 |
++ | px++ | 指针向地址大的方向移动1个数据 |
– | px– | 指针向地址小的方向移动1个数据 |
- | px-py | 两个 指针之间相隔的元素个数 |
不同数据类型的两个指针实行加减整数运算是无意义的
px+n表示的实际位置的地址量:(px)+sizeof(px的类型)*n
两个指针相减不是得到地址值的差,而是数据量的差,是一个整数值,表示两指针之间相邻数据的个数
二维数组也是连续存储的,按行优先存储
有几行就是几个一维数组,a[3][2]
有3个一维数组,每个一维数组有2个元素。a[0] ,a[1] ,a[2] 都是一维的数组名
a[0]=*a=&a[0][0],a[1]=*(a+1)=&a[1][0],a[2]=*(a+2)=&a[2][0]
二维数组名代表起始地址,数组名加1,是移动一行元素,所以二维数组名是行地址,在这个例子中,a+1,每行两个元素,所以一次性跨过两个元素,**a=a[0][0]
存储行地址的指针变量,叫做行指针变量,形式:<存储类型><数据类型> (*<指针变量名>)[表达式] int (*p)[3]
方括号中的常量表达式表示指针加1移动几个数据
当用行指针操作二维数组的时候,表达式一般写成1行的元素个数,即列数。
a[1][1]=*(*(a+1)+1)
a[i][j]=*(*(a+i)+j)
初始化字符指针是把内存中字符串的首地址赋予指针,而不是把该字符串赋值到指针中,因为不同的字符数组是在不同的地址,是两个不同的局部变量
char str[]="hello world";
char *p=str;//p指向str的首地址
c编程中,当一个字符指针指向一个字符串常量时,不能修改指针指向的对象的值。因为常量是放在固定的区域的,是在静态区的,程序结束才会释放,所以地址不会变的。
char *p="Hello World";
*p='h';//错误,字符串常量不能修改
char *p2="Hello Wrold";
//此时p1p2地址相同,都指向"Hello Wrold"
所谓指针数组是指由若干具有相同存储类型和数据类型的指针变量构成的集合。
指针数组的一般说明形式:
<存储类型> <数据类型> *<指针数组名>[<大小>]
指针数组名表示该指针数组的起始地址,是一个二级指针
int *a[3]表示由三个指针构成的数组,指针是int型的,每个指针都可以指向一个int型变量
把一个指向指针变量的指针变量,称为多级指针变量
对于指向处理数据的指针变量称为一级指针变量,简称一级指针
而把指向一级指针变量的指针变量称为二级指针变量,简称二级指针
二级指针变量的说明形式如下:
<存储类型><数据类型>**<指针名>;
指针变量加1,是向地址大的方向移动一个目标数据。相似的道理,多级指针运算也是以其目标变量为单位进行偏移
比如,int **p;p+1
移动一个int*
变量所占的内存空间。再比如int***p,p+1
移动一个int **
所占的内存空间
指针数组也可以用另外一个指针来处理。例如:有一个一维字符指针数组ps[5]
char *ps[5]={"EDG","RNG","JDG"};
char** pps=ps;
//此时pps每加1就移动到下一个字符串的开头,用*(pps+i)可以拿到下一个字符串
void指针是一种不确定数据类型的指针变量,它可以通过强制类型转换让该变量指向任何数据类型的变量
一般形式为:void * <指针变量名称>
对于void指针,在没有强制类型转换之前,不能进行任何指针的算术运算
#include
int main()
{
int m=10;
float n=3.14;
void *p,*q;
p=(void*)&m;
q=(void*)&n;
printf("%d %f",*(int*)p,*(float*)q);
return 0;
}
void malloc(size_t size);
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void*),void *arg);
void qsort(void *base,size_t nmemb,size_t size),
int(*compar)(const void*,const void*));
1️⃣常量化变量
const int m=10;//此时m的值不能修改了
2️⃣常量化指针目标表达式
*p
,*p
不能变,p可变3️⃣常量化指针变量
<数据类型>*const<指针变量名称>[=<指针运算表达式>]
使得<指针变量>的存储地址不能修改,但是可以通过*pointer来修改指针所指向变量的数值。指针固定指向某个地址,但是可以改变这个地址里存放变量的值
可以让某个地址的变量值改变,const修饰p
,p
不能变,*p可变
const int * const p
的话,*p
和p
都不能变
int main(int argc,const char *argv[]){
int i;
printf("argc=%d\n",argc);
for(int i=0;i
argc表示执行main时传入参数的个数
argv数组存储了传入的参数
函数是指定特定功能的代码块,程序代码独立,通常有返回值,也可以是空值。
函数说明的时候,可以有以下两种写法
double Power(double x,int n);
double Power(double,int);
在函数中的局部变量在函数结束时就消失了,所以不能返回局部变量的地址
全局变量传递
值传递(改变的是函数内的值,不会影响传入的值)
指针传递(改的是地址里面的变量,会影响传入的变量的值,如果用const 那么指针传递也不能改变实参)
全局数组传递
复制传递,实参为数组的指针,形参为数组名,本质上就是一个指针变量
地址传递,实参为数组的指针,形参为同类型的指针变量。
指针函数是一个函数的返回值为地址量的函数
指针函数的定义一般形式:
<数据类型> * <函数名称>(<函数参数>){
函数语句
}
指针函数的返回值:全局变量的地址/static变量的地址/字符串常量的地址/malloc申请的地址(堆栈的地址)
不能返回局部变量的地址,因为在函数执行完之后,局部变量会释放,返回局部变量的地址的话不能再通过地址找到对应的值
递归函数是指一个函数的函数体中直接或间接调用了函数自身
递归函数调用的执行过程分为两个阶段
递推阶段:从原问题出发,按递归公式从已知到未知,最终达到递归终止条件
回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归到原问题求解。
函数指针用来存放函数的地址,这个地址是一个函数的入口地址
函数名代表了函数的入口地址
函数指针变量说明的形式一般如下
<数据类型>(*<函数指针名称>)(参数说明列表)
数据类型是函数指针所指向的函数的返回值的类型
<参数说明列表>应该与函数指针所指向的数的形参说明保持一致
(*<函数指针名称>)
中,*说明指针()不可缺省
int add(int a,int b);
int main(){
int m=10,n=20;
int (*p)(int ,int );
p=add;
(*p)(m,n);
}
int (*p[2])(int,int);