** 1:原码、反码、补码**
规定:
5
0000 0101 负数:-5 0000 0101 最高位为符号位 最高位为 1 代表是个负数 原码: -5 1000 0101 反码:除了符号位 其他位取反 1111 1010 补码:反码 +1 1111 1011 注意:负数在内存中是以补码形式存放的
是静态的意思
static 可以修饰全局变量、局部变量、函数
存储类型
auto extern re static
在 c 语言中给变量和函数起名的时候,由字母、数字、下划线构成
必须以字母或者下滑线开头 例 5: int a2;//正确的 int a_2;//正确的 int _b;//正确的 int 2b;// 错误的 int $a2;//错误的
char 、short int 、int、long int、float、double
整型 100,125,-100,0 实型 3.14 , 0.125f,-3.789 字符型 ‘a’,‘b’,‘2’ 字符串 “a”,“ab”,“1232”
float a= 12.5f;
unsigned long = 232324343443ul;
1.对于输出%m.nf格式:
m表示要输出这个数的宽度,包括小数点,如果实际数值的宽度大于m,则以实际的数据宽度为准,如果实际数值宽度小于m,那么默认右对齐,前面补空格。
n表示小数点后面数据的位数。
public static void main(String[] args) { float x=1.456f; System.out.printf("%3.2f",x); }
输出:1.46
public static void main(String[] args) { float x=1.456f; System.out.printf("%13.3f",x); }
输出: 1.456(前面有8个空格)
m表示要输出这个数的宽度,包括小数点,*如果实际数值的宽度大于m,则以实际的数据宽度为准,如果实际数值宽度小于m,那么默认右对齐,前面补空格。*
注意:对于浮点型变量,小数点后默认有6位小数。
public static void main(String[] args) { double x=1.456; //实际数据为1.456000 System.out.printf("%4f",x); }
输出:1.456000
字符数据 字符常量: 直接常量:用单引号括起来,如:'a'、'b'、’0’等. 转义字符:以反斜杠“\”开头,后跟一个或几个字符、如'\n','\t'等,分别代表换行、横向跳格. ‘\’表示的是\ ‘%%’ ‘\’’ 字符变量: 用 char 定义,每个字符变量被分配一个字节的内存空间 字符值以 ASCII 码的形式存放在变量的内存单元中; 注:char a; a = 'x'; a 变量中存放的是字符'x'的 ASCII :120
字符串常量 是由双引号括起来的字符序列,如“CHINA”、”哈哈哈” “C program”,“$12.5”等都是合法的字符串常量. 字符串常量与字符常量的不同 ‘a’为字符常量,”a”为字符串常量 每个字符串的结尾,编译器会自动的添加一个结束标志位'\0',
%d 十进制有符号整数 %u 十进制无符号整数 %x, 以十六进制表示的整数 %o 以八进制表示的整数 %f float 型浮点数 %lf double 型浮点数 %e 指数形式的浮点数 %s 字符串 %c 单个字符 %p 指针的值 特殊应用: %3d %03d %-3d %5.2f %3d:要求宽度为 3 位,如果不足 3 位,前面空格补齐;如果足够 3 位,此语句无效 %03d:要求宽度为 3 位,如果不足 3 位,前面 0 补齐;如果足够 3 位,此语句无效 %-3d: 要求宽度为 3 位,如果不足 3 位,后面空格补齐;如果足够 3 位,此语句无效 %.2f:小数点后只保留 2 位
1)当表达式中出现了 char 、short int 、int 类型中的一种或者多种,没有其他类型了 参加运算的成员全部变成 int 类型的参加运算,结果也是 int 类型的
例 8: #includeint main(int argc, char *argv[]) { printf("%d\n",5/2); return 0; }
如何实现类型转换 默认:整数就是int 小数就是double
short s = 10;(float )
float f= 12.5;(double型)
int a = 12.5; (double型)
char --> unsigned char ---> short ---> unsigned short ---> int ---> unsigned int ---> long ---> unsigned long ---> long long ---> unsigned long long ---> float ---> double ---> long double
2) 当表达式中出现了带小数点的实数,参加运算的成员全部变成 double 类型的参加运算,结果 也是 double 型。
例 9: #includeint main(int argc, char *argv[]) { printf("%lf\n",5.0/2); return 0; }
3) 当表达式中有有符号数 也有无符号数,参加运算的成员变成无符号数参加运算结果也是无符 号数.(表达式中无实数)
例 10: #includeint main(int argc, char *argv[]) { int a=-8; unsigned int b=7; if(a+b>0) { printf("a+b>0\n"); } else { printf("a+b<=0\n"); } printf("%x\n",(a+b)); printf("%d\n",(a+b)); return 0; }
4) 在赋值语句中等号右边的类型自动转换为等号左边的类型
例 11: #includeint main(int argc, char *argv[]) { int a; float b=5.8f;//5.8 后面加 f 代表 5.8 是 float 类型,不加的话,认为是 double 类型 a=b; printf("a=%d\n",a); return 0; }
5) 注意自动类型转换都是在运算的过程中进行临时性的转换,并不会影响自动类型转换的变量的 值和其类型
例 12: #includeint main(int argc, char *argv[]) { int a; float b=5.8f;//5.8 后面加 f 代表 5.8 是 float 类型,不加的话,认为是 double 类型 a=b; printf("a=%d\n",a); printf("b=%f\n",b);//b 的类型依然是 float 类型的,它的值依然是 5.8 return 0; }
通过类型转换运算来实现 (类型说明符) (表达式)
功能: 把表达式的运算结果强制转换成类型说明符所表示的类型 例如: (float)a; // 把 a 的值转换为实型 (int)(x+y); // 把 x+y 的结果值转换为整型 注意: 类型说明符必须加括号
例 13: #includeint main(int argc, char *argv[]) { float x=0; int i=0; x=3.6f; i = x; i = (int)x; printf("x=%f,i=%d\n",x,i); return 0;
1、&& 逻辑与 两个条件都为真,则结果为真 if((a>b) && (a
无论是正数还是负数,编译系统都是按照内存中存储的内容进行位运算。
1、&按位 与 任何值与 0 得 0,与 1 保持不变 使某位清 0 0101 1011& 1011 0100 0001 0000 2、| 按位或 任何值或 1 得 1,或 0 保持不变 0101 0011 | 1011 0100 1111 0111 3、~ 按位取反 1 变 0,0 变 1 0101 1101 ~ 1010 0010 4、^ 按位异或 相异得 1,相同得 0 1001 1100 ^ 0101 1010 1100 0110 5、位移
右移 << 左移 注意右移分:逻辑右移、算数右移 (1)、右移 逻辑右移 高位补 0,低位溢出 算数右移 高位补符号位,低位溢出 (有符号数) A)、逻辑右移 低位溢出、高位补 0 0101 1010 >>3 0000 1011 B)、算数右移: 对有符号数来说 低位溢出、高位补符号位。
010 1101 >> 3 1111 010 1 0101 0011 >>3 0000 101 0 总结 右移: 1、逻辑右移 高位补 0,低位溢出 注:无论是有符号数还是无符号数都是高位补 0,低位溢出 2、算数右移 高位补符号位,低位溢出 (有符号数) 注:对无符号数来说,高位补 0,低位溢出 对有符号数来说,高位补符号位,低位溢出 在一个编译系统中到底是逻辑右移动,还是算数右移,取决于编译器
判断右移是逻辑右移还是算数右移 #includeint main(int argc, char *argv[]) { printf("%d\n",-1>>3); return 0; } 如果结果还是-1 证明是算数右移
(2) 左移<< 高位溢出,低位补 0 5<<1 0000 0101 0000 1010
例 18: #includeint main(int argc, char *argv[]) { int i=3; int num; num = (i++)+(i++)+(i++); printf("num=%d\n",num); return 0; }
例 19: #includeint main(int argc, char *argv[]) { int i=3; int num; num = (++i)+(++i)+(++i); printf("num=%d\n",num); return 0; }
注意 if 和 else 之间只能有一条语句,或者有一个复合语句,否则编译会出错
例 22: if() 语句 1; 语句 2; else 语句 3; 语句 4;
TCP/IP
用来检测网络传输中差错的传输控制协议TCP
专门负责对不同网络进行互联
物理层 数据链路层 网络层 传输层 会话层 表示层 应用层
物 数 网 传会 表 应
扩展:如果在一行中定义多个指针变量,每个指针变量前面都需要加*来修饰 int p,q;//定义了两个整型的指针变量 p 和 q int * p,q;//定义了一个整型指针变量 p,和整型的变量 q
c 语言规定:数组的名字就是数组的首地址,即第 0 个元素的地址,就是&a[0],是个常量。
int a[5]; int *p; p=a; *(p+2)=100;//也是可以的,相当于 a[2]=100
p 是第 0 个元素的地址,p+2 是 a[2]这个元素的地址。 对第二个元素的地址取值,即 a[2]
一维数组名字取地址,变成一维数组指针,即加 1 跳一个一维数组 int a[10]; a+1 跳一个整型元素,是 a[1]的地址 a 和 a+1 相差一个元素,4 个字节 &a 就变成了一个一维数组指针,是 int(*p)[10]类型的。 (&a) +1 和&a 相差一个数组即 10 个元素即 40 个字节。
引用数组元素回顾: a[2]、*(a+2)、p[2]、
*(p+2) 都是对数组 a 中 a[2]元素的引用。
11:sizeof strlen的区别
sizeof 它的功能是: 获得保证能容纳实现所建立的最大对象的字节大小(包括\0)。
strlen(只与字符串相关)只关心存储的数据内容,不关心空间的大小和类型。sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。 (求字符串长度) sizeof还可以用函数做参数,比如: short f(); printf("%d\n", sizeof(f())); 输出的结果是sizeof(short),即2。 例子
char str[20] = “0123456789”; int a = strlen(str); int b = sizeof(str);
这时的 a = 10,b = 20;因为strlen计算的是字符串的长度,以’\0’为字符串结束标志;而sizeof计算的是分配的数组str[20]所占的内存空间的大小,不受里面存储的内容影响。
char *str1 = “abcde”; char str2[] = “abcde”; char str3[8] = {‘a’}; char ss[] = “0123456789”;
其计算结果为: sizeof(str1) = 4; sizeof(str2) = 6; sizeof(str3) = 8; sizeof(ss) = 11;
str1 是一个指针,只是指向了字符串"abcde"而已。所以sizeof(str1)不是字符串占的空间也不是字符数组占的空间,而是一个指针所占的空间。在C/C++中一个指针占四个字节。 str2是一个字符型数组,对于一个数组,返回这个数组所占的总空间,所以sizeof(str2)取得的是字符串"abcde"的总空间。"abcde"中,共有a b c d e \0六个字符,所以str2数组的长度时6,。 str3已经定义成了长度为8的数组,所以sizeof(str3)为8; str4和str2类似,共十一个字符,所以ss所占的空间是11.
数组除去数组名就是数组类型
int arr[10]; int [10]类型 注意 下面两个描述都能表示 arr[2]-->*(arr+2); 2[arr]-->*(2+arr);
一旦数组被定义,那么只能通过下标的方式 存入数据
二维数组
初始化有两种方式(把一行看成一个元素)
int [2][2] = {1,2,3,3}; int [2][2] = {{1,2},{3,3}}; int [][2] = {2,2,3,4}; 可以没有行不能没有列 存储机制是先存完一行,再接着存一行 第一行首地址a[0] 第二行首地址a[1]
数组名是首元素地址但是有两个是例外
sizeof(arr) 这里的arr 数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节
& 数组名,数组名代表整个数组,&数组名,取出的是整个数组名的地址
&arr
文件包含 宏定义 条件编译
文件包含语句的功能是把指定的文件插入该语句行位置
一般形式为
#include"" #include<> #include <> 和 "" 区别: <> 去系统提供的路径下去寻找 /usr/include ... "" 去自己定义的路径下寻找,如果没有找到,就去系统提供的路径下寻找 #include "带路径的.h文件" 例子: #include "~/xx/yy/include/zz.h"
使用尖括号表示在系统头文件目录去查找,双引号表示首先在当前源文件目录去找,若未找到才到系统头文件目录中去找
gcc
gcc -v -Wall -O0 -g -E //预处理 -S //编译 -c //汇编 -o //生成 -v //详细显示 -Wall //详细警告 -On // n是个数字 优化程度 -O0 不优化 -O1 -O2 数字越大,优化程度越高,编译时间越长,执行时间越短 -g // 可以进行 gdb 调试
gdb
gdb 调试 : (运行时候错误查找) * 安装gdb sudo apt-get install gdb *编译的时候,后面要加 -g *为什么要用? 一步一步调试,查找段错误的位置 *如何使用: gdb 可执行文件 例子: gdb xx l : list显示代码 r : run 运行 start : 启动 n : next 不进入函数,直接执行 s : step 进入到每一个函数里面 p 变量名字 : printf 变量 例子 : p i 打印出i的值 b n : breakpoint n: 行 例子: b 15 i b : infomation breakpoint 查看所有的断点 d 编号 : delete num 例子: d 3 //删除编号为3的断点 c : continue 继续 一个断 q : quit : 退出
make
make: *> make是一个项目管理工具 *> 使用: *》安装make sudo apt-get install make *》书写 Makefile 的文件 *》按照make的规则,在Makefile中书写 代码 *Makefile基本姿势: 目标 : 依赖 (tab键) 命令 *声明: 依赖可以没有 命令也可以没有 目标就是我们要生成的东西 如果不需要生成目标,称该目标为伪目标 (.PHONY:clean) *make的使用: make 目标 : 查看该目标文件是否存在,如果存在是否为最新。 如果不存在,则去生成,如果不需要生成,则该目标为伪目标 如果目标是整个Makefile中的第一个目标, 可以省略不写 *》优势:时间戳管理方式: 如果依赖没有目标新,那么就不需要重复编译,否则谁最新就编译谁 *》依赖文件必须存在,如果依赖不存在,make想方设法去生成(将其作为目标去生成) cc -c -o xx.o xx.c 这是 Unix操作系统(linux)默认的编译方式 gcc -c -o xx.o xx.c 这是GNU组织的c语言编译器 sudo apt-get install gcc sudo apt-get install gdb sudo agt-get install make *伪目标: 我们不需要生成该文件,如果在项目中有该文件,则该伪目标由于没有依赖,永远是最新,顾不再执行,解决方式 .PHONY : 伪目标 * 变量赋值: * 简单赋值 := 在当前行有效 * 递归赋值 = 递归查找某变量的最后一个值 * 条件赋值 ?= 如果某变量已经定义,那么该语句无效 * 追加赋值 += 对某个变量进行追加操作 * 如果想隐藏命令(只执行,不显示),在命令前面加上@ echo : 打印的命令 * $^ ---> 代表所有的依赖 $@ ---> 代表目标 $< ---> 代表第一个依赖 1. make -C 文件夹(目录) -----》执行该 目录 下面的 Makefile下的第一个目标 make -C 文件夹(目录) 目标 -----》执行该 目录 下面的 Makefile下的目标 ====================== 内联函数: 不是函数 写在 .h 文件中 如果有人调用该函数,将其函数体全部拷贝过去
进制不过是对数的描述(就像一个人有多个名字)
一个整数四种表示
八进制 标志:0(零)
十六进制 标志 :0x 0X
十->二 十->八 十->十六 以上都是除X逆向取余
二->十(权位相加)
八->十(权位相加)
十六->十(权位相加)
%d -----> 以 int 类型输出 %hd -----> 以 short 输出 %hhd -----> char类型的10进制输出 %ld -----> long %lld -----> long long %c -----> 以字符形式打印 %s -----> 字符串 %x -----> 16进制打印 不带标志位0x %o -----> 8进制打印 不带标志位0 %#x -----> 16进制打印 带标志位0x !!!!! %#o -----> 8进制打印 带标志位0 !!!! %u -----> unsigned int %lu -----> unsigned long %llu -----> unsigned long long %hu -----> unsigned short %hhu -----> unsigned char %f -----> float 保留6位小数 !!!! %lf -----> double 保留6位小数 !!!! %g -----> float double 保留有效 !!!! float f = 0.00009000; printf("%g\n",f); 输出 9e-05 float f = 12345678; printf("%g\n",f); 输出1.23457e+07 %g用于打印浮点型数据时,会去掉多余的零,至多保留六位有效数字(不同于%e的默认保留小数点后6位) 1. 当%g用于打印超过6位的浮点型数据时,因为精度问题,%f不得不输出一个不精确的超过六位的数字,%e也是同样,而%g此时会选择%e格式进行输出,并且按第一条要求,去掉多余的零,并且四舍五入到6位数字。这是《C Primer Plus》中所说的超过精度的时候的情况。 (可见,这个6位,是按float类型精度来计算的。) 2. 当一个数字的绝对值很小的时候,要表示这个数字所需要的字符数目就会多到让人难以接受。举例而言,如果我们把π*10^-10写作0.00000000000314159就会显得非常丑陋不雅,反之,如果我们写作3.14159e-10,就不但简洁而且易读好懂。当指数是-4时,这两种表现形式大小相同。对于比较小的数值,除非该数的指数小于或者等于-5,%g才会采用科学技术发来表示,即,以%e的格式进行输出。 * 浮点型变量存储 单精度: float ----》 4个字节 1个符号位 8个指数位 23个小数位 float xx = -25.5; 25.5 ---> 二进制: 11001.1 ---> 1.10011*2^4 1个符号位: 1 8个指数位: 01111111 + 4 ---》 10000011 23个小数位: 10011000000000000..... 1 10000011 10011000000000....
双精度: double ----> 8个字节 (64个位) 1个符号位 : 0正数 1负数 11个指数位 : 01111111111 ----》 指数0 52个小数位 : 例子:(小数存储) double d = 520.250; 520 ---> 1000001000 0.25 ---> 0.01 ====> 1000001000.01 ---> 1.00000100001*2^9 符号位: 0 指数位: 01111111111 + 9 ---》 10000001000 小数位: 00000100001000000000...... 52位 520.250的存储为: 0 10000001000 00000100001000000000......
(18以下)
sudo /etc/network/interfaces
sudo vim /etc/netplan/*.yaml(18版本以上)
else 离他最近的if相匹配
为了避免出错加花括号
if 语句的时候() 里面有常量 与变量比较的时候
格式(4 == num)这样写比较好 容易看出问题
break 跳出本层循环
continue 跳出本次循环(后面代码不执行)
输入缓冲区
for(初始化;判断;调整)简单明了
while有可能迷失条件
for循环注意
1:不可在for循环体内修改循环变量,防止for循环失去控制
2:建议for语句的循环语句控制变量的取值采用“前闭后开区间”写法
int ret,ch; char password[20] = {0}; printf("请输入密码:>"); scanf("%s",password); while((ch = getchar()) != '\n') { ; } printf("请输入(Y/N)"); ret = getchar(); if(ret == 'Y') { printf("确认成功"); } else { printf("放弃确认\n");
3;一些for循环的变种
for(;;)死循环
for (x = 0, y = 0; x<2 && y<5; ++x, y++)
表达一条语句{}
三角形
* *** ***** ******* *********
#includeint main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { for(int j=1;j<=n-i;j++) printf(" "); for(int k=1;k<=2*i-1;k++) printf("*"); printf("\n"); } return 0; }
倒三角形
********* ******* ***** *** *
#includeint main() { int n; scanf("%d",&n); for(int i=n;i>0;i--) { for(int j=1;j<=n-i;j++) printf(" "); for(int k=1;k<=2*i-1;k++) printf("*"); printf("\n"); } return 0; }
菱形
#include int main() { int n,i,j,k; scanf("%d",&n); n=n/2+1; for(i=0; i =0; k--) printf("%c ",'*'); putchar('\n'); } return 0; }
void 函数名(类型名 ,类型名 )
return 0;可以省略
结束资源管理
一些函数
strcpy
比较
值传递
址传递
bzero(&a,4);
size_t
memset
strlen(字符串计数)
strate
const ---->修饰的变量不能改变
a的值在内存volitile(易变值防止cpu优化)
32位
4G虚拟内存怎么算的
一堆指令的集合a.out
char arr[30] = "ejfofif";
char *p = "fewofjf";(存在常量区)
const char p[20] ="fjfief";(在栈空间)
分页
(int *)malloc (9)//不被允许这样写(12)
指针减去指针 等于指针相差个数
指针数组
int a = 10; int b = 20; int c = 30; int *arr[3] = {&a,&b,&c};(指针数组) int i= 0; for(i = 0;i<3;i++) { printf("%d ",(arr[i])); } return 0;
字符数组
char * p = "cuffjfrf";
int (*a[10])[10]
int (*)[10]
去掉名字就是类型
一维数组
int arr[10] ={0};
test(arr);
test2(arr2);
二维数组
int arr[3][5 = {0};
test(arr);
函数指针
&函数名 和 函数名 都是函数的地址
int Add (int x,int y ) { ; } int (*pa)(int,int) = Add; int (*pa1)(int,int) = &Add;
int (*p)(int);
一些有趣的题目
代码1 (*(void (*)())0)(); 解:把0强制类型转换成:void(*)()函数指针类型 0就是一个函数的地址 调用0地址的该函数 代码2 void (*signal(int,void(*)(int)))(int); 一个函数 signsl参数为int型 和函数指针型 返回值是一个函数指针
1》概念: 自己定义的类型
2》姿势:
struct{结构成员;结构成员;}; struct{int len;int h;int w;} xx; xx.len = 20; xx.h = 160; xx.w = 160; struct 结构标记{结构成员;结构成员;}; *结构标记 结构成员 及变量名字可以相同 例: struct x{int x;}; struct x x; --- 没有问题 struct x{int x;} xx; struct x xx; ----》 以上两种方式是一样的
声明一个类型 struct xx { int len ; int h; int w; }; struct{int len;int h;int w;} xx; xx.len xx.h xx.w struct 结构标记{结构成员;结构成员;}; struct x{int x;}; struct x x; 以上两种都可以定义变量 声明一个类型 struct mm{ int h; int w; int xw; int yw; int tw; char name[20]; char addr[20]; } struct mm sm; strcpy (sm.name,"小郭子"); sm.h = 159; sm.w = 234; ..... struct mm *pp = &sm; pp->h = 159; printf("%d",pp->h); 面向对象 面向过程 去北京 一步一步
8》结构体算字节数
* 32位操作系统最大按照4字节对其 * 64位操作系统最大按照8字节对其 * 每个数据成员存储的起始位置是自身大小的整数倍 * 结构体总大小(也就是sizeof的结果),必须是该结构体成员中最大的对齐模数的整数倍
9》手动修改结构体的对其方式 #pragma pack(n) n为 2的次方数 1 2 4 8 16 32
指针-> 结构体.
typedef struct Stu { //成员变量 char name [20]; short age; char tele[12]; char sex[5]; }Stu; void Printf1(Stu temp) { printf("name: %s\n",temp.name); printf("age: %d\n",temp.age); printf("tele: %s\n",temp.tele); printf("sex: %s\n",temp.sex); } void Printf(Stu *ps)//结构体指针取值用-> { printf("name: %s\n",ps->name); printf("age: %d\n",ps->age); printf("tele: %s\n",ps->tele); printf("sex: %s\n",ps->sex); } int main() { Stu s = {"李四",40,"32342344","男"}; Printf1(s); Printf2(&s); return 0; }
1》概念: 带有预定宽度的变量称为位域
2》姿势: struct 标签{ 位域类型 位域变量名:位域宽度; 位域类型 位域变量名:位域宽度; };
例子: struct xx{ int a:2; //占2位 00 01 10 11 unsigned b:4; //占4个位 };
3》位域类型: 位域类型为整型 例: char short int unsigned int(简写为unsigned)
4》位域宽度:
不能超过该类型的的大小 例子: int a:33 //错误 赋值时不能超过该类型的承受范围 例子: unsigned char a:2 // 那么a只能存 0 1 2 3 这几个数字 a = 5 ; //错误
4》位域对齐: 位域类似结构体,按照最大类型对齐
5》空域: 位域宽度为0的位域称为空域,其作用是:该次对齐空间剩余部分全部补0 例子: struct xx{ int b:1 ; int :0 ; // 32位对齐,b用了1位,所以该处共有31个0 int c:3 ; // 新的对齐行 } 6》无名位域: 位域没有名字,仅仅占用空间,无名位域不能调用,其作用是隔开两个位域 例子: struct xx{ unsigned a:2 unsigned: 3 //无名位域,将a和c隔开3个位,该3个位不能使用 unsigned c:2 } 7》位域大小计算(存储规则): 1>如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止 2>如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍 3>如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++,GCC采取压缩方式 4>如果位域字段之间穿插着非位域字段,则不进行压缩
联合体:
1》概念: 不同类型变量公用一块空间
2》姿势: union{ 变量类型 变量名; 变量类型 变量名; 变量类型 变量名; }; 2.1》联合体取别名: typedef union xx ux;
union 标签{ 变量类型 变量名; 变量类型 变量名; 变量类型 变量名; };
不同类型变量共用一块空间
union { double s; int a; short s; }
枚举(实质是宏定义):
1》定义: enum 标签{成员,成员,成员}; 例子: enum WeekDay{MONDYA,TUEDAY,WENDAY,TURDAY,FRIDAY,SATDAY,SUNDAY}; enum WeekDay day; 枚举默认从0开始 enum WeekDay{MONDYA,TUEDAY=3,WENDAY,TURDAY,FRIDAY=6,SATDAY,SUNDAY}; WENDAY为4 2》赋值: day = MONDAY; scanf("%u",&day); 3》使用: enum BIT{SHINENG=1,XUANZE=3}; ---- 可以用于对配置寄存器配置操 #includeemun js{OYNN=1,CXK,MBG,YYQX,PLX,CYW,ZLS}; int main (void) { printf("请选择你的技师:\n"); printf("1.OYNN,2.CXK,3.MBG,4.YYQX,5.PLX,6.CYW,7.ZLS\n"); enum js ej; scanf("%u",&ej); swich(ej) { case OYNN: printf("OYNN为您服务\n"); break; case CXK: printf("CXK为您服务\n"); break; case MBG: printf("MBG为您服务\n"); break; case YYQX: printf("YYQX为您服务\n"); break; case PLX: printf("PLX为您服务\n"); break; case CYW: printf("CYW为您服务\n"); break; case ZLS: printf("ZLS为您服务\n"); break; } return 0; }
条件编译
if else if else
#if #elif #else #endif
基本姿势
#if 0
printf("ff");
#endif
递归:
自己调自己
fun(){ fun(); } ------>设置退出的条件 例子 #include float my_power(float f,int n); int main(void) { float f; int n; scanf("%f %d",&f,&n); printf("%f\n",my_power(f,n)); return 0; } /* float my_power(float f,int n) { if(n<0){ f = 1/f; n = -n; } int i; float sum = 1.0; for(i=0;i 24:数据的存储
大端存储,数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端存储,数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中;
逗号表达式
表达式结果为最后表达式结果
25:指针的进阶
字符指针
指针数组(是数组)
int arr[10] = {0};//整形数组 char ch[5] = {0};//字符数组 int *parr[10] ;//存放整形指针的数组 - 指针数组 char *pch[7] ;//存放字符指针的数组 - 指针数组指针数组用法
int arr1[] = {1,2,3,4,5,6,7}; int arr2[] = {2,3,4,5,6,7,8}; int arr3[] = {3,4,5,6,7,8,9}; int *parr[] = {arr1,arr2,arr3}; for(int i = 0;i<5;j++) { int j = 0; for(j = 0;j<5;j++) { printf("%d",*(parr[i] +j)) } }数组指针
指向数组的指针 -存放数组的地址(对一维数组不友好)
int arr[10] = {1,2,3,4,5,6,7,}; int (*p)[10] = &arr;//数组指针 char *arr[5]; char*(*pa)[5] = &arr;二维数组的首地址得到的思路过程
首先要把二维数组看出一维数组(每行看成一个元素)
再取他的首地址得到一个一维数组的地址
1:linux基础
linux 是一种操作系统
为什么是linux
嵌入式(代码操作硬件)
2:基本地行模式命令
x 保存并退出
w hello.c 将编辑内容存到hello.c上
vs hello.c 分屏编辑
set nonu 临时取消行号
%s/nihao/hello/g 将文件全文的nihao变成hello
s/nihao/hello/g 将光标所在行nihao变成hello
.,$ s/nihao/hello/g 光标当前行到末尾行
/hello 去文本搜索hello字符 :r 文件 直接加载文件
set key=XXXXXX 设密码
3:配置vim:
sudo vim /etc/vim/vimrc
set mouse=a //鼠标控制光标 set cindent //C语言的格式 set number //行号 set st=4 set sw=4 set sts=4 //tab键的长度 vim的固件 一键生成main函数 map mn i#includeo oint main(void) o{ oreturn 0; o} 2ko 4:软件包管理
软件包存放的路径:cd /var/cache/apt/archives
apt-get -h: update---更新 install--安装 remove---卸载5: ubuntu软件源的更换
URL链接---软件商店的仓库:Index of /ubuntu
更换源操作: 1:切换到源的目录 cd /etc/apt 2:把默认源备份 sudo cp sources.list sources.list.back 3:网上搜索18.04国内源:中科大源,阿里源,清华源,腾讯源,163源 sudo vim sources.list 4:把list里面的默认源清空,添加复制的国内源 保存并退出 5:执行: sudo apt-get update
6:用户切换
切换成超级用户:sudo su 切换成其他用户:su 用户名7:标准文件的重定向(了解)----应用层:IO编程 ---输入/输出编程
在linux中,系统打开时,就会有三个标准文件打开 标准文件 文件描述符 介绍 标准输入 0 从键盘输入 标准输出 1 从屏幕输出 标准错误输出 2 从屏幕输出(错误信息) 重定向: > //输出重定向,新建模式 ls>1.c(会把ls输出的东西重定向输出到1.c) >> //输出重定向,追加模式 ls>>1.c(会把ls输出的东西以追加的方式重定向输出到1.c) < //输入重定向 wc -w<1.c(把1.c里面的内容输入重定向到wc -w中) 2> //错误输出重定向 gcc 1.c 2> 2.c(将gcc 1.c的错误信息重定向到2.c中)
8:挂载
概念: linux中,根目录以外的文件想要被访问,需要将其"关联"到根目录下的某个目录来实现, 这种关联的操作就叫"挂载",这个被挂载的目录叫"挂载点",解除本次挂载的操作叫卸载。
注意:挂载点的目录需要有一下几个条件: 1,目录需要事先存在,可以用mkdir命令新建目录 2,挂载点目录不可以被其他进程使用 3,挂载点原有的文件将会被隐藏 查看ubuntu硬盘信息:cat /proc/partitions 8 0 20971520 sda 8 1 20969472 sda1 sd*X: *:a b c d ubuntu的第几快硬盘 sda 第一块硬盘 sdb 第二块硬盘 sdc 第三块硬盘
X:1 2 3 4 ubuntu的第几快硬盘的第几分区 sda1 第一块硬盘的第一分区 sda2 第一块硬盘的第二分区 sda3 第一块硬盘的第三分区 sdb1 第二块硬盘的第一分区 1,cd到mnt目录下 cd /mnt 2,创建挂载点 mkdir myusb 3,查看ubuntu硬盘信息:cat /proc/partitions 查看sda1是否在 4,插上U盘,选择连接虚拟机,不要记住选择!!!!!!!!! 再次执行:cat /proc/partitions sdb sdb1 5,确认sdb是插上U盘才出现的,证明是U盘 6,挂载操作,在mnt这个目录下操作 sudo mount /dev/sdb1 /mnt/myusb 7,ls查看一下。信息是否对应
卸载U盘:umount 前提是在mnt目录下 卸载:sudo umount myusb
9:用户管理,进程管理
在字符界面 有三个用户配置清单的文件 /etc/sudoers //用户的权限 /etc/passwd //用户密码 /etc/shadow //用户信息1,修改用户密码-----passwd 用户名
2,新建一个用户-----adduser 用户名
3/给新建的用户添加权限 //不要乱玩,配置这个之前,最好保存一份快照
sudo vim /etc/sudoers
在第21行添加 XXXXXXX ALL=(ALL:ALL) ALL4/修改用户名
tonlyfucku@ubuntu:/home/farsight$ su farsight Password: farsight@ubuntu:~$ sudo vim /etc/sudoers farsight@ubuntu:~$ sudo vim /etc/passwd //在三个文件底行模式都执行:%s/xxx/xxxxx/g farsight@ubuntu:~$ sudo vim /etc/shadow farsight@ubuntu:/home$ sudo mv XXX XXXX5/删除用户----两种方法:第一种是命令删除 ---userdel 用户名 第二种是操作删除
操作删除: farsight@ubuntu:~$ sudo vim /etc/sudoers farsight@ubuntu:~$ sudo vim /etc/passwd //在三个文件分别清空用户信息 farsight@ubuntu:~$ sudo vim /etc/shadow farsight@ubuntu:~$ cd .. farsight@ubuntu:/home$ sudo rm -rf tonly //删除用户目录 第一种是命令删除: sudo userdel tonly 被某个进程占用 XXXX 先执行kill -9 XXXXps -aux ----查看进程(静态)
USER:进程拥有者 PID:进程的ID号 %CPU:CPU占有率 %MEM:物理内存的占有率 VSZ:虚拟内存的占有率 RSS:内存的占用大小 TTY:终端 STAT:当前进程的状态 D:不可中断的静止 R:正在执行中 S:阻塞状态 T:暂停执行 Z:不存在,但暂时无法消除 W:没有足够的内存可分配 <:高优先级的进程 N:低优先级的进程 L:有足够的内存分配并锁在内存中 I:空闲状态
10:进程
farsight@ubuntu:~$ ls -l total 55172 -rw-r--r-- 1 farsight farsight 157 Jul 28 01:34 1.c 文件类型与权限 硬链接数 文件拥有者 文件所属组 文件的大小 文件的最近修改时间 文件名 文件类型与权限 -rw-r--r--一共10位 10=1+3+3+3 1:即10位的开头位,代表文件的类型 第一个3:文件拥有者的权限 第二个3:文件所属组的权限 第三个3:其他用户的权限 文件类型 标识 普通文件 - 块设备文件 b 字符设备文件 c 目录文件 d 符号连接文件 l 命名管道 p ---多进程线程,网络编程 套接字 s ---网络编程的域通信 文件权限 rw- r-- r-- r:读的权限 w:写的权限 x:执行的权限 在linux当中,权限一般用八进制表示 rw- r-- r-- 八进制:0 6 4 4 二进制: 110 100 100 修改权限的命令:chmod 权限 文件名字 chmode 0777 test 0 7 7 7 0 111 111 111 八进制:rwx rwx rwx
11:文件压缩与解压
文件压缩和解压 用户在进行数据备份时,需要把若干文件整合为一个文件便于保存。尽管整合为一个 文件进行管理,但文件的大小依旧没有改变。如果需要网络传输文件,就希望将其压缩 成更小的文件,以节省在网络传输的时间,且更好的保护文件不损坏 归档:是将一组文件或目录保存在一个文件中。 压缩: 也是将一组文件或目录保存一个文件中, 并按照某种存储 格式保存在磁盘上,所占磁盘空间比其中所有文件总和要少。 压缩工具 解压工具 文件拓展名 gzip gunzip .gz bzip2 bunzip2 .bz2 zip unzip .zip tar-----考试会考 压缩和解压的操作 gzip:只能操作一个文件 farsight@ubuntu:~/test$ gzip 1.c 2.c 3.c farsight@ubuntu:~/test$ ls 1.c.gz 3.c.gz guo_1.c guo_3.c guo_a.c guo_c.c 2.c.gz 解压: farsight@ubuntu:~/test$ gunzip 1.c.gz farsight@ubuntu:~/test$ ls 1.c 3.c.gz 5.c guo_123.c guo_2.c guo_abc.c guo_b.c 2.c.gz 4.c 6.c guo_1.c guo_3.c guo_a.c guo_c.c farsight@ubuntu:~/test$ gunzip 2.c.gz bzip2: farsight@ubuntu:~/test$ bzip2 1.c 2.c 3.c farsight@ubuntu:~/test$ ls 1.c.bz2 3.c.bz2 5.c guo_123.c guo_2.c guo_abc.c guo_b.c 2.c.bz2 4.c 6.c guo_1.c guo_3.c guo_a.c guo_c.c bzip2解压 farsight@ubuntu:~/test$ bunzip2 1.c.bz2 2.c.bz2 3.c.bz2 farsight@ubuntu:~/test$ ls 1.c 3.c 5.c guo_123.c guo_2.c guo_abc.c guo_b.c 2.c zip:可以压缩多个文件,更像我们windows的压缩 farsight@ubuntu:~/test$ zip 123.c.zip 1.c 2.c 3.c adding: 1.c (stored 0%) adding: 2.c (stored 0%) adding: 3.c (stored 0%) farsight@ubuntu:~/test$ ls 123.c.zip 2.c 4.c 6.c guo_1.c guo_3.c guo_a.c guo_c.c 1.c 3.c zip解压: farsight@ubuntu:~/test$ ls 123.c.zip 5.c guo_123.c guo_2.c guo_abc.c guo_b.c 4.c 6.c guo_1.c guo_3.c guo_a.c guo_c.c farsight@ubuntu:~/test$ unzip 123.c.zip Archive: 123.c.zip extracting: 1.c extracting: 2.c extracting: 3.c farsight@ubuntu:~/test$ ls 123.c.zip 2.c 4.c 6.c guo_1.c guo_3.c guo_a.c guo_c.c 1.c 3.c gzip/bzip2/zip:都没有办法归档 tar---集归档和压缩/解压为一体 主要用于将若干文件或目录合并为一个文件,以便 备份和压缩 详解: tar -cvjf 123.bz2 1.c 2.c 3.c 命令 选项 压缩后的压缩包名字 需要压缩的文件 -v :显示压缩和解压的过程 -cf:压缩文件 -j :以bzip2的压缩格式进行压缩(.bz2) -z :以gzip的压缩格式进行压缩(.gz) -xf:解压文件 tar -cvjf :以bzip2的压缩格式进行压缩 tar -cvzf :以gzip的压缩格式进行压缩 tar -xvf :解压命令(解压任何格式的压缩包)12:硬链接
什么是链接文件?(windows) 概念: 链接文件就类似我们windows的快捷方式,只保留本体文件的地址,而不占用存储空间 使用链接文件与使用本体文件的效果是一样的。 为什么要使用链接文件? 1/比如说:在windows都会把文件放到一个较大的盘里,我们每次需要用的时候,就要到盘里 去文件夹里找,这样的操作比较麻烦 现在使用linux的字符界面,是不是更麻烦? 2/ 你做某个东西的时候,需要在意文件的安全和技术要点。 比如做了一个app拿去销售,你同时要保护app的专利,就可以给app创建一个链接文件, 给这个链接文件加上权限,只执行,不可以读不可以写,就不怕用户乱更改你的app了。 linux中有两种类型的链接: 硬链接:利用linux中为每一个文件分配的inode码建立连接的 什么是inode码? 在Linux中,每创建一个文件,系统就会给这个文件 赋予一个inode码来记录这个文件的信息。 对于系统来说,inode码才是这个文件的真实名字 查看文件的inode码:ls -i 软链接:(符号链接)利用带路径的文件名来进行建立链接。 通常建立软链接使用的是绝对路径而不是相对路径,以最大限度提高可移植性 绝对路径:以/根目录为开头的详细路径 相对路径:不以/根目录为开头的相对路径 两种路径是相对的, 如果不是绝对路径就是相对路径 如果不是相对路径就是绝对路径 创建链接文件的命令:ln 1/硬链接:ln -v -v是显示链接过程 farsight@ubuntu:~/test$ ln 1.c 1lin.c 786531 1.c 796555 4.c 786544 guo_1.c 786548 guo_b.c 786531 1lin.c 2/软连接:ln -s soft(软) farsight@ubuntu:~/test$ ln -s 3.c 3lin.c //相对路径 farsight@ubuntu:~/test$ ln -s /home/farsight/test/4.c 4lin.c //绝对路径 总结: 硬链接: 本体文件被删除后,链接文件依旧有效,但是链接断开 重新创建同名本体文件,链接文件有效,但是链接失效 移动本体文件,链接文件依旧有效 软链接: 相对路径:本体文件被删除,链接文件失效 重新创建同名本体文件后,链接文件有效,链接有效 本体文件被移动后,链接文件失效 重新移回本体文件,链接文件有效,链接有效 绝对路径: 本体文件被移动,链接文件失效 链接文件被移动,链接文件依旧有效,且链接有效二:数据结构
1:时间复杂度(硬件的提升空间复杂度不用理会)
代码运行的效率,快慢
时间复杂度是一个函数
例子 F(N) = N*N + 2*N+1 估算O(N^2) F(N) = 2N+10 O(N) 循环100次 O(1)数据结构按照逻辑结构分类
* 线性结构: 只有一个前驱节点和一个后继点(一个元素就是一个节点) 包含: 线性表 栈 队列 * 非线性结构: 不止有一个前驱节点或者后继节点 包含: 树 图----不讲数据结构按照存储结构分类:
* 顺序结构: 数据紧挨保存在一块空间---数据不能间断 * 链式结构: 数据随机存放(到处存放),通过指针的方式链接起来2:线性表:
1》概念: 只有一个前驱节点和一个后继节点 2》分类: *按照顺序存储的方式:(数组) 顺序表 *按照链式存储的方式: 单向链表 双向链表 内核链表
顺序表的优缺点: 优点: 查找数据方便(通过下标) 缺点: *插入 和 删除数据,后面往后或者往前移动 -----> 麻烦 *假如数据量大,那么连续占用的空间大,不方便 例子: malloc(1000000);
3:链表:
单向链表
单向循环链表
双向链表
双向循环链表
内核链表
单向链表(增删改查)
三:文件IO
1:标准(带缓冲)IO编程
格式化标准IO编程
非格式化标准IO编程
2:文件操作步骤: 第一步: 打开文件 第二步: 读写文件 第三步: 关闭文件
定义: 文件:一组相关数据的有序集合。 文件名:这个数据集合的名称。
3:linux中文件分类: (-)常规文件 ASCII码文件 二进制的文件 (d)目录 (c)字符设备 (b)块设备 (p)有名管道 (s)套接口 (l)符号连接
4,标准IO概念
不仅在UNIX系统,在很多操作系统上都实现了标准I/O库 标准I/O库由ANSI C标准说明 标准I/O库处理很多细节,如缓冲分配、以优化长度执行I/O等,这样使用户不必关心如何选择合适的块长度 标准I/O在系统调用函数基础上构造的,它便于用户使用 标准I/O库及其头文件stdio.h为底层I/O系统调用提供了一个通用的接口。5,文件指针 FILE指针:每个被使用的文件都在内存中开辟一个区域,用来存放文件的有关信息,这些信息是保存在一个结构体类型的变量中, 该结构体类型是由系统定义的,取名为FILE。
struct _IO_FILE; typedef struct _IO_FILE FILE; struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; _IO_off_t _old_offset; /* This used to be _offset but it's too small. */ #define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */ _IO_lock_t *_lock; }标准I/O库的所有操作都是围绕流(stream)来进行的,在标准I/O中,流用FILE *来描述。
标准I/O库是由Dennis Ritchie在1975年左右编写的
6,流(stream) 定义:所有的I/O操作仅是简单的从程序移进或者移出,这种字节流,就称为流。 分类:文本流/二进制流。
7,打开文件,返回文件指针:FILE*
#includeFILE *fopen(const char *pathname, const char *mode); //参数1 ---- 要打开的文件 //参数2 ---- 打开的操作权限: r //只读,文件必须存在 r+ //读写,文件必须存在 w //只写,文件不存在,则创建,文件存在,则把文件清空 w+ //写读,文件不存在,则创建,文件存在,则把文件清空 a //只写, 文件不存在,则创建,文件存在,则在文件末尾追加 a+ //写读, 文件不存在,则创建,文件存在,则在文件末尾追加,如果是读,则从文件头开始读 //返回值 ---成功:文件指针,失败:NULL 8,关闭文件: #include
int fclose(FILE *stream); int main(int argc,char **argv) { FILE *fp; if(argc != 2){ printf("Usage: %s\n",argv[0]); exit(1); //结束程序 } //打开文件 fp = fopen(argv[1],"a"); if(fp == NULL){ perror("fopen"); exit(1); } //关闭文件 fclose(fp); //刷新缓冲区,释放缓冲区 return 0; } 9,标准IO的缓冲
当程序和硬盘上的文件进行数据存取时,由于cpu速度比硬盘速度快很多,为了提高程序的效率, 在程序和文件之间创建一个缓冲区,程序可以先将数据写到缓冲区中,然后再一点一点刷新到文件中,这样能够程序效率。
在标准IO中,缓冲分为三种: 1》全缓冲 ---- //操作常规文件的时候 全缓冲刷新的条件: 缓冲区满时 关闭文件时 强制刷新缓冲区 程序正常结束时 2》行缓冲 ----- //操作标准输入和标准输出的时候 当运行一个程序时,系统会自动默认打开三个设备文件: 文件指针 设备 标准输入 stdin 键盘 标准输出 stdout 屏幕 标准错误输出 stderr 屏幕 行缓冲刷新的条件: 缓冲区满时 关闭文件时 强制刷新缓冲区 ------ //fflush(FILE * ) 程序正常结束时 当缓冲区中遇到换行符('\n')时 例如: int main(int argc,char **argv) { #if 0 while(1){ printf("hello world"); usleep(100000); } #else printf("hello world\n"); //exit(0); //fflush(stdout); //fclose(stdout); while(1); #endif return 0; } 3》不带缓冲 ------ //操作标准错误输出的时候 没有缓冲区刷新的条件,直到往缓冲区写数据,会立即刷新。 很多的人机交互界面要求不可全缓冲。 标准出错决不会是全缓冲的。 例如: int main(int argc,char **argv) { printf("helloworld"); //通过标准输出打印,行缓冲 fprintf(stderr,"hello world"); //通过标准错误输出打印,不带缓冲 while(1); return 0; } 2.格式化标准IO
1,格式化输出函数
int printf(const char *format, ...); //只能向标准输出写数据 int fprintf(FILE *stream, const char *format, ...); //向指定的文件中写数据
例如: int main(int argc,char **argv) { #if 0 printf("helloworld"); //通过标准输出打印,行缓冲 fprintf(stderr,"hello world"); //通过标准错误输出打印,不带缓冲 while(1); /****************************************************/ #else FILE * fp; if(argc != 2){ fprintf(stderr,"Usage: %s\n",argv[0]); exit(1); } if((fp = fopen(argv[1],"w")) == NULL){ perror("fopen"); exit(1); } #if 0 //向文件中写数据 char buf[100]; while(1){ bzero(buf,sizeof(100)); scanf("%s",buf); fprintf(fp,"%s\n",buf); //将buf输出的结果写到文件中 fflush(fp); //确保数据能够立即写到文件中,可以使用fflush()强制刷新 } #endif fprintf(fp,"%s\n","hello world"); fprintf(fp,"%d\n",120); fprintf(fp,"%f\n",545.34534); fclose(fp); #endif return 0; } int sprintf(char *str, const char *format, ...); //输出结果以字符串形式写到内存中 例如: struct student{ int sno; char name[20]; float score; }; int main(int argc,char **argv) { int i; struct student st[3]; char buf[5]; //向文件中写数据 for(i =0; i < 3; i++){ printf("请输入学生信息:"); scanf("%d%s%f",&st[i].sno,st[i].name,&st[i].score); sprintf(buf,"%d %s %.2f",st[i].sno,st[i].name,st[i].score); //数组溢出 printf("%s\n",buf); } return 0; } int snprintf(char *str, size_t size, const char *format, ...); //输出结果以字符串形式写到内存中,同时限制写的字符数,防止溢出 例如: struct student{ int sno; char name[20]; float score; }; int main(int argc,char **argv) { int i; struct student st[3]; char buf[5]; //向文件中写数据 for(i =0; i < 3; i++){ printf("请输入学生信息:"); scanf("%d%s%f",&st[i].sno,st[i].name,&st[i].score); snprintf(buf,5,"%d %s %.2f",st[i].sno,st[i].name,st[i].score); //数组溢出 printf("%s\n",buf); } return 0; } 2,格式化输入函数
int scanf(const char *format, ...); //从标准输入(键盘)获取数据 int fscanf(FILE *stream, const char *format, ...); //从指定文件中获取数据
例如: struct student{ int sno; char name[20]; float score; }; int main(int argc,char **argv) { FILE * fp; int i; struct student st[3]; if(argc != 2){ fprintf(stderr,"Usage: %s\n",argv[0]); exit(1); } if((fp = fopen(argv[1],"r")) == NULL){ perror("fopen"); exit(1); } //从文件中读出数据 for(i =0; i < 3; i++){ printf("请输入学生信息:"); fscanf(fp,"%d%s%f",&st[i].sno,st[i].name,&st[i].score); printf("%d %s %.2f\n",st[i].sno,st[i].name,st[i].score); //将buf输出的结果写到文件中 } return 0; } int sscanf(const char *str, const char *format, ...); //从内存中获取数据 例如: struct student{ int sno; char name[20]; float score; }; int main(int argc,char **argv) { #if 0 struct student st; char buf[] = "1001 jack 87.56"; sscanf(buf,"%d%s%f",&st.sno,st.name,&st.score); printf("%d %s %.2f\n",st.sno,st.name,st.score); //将buf输出的结果写到文件中 #else char buf[100]; int h,m; printf("请输入时间:"); scanf("%s",buf); sscanf(buf,"%d:%d",&h,&m); printf("%s为%d小时%d分钟\n",buf,h,m); int a; strcpy(buf,"123"); sscanf(buf,"%d",&a); printf("a = %d\n",a); #endif return 0; } 3:非格式化标准IO编程 -------//输入与输出没有格式,以字节流读写
1,一次一个字符的IO 输入
int fgetc(FILE *stream); //(函数)从指定的文件中获取一次字符 int getc(FILE *stream); //(宏)从指定的文件中获取一次字符 int getchar(void); //默认从标准输入(键盘)获取一次字符
例如: int main(int argc,char **argv) { int a; char b; scanf("%d",&a); printf("a = %d\n",a); while(getchar() != '\n'); //清空输入缓冲区 scanf("%c",&b); printf("b = %c\n",b); return 0; }2》输出
int fputc(int c, FILE *stream); //(函数)向指定的文件中写一个字符 int putc(int c, FILE *stream); //(宏)向指定的文件中写一个字符 int putchar(int c); //向标准输出写一个字符
例如: int main(int argc,char **argv) { FILE * rfp,*wfp; char ch; if(argc != 3){ fprintf(stderr,"Usage: %s\n",argv[0]); exit(1); } if((rfp = fopen(argv[1],"r")) == NULL){ perror("fopen"); exit(1); } if((wfp = fopen(argv[2],"w")) == NULL){ perror("fopen"); exit(1); } //从一个文件中读数据,写到另一个文件中 while((ch = fgetc(rfp)) != EOF){ //printf("%c",ch); putchar(ch); fputc(ch,wfp); } fclose(rfp); fclose(wfp); return 0; } 2,一次一行IO
//输入函数 char *fgets(char *s, int size, FILE *stream); //从指定文件中读取一行数据 //fgets()会连同一行后面的换行符一起读入 //参数1 ----- 内存地址 //参数2 ----- 内存大小 //参数3 ----- 要读取数据的文件的指针 char *gets(char *s); //默认从标准输入(键盘)获取一行数据
int main(int argc,char **argv) { char buf[100]; #if 0 fgets(buf,sizeof(buf),stdin); printf("%ld\n",strlen(buf)); printf("%s\n",buf); #else FILE * rfp; if(!(rfp = fopen(argv[1],"r"))){ perror("fopen"); exit(1); } while(fgets(buf,sizeof(buf),rfp) != NULL) printf("%s",buf); fclose(rfp); #endif return 0; }//输出函数 int fputs(const char *s, FILE *stream); //向指定的文件中写一行 int puts(const char *s); //默认向标准输出(屏幕)打印,在字符串后面会自动添加换行符
例如: int main(int argc,char **argv) { FILE * rfp,*wfp; char buf[100]; if(argc != 3){ fprintf(stderr,"Usage: %s\n",argv[0]); exit(1); } if((rfp = fopen(argv[1],"r")) == NULL){ perror("fopen"); exit(1); } if((wfp = fopen(argv[2],"w")) == NULL){ perror("fopen"); exit(1); } //从一个文件中读数据,写到另一个文件中 while(fgets(buf,sizeof(buf),rfp)){ printf("%s",buf); fputs(buf,wfp); } fclose(rfp); fclose(wfp); return 0; } 3,直接IO -----//字节流
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); //参数1 ----- 内存地址 //参数2 ----- 对象大小 //参数3 ----- 对象个数 //参数4 ----- 文件指针
例如: struct student{ int sno; char name[20]; float score; }; int main(int argc,char **argv) { FILE * fp; int i; struct student st[3]; if(argc != 2){ fprintf(stderr,"Usage: %s\n",argv[0]); exit(1); } if((fp = fopen(argv[1],"w")) == NULL){ perror("fopen"); exit(1); } //向文件中写数据 for(i =0; i < 3; i++){ printf("请输入学生信息:"); scanf("%d%s%f",&st[i].sno,st[i].name,&st[i].score); } //直接iO,向文件中写三个结构体 fwrite(st,sizeof(struct student),3,fp); return 0; } 例如: struct student{ int sno; char name[20]; float score; }; int main(int argc,char **argv) { FILE * fp; int i; struct student st[3]; if(argc != 2){ fprintf(stderr,"Usage: %s \n",argv[0]); exit(1); } if((fp = fopen(argv[1],"r")) == NULL){ perror("fopen"); exit(1); } //直接iO,向文件中写三个结构体 fread(st,sizeof(struct student),3,fp); //向文件中写数据 printf("学生信息:\n"); for(i =0; i < 3; i++){ printf("%d %s %.2f\n",st[i].sno,st[i].name,st[i].score); } return 0; } 例如: int main(int argc,char **argv) { FILE * rfp,*wfp; char buf[100]; if(argc != 3){ fprintf(stderr,"Usage: %s \n",argv[0]); exit(1); } if((rfp = fopen(argv[1],"r")) == NULL){ perror("fopen"); exit(1); } if((wfp = fopen(argv[2],"w")) == NULL){ perror("fopen"); exit(1); } //从一个文件中读数据,写到另一个文件中 while(!feof(rfp) && !ferror(rfp)){ bzero(buf,sizeof(buf)); fread(buf,sizeof(char),sizeof(buf)-1,rfp); printf("%s",buf); fwrite(buf,sizeof(char),strlen(buf),wfp); } fclose(rfp); fclose(wfp); return 0; } 4,定位文件指针
long ftell(FILE *stream); //参数 ----- 文件指针 //返回值 ----成功:文件指针的位移量,失败:-1
例如: int main(int argc,char **argv) { FILE * fp; char ch; int i; if(argc != 2){ fprintf(stderr,"Usage: %s\n",argv[0]); exit(1); } if((fp = fopen(argv[1],"r")) == NULL){ perror("fopen"); exit(1); } for(i = 0; i < 7; i++){ ch = fgetc(fp); printf("%c",ch); } printf("\n%ld\n",ftell(fp)); return 0; } 2》修改文件指针的位置
int fseek(FILE *stream, long offset, int whence); //参数1 ----- 文件指针 //参数2 ----- 偏移量(相对于whence的) //参数3 ----- 表示参数2偏移的起始位置: SEEK_SET --- 文件开头 SEEK_CUR --- 文件指针当前位置 SEEK_END --- 文件末尾 例如: int main(int argc,char **argv) { FILE * fp; char ch; int i; if(argc != 2){ fprintf(stderr,"Usage: %s\n",argv[0]); exit(1); } if((fp = fopen(argv[1],"r")) == NULL){ perror("fopen"); exit(1); } #if 0 //修改文件指针位置,从第5个字符后开始读取数据 fseek(fp,5,SEEK_SET); for(i = 0; i < 3; i++){ ch = fgetc(fp); printf("%c",ch); } #else //计算大小 int len; fseek(fp,0,SEEK_END); len = ftell(fp); printf("len = %d\n",len); #endif return 0; } 小总结:
1,格式化输出函数
int printf(const char *format, ...); //只能向标准输出写数据 int fprintf(FILE *stream, const char *format, ...); //向指定的文件中写数据 int sprintf(char *str, const char *format, ...); //输出结果以字符串形式写到内存中 int snprintf(char *str, size_t size, const char *format, ...); //输出结果以字符串形式写到内存中,同时限制写的字符数,防止溢出 例如: struct student{ int sno; char name[20]; float score; }; int main(int argc,char **argv) { int i; struct student st[3]; char buf[5]; //向文件中写数据 for(i =0; i < 3; i++){ printf("请输入学生信息:"); scanf("%d%s%f",&st[i].sno,st[i].name,&st[i].score); snprintf(buf,5,"%d %s %.2f",st[i].sno,st[i].name,st[i].score); //数组溢出 printf("%s\n",buf); } return 0; }2,格式化输入函数
int scanf(const char *format, ...); //从标准输入(键盘)获取数据 int fscanf(FILE *stream, const char *format, ...); //从指定文件中获取数据 int sscanf(const char *str, const char *format, ...); //从内存中获取数据 struct student{ int sno; char name[20]; float score; }; int main(int argc,char **argv) { #if 0 struct student st; char buf[] = "1001 jack 87.56"; sscanf(buf,"%d%s%f",&st.sno,st.name,&st.score); printf("%d %s %.2f\n",st.sno,st.name,st.score); //将buf输出的结果写到文件中 #else char buf[100]; int h,m; printf("请输入时间:"); scanf("%s",buf); sscanf(buf,"%d:%d",&h,&m); printf("%s为%d小时%d分钟\n",buf,h,m); int a; strcpy(buf,"123"); sscanf(buf,"%d",&a); printf("a = %d\n",a); #endif return 0; } 二,非格式化标准IO编程 -------//输入与输出没有格式,以字节流读写
1,一次一个字符的IO 1》输入
int fgetc(FILE *stream); //(函数)从指定的文件中获取一次字符 int getc(FILE *stream); //(宏)从指定的文件中获取一次字符 int getchar(void); //默认从标准输入(键盘)获取一次字符 2》输出 int fputc(int c, FILE *stream); //(函数)向指定的文件中写一个字符 int putc(int c, FILE *stream); //(宏)向指定的文件中写一个字符 int putchar(int c); //向标准输出写一个字符2,一次一行IO
//输入函数 char *fgets(char *s, int size, FILE *stream); //从指定文件中读取一行数据 //fgets()会连同一行后面的换行符一起读入 //参数1 ----- 内存地址 //参数2 ----- 内存大小 //参数3 ----- 要读取数据的文件的指针 char *gets(char *s); //默认从标准输入(键盘)获取一行数据 输出 int fputs(const char *s, FILE *stream); //向指定的文件中写一行 int puts(const char *s); //默认向标准输出(屏幕)打印,在字符串后面会自动添加换行符例如:
例子:printf scanf
打开文件
sprint 把
sscanf 把字符串变成整数(时间:)
fgets 会读取换行符
puts 会自动加换行符
直接IO
fwrite
fread
有乱码的原因
定位文件指针
ftell(报位置)
fseek
2:非标准IO