一:系统准备
1.VMware软件安装,用来在现在操作系统下模拟Linux系统而不必重装系统
2.Linux系统安装,推荐使用Ubuntu14.02版本,较为稳定
注意:安装步骤,选择稍后安装虚拟机,完成必要的配置步骤后添加镜像安装
打开VMware workstations→在主页中选择“创建新的虚拟机”→典型→稍后安装系统→选择Linux系统及版本→
选择安装名称和路径→指定硬盘大小→自定义硬件配置→选择安装镜像→完成后启动此虚拟机开始安装→
安装中按顺序要求填写用户名、语言、时区、管理员密码和创建用户等。
建议选择已经配置好的系统,避免学习环境安装而浪费大量时间,且安装系统后的软件升级和配置需求很多其他知识,需要循序渐进
下载配置好的系统,在虚拟机中选择打开虚拟机,选择文件夹后双击.Ubuntu.vmx后即可使用
二、Linux系统下学习C语言的大致框架
1.搭建环境、熟悉Linux下常用命令及vim编辑器
2.C语言发展及基础知识,包含数据类型、变量、常量和运算符和优先级
3.输入输出语句
4.分支、循环语句(即控制语句)
5.数组和字符串
6.指针和数组即字符串
7.函数。
C语言的基础知识大致如此,编程语法和其他编程语言类似,逻辑思维能力需要多敲代码练习
三、Linux系统的基础知识
1.Linux是1991年由林纳斯托瓦斯创建,Linux内核具备以下5种功能①设备管理②文件管理③进程管理④内存管理⑤网络管理
2.Linux文件系统和Windows不同,Linux的层级目录是通过文件系统组织管理,是倒置树结构,没有盘符感念,一切皆文件。
3.Linux文件系统各个目录功能根据FHS(filesystem hierarchy standar)
/ 根目录
/bin 用户命令和二进制文件
/sbin 系统二进制文件
/boot 系统启动相关文件
/etc 系统启动时候用到的配置文件
/dev 设备文件(通过此文件访问设备驱动)
/home 用户家目录
/lib 可执行程序需要连接的库文件
/mnt/hgfs/share 共享目录
4. shell命令
Linux @ Ubuntu : ~
用户名 间隔符 主机名 间隔符 家目录
whoami 查看用户名
hostnamec 查看主机名
$ 符号表示普通用户
#符号表示超级用户
su root 从普通用户切换到root超级用户,输入密码不会显示
sudo passwd root 进行修改超级用户密码
exit 从root退回去Linux用户或退出terminal
用户界面下打开terminal Ctrl+alt+T
terminal状态下打开多个terminal Ctrl+shift+n
①ls命令
ls 显示当前目录文件列表
ls -l 查看文件属性(ll)
ls -a查看所有文件包含隐藏文件(以. .. 开头文件)
ls -lh 把文件大小转换为响应数量级
ls -R 递归显示文件(文件下文件目录)
ls -i 显示文件的iNode号
文件类型: b s p - l c d
块设备驱动文件 套接字文件 管道文件 普通文件 连接文件 字符设备驱动文件 目录文件
权限: rwx rwx r-x (r 4 读 w 2 写 x 1 执行)
用户 组 其他用户
ls -l下 数值(如果是目录,代表子目录个数,如果是文件,代表副本个数)
②cd 命令 切换目录
cd 相对路径/绝对路径
cd cd~ 回到家目录
cd - 回到上一次操作目录
cd ../ 返回上一级目录 cd ../ ../返回上上级目录
cd /mnt/hgfs 以绝对路径方式切换目录
③pwd 显示当前工作路径
④clear 清屏命令(实际是翻页)Ctrl+l
⑤touch 穿件文件命令 touch hello.c
文件不存在即是创建,存在即是修改时间戳
⑥mkdir 创建目录
mkdir hello 创建hello目录
mkdir -m 0664 test 创建一个权限为664的目录
cd test失败的原因可能是test/: Permission denied
mkdir -p hello/test 递归创建目录及子目录
⑦rm 删除命令
rm 文件名 rm *.c *是通配符
rm -rf 删除目录 -r递归删除 -f强制删除
⑧chmod 修改权限 chmod 0664 hello 修改hello文件的权限为664
⑨cp 拷贝命令
cp hello.c hello/ 拷贝hello.c文件到hello目录下
cp hello/ test/ -r (-a)拷贝目录
⑩mv 移动或者重命名
mv hello/ test/ 移动hello目录到hello目录下,如果没有权限 mv前+sudo(cd前不能+sudu,需切换至root后cd)
mv hello.c hello1.c 重命名
⑪ echo 打印
echo 1111 向屏幕终端打印1111
echo 1111 >test.c 向test.c文件中写入1111(重定向,覆盖之前内容)
echo 1111 >>test,c 向test.c文件中追加写入1111(不覆盖,追加写入)
⑫ cat 1.c 将1.c文件的内容在终端上显示
5.vim编辑器命令
在terminal终端上键入vi test.c,即创建一个test.c的文件,如果文件存在则是打开
①命令行模式 下的命令
按Esc进入命令行: yy 拷贝
nyy 拷贝n行
dd 剪切
ndd 剪切n行
p 粘贴
u 撤销
gg=G 对其(或者鼠标左键选择后按=)
/要查找的字符 查找字符串
/^要查找的字符 查找字符串并高亮每行第一次出现的位置
/字符串$ 查找字符串 显示并高亮每行以这个字符串结尾的位置
n 下一个
N上一个
底行模式下 :nohl 取消高亮
插入模式:按a 光标当前位置后插入 A 光标当前行位插入
i 光标当前位置插入 I 光标当前行首插入
o 当前位置下一行插入行 O 光标挡墙行上插入行
底行模式 按空格或者:进入,
:w 保存
:wq 保存并退出
:x 保存并退出
:wqa 保存并退出所有
:q 退出未修改文件
:q! 强制退出
:n 跳转到N行
:nohl 取消高亮
:set nu 显示行号
:set nonu 取消显示行号
:set mouse= 可以拷贝(按住shift鼠标选中后右键可拷贝)
:set mouse=a 取消拷贝
:60,65y 起止行号拷贝 剪切等
:%s/旧/新/g 替换所有行
:vsp 1.c 垂直现在文件打开另一个1.c
:sp 1.c 水平现在文件打开另一个1.c
二、C语言基础知识
编程即是内存申请、内存管理和内存应用的过程
1.一个hello world 程序
#include
// <> 在系统的/usr/include下找头文件
// "" 在当前目录下找头文件
int main()//c代码的入口函数
{
printf("hello world\n"); //printf是一个打印函数,\n 1.换行 2.刷新缓冲区域
return 0;
}
编译代码分四步
1.预处理:头文件展开、宏替换 gcc -E hello.c -o hello.i 不可执行
2.编译:将预处理后文件生产汇编文件 gcc -S hello.i -o hello.s 不可执行
3.汇编:将编译文件生产可执行文件 gcc -C hello.s -o hello.o 可执行但没有库文件
4.连接:将c代码中用到的库文件连接到可执行程序中 可以执行
2.计算机的组成(输入输出设备、控制器、运算器、存储设备、总线)
哈佛结构:指令和数据分开存储的架构,效率高 常用DSP ARM
冯诺依曼结构:指令和数据不分开存储、分时操作,效率低一些,用于早起的x86架构处理器
3.存储器的类型
①cache 高速缓存(i-cache指令缓存 d-cache数据缓存)
②iROM 只读存储器(可存储可执行存放启动代码)
③IRAM 随机存储器 可执行掉电丢失数据
④DRAM/DDR 内存 可执行掉电丢失数据
⑤flash 硬盘
Nor flash Nand flash Emmc 机械硬盘
4.数据表示(计算机内只能以0 1 形式存储数据)
进制:二进制0b 八进制 0 十进制 十六进制0x (几进制就是逢几进一),进制的相互转换(8进制占3位,16进制占四位转换)
计算机中,数据以补码形式储存,正数源码反码补码一致,负数源码最高位是符号位,反码除符号位其他翻转,补码是反码+1
补码的补码是源码 -128 10000000(特殊记住)
1bit
1byte = 8bit
1KB =1024byte
1M =1024kb
1G =1024Mb
1T =1024Gb
1Pb =1024Tb
5 .字符:根据ASCII表,不同字符有对应的0~255编码,特殊字符如‘a’‘A’‘0’'\0'等
6.C语言中的数据类型
①基本类型
字符 char unsigned char 1字节
整形 short (2字节) int(4字节) long(4字节) long long(8字节)
实型 float(4字节) double(4字节) long double(12字节)
枚举 enum
②构造类型:数组 结构体 共用体
③指针类型
④空类型 void
注意:数据类型间可以强制转换,但是可能存在损失精度的风险,一般不转化
大端小端问题:定义一个int类型,强制转换为char类型,取出的数值是高位是小端,取出的是低位是大段
大端:高位存在低字节
小端:高位存在高字节
7.C语言中的变量声明(内存申请)
<储存类型><变量类型><变量名>
存储类型:auto register static const volatile extern
变量类型即是数据类型
变量名:①以字母数组下划线组成,且以字母或者下划线开头
②:不能是32个关键字
③ 大小写区分
④见名知意
8.C语言中的常量
①.整形常量
②实型常量
③字符常量
④字符串常量
⑤标识常量 define(宏)
#define M 5+1 预处理阶段原样展开。不计算
#define S(a) #a 字符串化
#define S(a,b) a##b 字符串拼接
9.c语言中的运算符
()在前,单算移关与,异或逻条赋,逗号(按照优先级)
注意:使用异或(加法)可以在不定义新的变量下 实现数值交换
a^=b
b^=a
a^=b
a=a+b
b=a-b
a=a-b
注意:使用移位和或运算,实现高低位翻转(偶数位与1,左移一位 | 奇数位与1 右移1位),相邻一位对调 2位对调 4位对调
条件运算符?: a>b?a:b
10.C语言中的输入输出语句
①printf 格式化输出 %d %s %u %p %o %x %c %e %g %# %f %lf
%4d 打印数占4个字符单元 前面补空
%04d 打印数占4个字符单元,前面补0
%-4d 左对齐
%ld long
%ld double
%.2f 显示小数点后两位
%Lf long double
②scanf
scanf("%d%c%s%f",&a,&b,&c,&d);
scanf("%d",&a);
scanf("%c",&b);
1.scanf在使用的时候它不会读取最后一个\n 的字符,可以使用%*c来吃掉一个字符。
2.scanf如果需要连续输入两个(多个)整数,scanf("%d%d",&a,&b); 它会吃掉空格,回车,tab
3.scanf双引号是什么格式,终端输入就是什么格式,scanf("%d,%d",&a,&b); -->1231,123
4.scanf在连续输入的时候,它会把空格,tab,回车作为结束,如果不想以空格或tab作为结束,
scanf("%[^\n]",c) //只把\n作为结束符,可以读取\n之外的所有字符
5.如果scanf按照如下方式来实现
scanf("%d\n",&a);
printf("%d\n",a);
scanf("%d\t",&a);
printf("%d\n",a);
scanf("%d ",&a);
printf("%d\n",a);
输入一个整数之后,在额外输入一个字符(任意的),它就会结束了
③getchar
函数原型:int getchar(void);
功能:输入一个字符
参数:@ 无;
返回值:成功返回字符的ascii,失败返回-1;
1.getchar的用法
char a;
a = getchar();
printf("%c\n",a);
2.getchar吃掉字符
int a;
char b;
scanf("%d",&a)
b = getchar();
3.在函数内部定义的变量默认是随机值,全局变量默认的值是0;
④putchar()
函数原型:int putchar(int c);
功能:输出一个字符
参数:@c:想要输出的字符(ascii)
返回值:成功返回字符的ascii,失败返回-1;
一般用法:
putchar(a);
putchar('\n');
putchar('A');
putchar('\n');
putchar(65);
putchar('\n');
⑤gets()
函数原型:gets(char *s);
功能:读取多个字符
参数:@s 数组的名字
注意:
gets会将缓冲区中所有的字符全部读入,不管内存是否越界。
gets会在最后的位置补充\0
char a[50];
gets(a);
⑥puts()
函数原型:int puts(const char *s);
功能:输出多个字符
参数:@s 数组的名字
注意:puts只能用于输出多个字符(字符串),puts会自动补充\n
用法:
char a[50];
puts(a);
puts("hello world");
puts(""); ---->自动输出一个换行
area.c:(.text+0x130): undefined reference to `sqrt'
collect2: ld returned 1 exit status
该错误是未有链接文件,需gcc area.c -lm
注意,自行定义的头文件格式位.h文件
#ifndef __HEAD_H__
#define __HEAD_H__
int add(int a,int b);
#endif
11.C语言中的控制语言
①if 、if/else 、if/elseif........
②switch/case/default(case语句执行到遇到break,没有break则执行到最后,default语言在case都不执行时候执行,也是遇到break或到最后 )
③循环for(语句1;语句2;语句3),循环三要素 初始条件 判断条件 结束条件
for循环执行顺序为,语句1,语句2,循环体,语句3,语句2.。。。。。。
while()先判断后执行
do while 先执行后判断
④continue 结束本次循环进行下一次循环,break,结束当前循环体
⑤goto 无条件跳转语言,只能在本函数内部跳转,需要一个标签(一般最为错误的统一处理口)
⑥return 结束函数或将行数返回值返回给调用者
12.C语言中的数组
①.数组为构造类型,是基本类型的多个元素组合
②.数组内元素数据类型必须一致
③.数组在内存上连续
④.数组不进行越界检查
⑤.数组名是数组首地址(a+1 &a+1 &a[0]+1,移动步长为对应类型大小)杜绝a++ ,可以a+1
char a[5],方括号内必须是常量
⑥数组赋值:①初始全部赋值,部分赋值(未赋值元素为0,)
②数组大小根据赋值数确定大小int a[] = {1,2,3,4}
先定义后赋值需要借助循环赋值
sizeof函数可以测量数组长度 sizeof(a)/sizeof(a[0])
⑦冒泡排序
for(i=0;i
a[-1],是数组前一个元素,不定值,不建议使用,数组不进行越界检查
⑨.二维数组 行号可以省略,列不可省略,二维数组名字也是常量,也不可a++
⑩.一维字符数组(以‘\0’结束就是字符串数组,字符串数组可以%s输入或者输出)
⑪.二维字符串数组,字符串的集合
13 C语言中的指针
地址:在计算机中,地址是以字节为单位进行编号,管理内存,每一个内存区域都有一个编号,这个编号叫做地址
指针:指针就是指向地址的
指针变量:存放地址的变量就叫做指针变量
内存分类:
①堆区:需要手动申请和释放(malloc/free函数)
②栈区:用户的函数、局部变量,是由操作系统自行申请和释放的
③.bss:全局未初始化的变量以及static修饰的变量
④.data:存放用户的数据
⑤.ro:存放字符串常量
⑥。text:文本段
1.指针的定义 :<存储类型><数据类型>*<变量名>
char *p;
short *t;
int *q; //*这里的*是一个标识符,//代表定义的是指针类型的变量
sizeof(char *); //4 p+1 移动1字节
sizeof(int *); //4 q+1 移动4字节
sizeof(short *);//4 t+1 移动2字节
指针均占4个字节,指针加1,移动相应数据类型步长
2.和指针相关的符号
* //取出地址中的内容
& //取地址符
3.一维数组和指针
int a[3];
int *p = a;
数组访问:a[i] <=====>p[i] <====> *(a+i) <====>*(p+i)
注意:
p++ //可以
a++ //不行,原因a是数组名,它是常量不能做加减操作。
4.指针和字符串
char *p = "hello world"; 定义一个指针,指向字符串常量,*p内容不可以修改
*p = 'a'; //错误的
p++; //可以
char buf[] = "hello world"; //在栈上存放
char *a;
char str[];
buf[0] = 'a' //可以
buf++; //错误的
a = "hello world"; //可以
str = "hello world";//错误
5.指针和二维数组,
注意:将数组名赋值给一级指针时候报错,类型不匹配,需要将数组名赋值给 (同步长数组指针)
6指针数组:int *p[3],一个数组,数组元素为指针
7.二级指针:指向一级指针的指针,通常用着传参函数中的套用函数传参
8.数组指针 int (*p)[3] 它是一个指针,指向的是一个数组。这个数组(每一行有三个成员)
数组指针和二维数组和相互对应的。数组指针和二维数组相对对应
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3];
p = a;
a[i][j]<====>*(a[i]+j)<=====>*(*(a+i)+j)<======>
p[i][j]<====>*(p[i]+j)<=====>*(*(p+i)+j)
a+1 //移动一行,3(一行的成员个数)* sizeof(int)
&a[i]+1 //移动一行,3(一行的成员个数)* sizeof(int)
&a+1 //移动整个数组,3(三行)*3(一行的成员个数)* sizeof(int)
a[i]+1 //移动一个成员的大小,sizeof(int);
&a[0][0]+1 //移动一个成员的大小,sizeof(int);
9.sizeof和strlen的区别
1.sizeof是关键字,strlen是函数。
2.sizeof可以求类型的大小,strlen求字符串成员的个数
3.sizeof(buf) = 10(不包含'\0'); strlen(buf) = 5(数组长度);
14.C语言中的数据存储类型
定义变量
<存储类型> <变量类型><变量名>;
auto :自动 auto int a;
定义局部变量的时候,int a;前面其实是省略了auto。
当函数执行的时候变量会被申请,当函数执行完的时候
变量会被销毁。
非自动类型的变量:全局变量或者static修饰的变量。
static :1.延长变量的生命周期
void swap()
{
static int a=3; //int a=3;
printf("%d\n",a++);
}
2.限制作用域(只能在本文件内使用)
static int a;
static void hello()
{
printf("hello");
}
register :寄存器
register int a = 5;
定义寄存器类型的变量,但是由于芯片内部的寄存器的个数是有限制的。
所以在使用的时候注意使用的次数。寄存器类型的变量要比普通的变量
读写的效率高。
extern :外部的,可以在其他文件中调用
extern int a;
extern int add(int a,int b);
const :它修饰的是一个只读的变量,修饰的不是常量。
const int a = 5;
a = 100; =>error: assignment of read-only variable ‘a’
const char *p; => const *p; //p指向的内容不可修改
char const *p; => const *p; //p指向的内容不可修改
char * const p;=> const p; //p指向的地址不可以修改
const char *const p; //指向的地址和内容都不可修改
char const *const p; //指向的地址和内容都不可修改
注意:把数据类型去掉后,const修饰的是谁,它就是一个只读的。
volatile :字面含义(易变的)
(volatile unsgined int *)0x50000000
假如刚开始0x50000000中保存的是0x12345678;
如果这里不加volatile,编译会对其进行优化,下代码中只要用到
0x50000000地址中的值的时候,它取得都是0x12345678这个值。但是
在操作系统运行的时候,可能会去修改0x50000000地址中的值。代码
是不能取出到最新值的。
volatile告诉编译器不对代码进行优化,每次在用这个地址中的值的
时候,都要重新从这个地址中来取数据,所以加了volatile之后就能保证
取到的都是最新的数据。
15.C语言中的函数(函数是c语言最基本的组成单元)
函数就是一个实现特定功能的代码集合,函数封装要遵从高内聚低耦合
函数三要素:①功能唯一 ②输入 ③输出
函数类型
<存储类型><返回值类型><函数的名字>(参数列表)
{
语句;
return;
}
注意:函数的使用要:先声明后使用,先使用的先声明
函数的参数:
1.参数的成员的个数一般小于等于4(效率高)
2.函数的中的参数的名字叫做形式参数,形式参数(函数内部的变量)当函数被调用的时候分配内存,在函数执行结束的时候,形参所占的内存
就会被释放。
3.实参数:在main中定义的变量,int a = 5; int b =100 =>a就是实参,add(a,b);实际参数可以的变量,常量,表达式,地址。
参数传递分为:
值传递:不可以交换数据
地址传递:可以交换数据
传递数据:不是将整个数据都传递过去了,它是将数据的首地址传递过去了。
传递数组:
int func(int buf[100],int n)
{
sizeof(buf);
}
传递的是数组的首地址,在函数中sizeof(buf) == 4;
传递函数:传递的是函数的首地址
int func(int (*fn)(int ));
int func(int fn(int ));
函数使用中,会用到嵌套函数(函数内部调用其他函数)
递归函数(自己调用自己)
指针函数(返回值是指针的函数)
函数指针(即函数名) int (*p)(int a, int b)
函数指针数组(数组元素是函数指针的数组) int(*p[3])(int a, int b)
函数指针数组指针:是一个指针,这个指针指向函数指针数组
16 typedef 关键字 类型重命名,定义变量时候,将变量名去掉,改为想定义的名称即可
typedef int INT_32; int
typedef int INT_ARR[3]; int a[]
typedef int INT_ARR_2[3][2]; int a[][]
typedef int * INT_P; int *p
typedef int * INT_A[3]; int *p[3]
typedef int (*ARR_P)[3]; int (*p)[3]
typedef int FUNC (int a,int b);
typedef int (*FUNC_P)(int a,int b);
添加新的知识点:1.float和double类型数据不能判断是否等于0(根据float的存储方式,永远不等于0)
2、#define PI 3.1415 这里的PI是文本替换,是(字符串类型而非常量)