只是为了记录自己的学习过程。如若有网友发现有错误,请帮我指正,十分感谢。全篇并没有将所有的C知识都一一罗列出来,例如不包括一些数据类型等很基础的东西,只是将很重要的知识给整理了。本文章仅适合用来复习C 知识,还是需要一定的基础的。所有代码均在Linux平台上实现,使用的kate编译器。
#include //预处理 插入头文件
int main() //若没有int,C 默认加上int
{
printf("Hello World\n");
return 0;/*返回0表示正常,非0则不正常*/
}
kate(Linux中)输入:
gcc -c hello.c: 生成 hello.o目标文件,对应于windows上的xxx.obj文件。
gcc hello.o -o hello2:生成hello2可执行文件。若取消“-o hello2”则默认生成a.out可执行文件。
./hello2:执行hello2文件,打印Hello World;
(gcc hello.c: 将直接生成a.out 可执行文件)
现在计算机中使用补码来存储数字,非负数的补码与源码相同,负数的补码需要按位取反后再加1成为补码。
-1 的源码为 10000001 1 的源码为 00000001
反码为 11111110 反码为 00000001
补码为 11111111 补码为 00000001
unsigned int 为非负的int整形
#include
int main()
{
printf("%c,%c,%c,%c,%c\n",0,32,97,65,48); //, ,a,A,0
printf("%c\n",'7'+1); //8
printf("%c\n",'7'+'1'); //h
/*ASCII 每个字符是一个编码a-z(97-122) ,A-Z(65-90) ,0-9(48-57);*/
printf("%hd %hd %hd %hd\n",32767,32768,32769,32770); //32767 -32768 -32767 -32766
printf("Hello Data\n");
printf("%i %f %c \n",123, 45.6, 65); //123 45.600000 A
printf("%i %g %c \n",123, 45.6, 's'); //123 45.6 s
printf("%x %o",763, 763); //2fb 1373
printf("%g\n",45.6); //45.6
return 0;
}
计算机管理内存以字节为单位,1byte = 8bit; 一个汉字扩展ASCII GB2312编码 1 个汉字 2 byte;
float 符号位1,阶码8,小数23
double 符号位1,阶码11,小数52
可通过sizeof(类型)查看字节数, sizeof(5 + 4.4)=8, 只关心数据类型;
溢出:
分为上溢出和下溢出。对于整数而言一处会导致回绕,小数不会回绕,会变成无穷(正无穷和负无穷);
整数考虑溢出,小数考虑误差;
有符号整型的最大值: 2^(位数-1)-1 最小值:-2^(位数-1)
无符号整型的最大值: 2^(位数)-1 最小值: 0
格式化输出:
int、short、long => %i/%d、%hd、%ld unsigned int => %u
float、double => %g(去掉尾部的000…) => %f、%lf(保留尾部000…)
char、char* => %c、%s
十六进制%x 八进制%o 地址%p
宏定义
#define 宏替换,预处理的时候替换。这里仅替换,并无优先结合性;
位运算
与运算 & 同位都为1则该位值为1 00001011 & 00000101 = 00000001;
或运算 | 同位有1则该值为1 00001011 | 00000101 = 00001111;
异或 ^ 同位不同则为 1 00001011 ^ 00000101 = 00001110;
取反 ~ 按位取反 ~00001011 = 11110100;(~11 = -12)
左移 << 所有位向左移动 00001011 << 3 = 01011000;(相当于11*2*2*2)
右移 >> 所有位向右移动 00001011 >> 3 = 00000001;(相当于11%2%2%2)
#include
int main()
{
int n =0;
float f =0;
double d = 0;
char c =0;
char str[10] ={0};
printf("%i %i %i\n",n++,n++,n++); //输出2 1 0 ,不同的编译器产生不同的结果
scanf("%d%f%lf",&n,&f,&d); //此处一定要对应格式输入,如果第一个输入1.1 , 则只读取1,留下0.1会被f读取
printf("%d , %f , %lf\n",n,f,d);
scanf(" %c",&c); //注意输入的格式类型为c的话,一定要再格式符前加空格“ ”;
printf("%c , %d\n",c,c);
scanf("%s",str);
printf("%s\n",str);
printf("Num was inputting success : %d\n",scanf("%f %lf",&f,&d)); //这里能读取两个
printf("Num was inputting success : %d\n",scanf("%f,%lf",&f,&d)); //这里只能读取第一个
scanf("%d\n",&n); //这里输入后,不会马上输出接下来的printf内容,而回等待下一个输入。
printf("aaa %d\n",n);
scanf("%d,%d\n",&n,&n);
printf("bbb %d\n",n);
return 0;
}
1.比较两个小数是否相等,不能使用精确的比较,而是比较近似;
2.printf的计算顺序是从右到左;
3.scanf(“格式符”,地址表); 返回值为成功读取的字符个数
scanf中如果有空白字符,则直到遇到空白字符才读取;
scanf中只要格式占位符;如果scanf有空白字符,则跳过所有空白字符,直到遇到非空白字符。
4.scanf(“%[^\n]%*c”); 表示抛弃,[]表示范围,^表示非,抛弃一个字符
%*c表示读入一个字符且不保存到变量里
%*[^\n]表示读入一个字符串,由范围[]内定,即^\n表示非换行符的都能读取。遇到\n,scanf则会返回
可以使用这个替代
{
char c;
do{
scanf(“%c”,&c);
}while(c!=’\n’);
}
#include
enum TEST{a=2,b=1,c};
int main()
{
int n;
do{
puts("Put in your number:");
scanf("%i",&n); //此处输入字母会进入死循环。由于输入的字符与对应的格式符不对应,无法取走输入缓冲区中的字符;
}while(n<100);
puts("Out of circle1 !!!!");
do{
puts("Put in your number:");
//scanf("%d",&n);
if(scanf("%d",&n)==1){
printf("Input Success ,and number is %d\n",n);
}else{
printf("Fail Input !!\n");
}
scanf("%*[^\n]%*c"); //这个是清空输入缓冲区
}while(n<100);
puts("Out of circle1 !!!!");
enum TEST test = c; //定义枚举变量,enum不能缺少,赋值类型必须对应相同枚举类型
typedef enum TEST T; //通过类型定义符给类型起别名
T test2 = b;
return 0;
}
循环的几种形式:
for(;;){} 、 do{}while(true) 、 while(true){}
#include
int main()
{
int a[5]={11,22,33,44,55}; //数组的初始化,数据不能多,可以少,少的部分全用数组0填充
printf("a = %p\n",a); //a = 0xbfa2e868
int i;
for(i=0;i<5;i++)
{
printf("&a[%d] = %p\n",i,&a[i]); //&a[0] = 0xbfa2e868
}
*a+=100;
printf("%d\n",a[0]); //111 a[0]也可以写成0[a],是一样的
for(i=0;i<5;++i)
{
printf("a + %d = %p\n",i,a+i); //a + 0 = 0xbfa2e868
}
printf("\n========================\n");
int x =123;
int y =456;
for(i = -2;i<8;i++)
{
printf("%d\n",a[i]);
}
printf("\n");
printf("x = %d , y = %d\n",x,y); //x=123,y=456
for(i =-2;i<8;i++)
{
a[i]=0; //有可能改变x或者y的值,vs编译器会严重报错
}
printf("x=%d , y=%d\n",x,y); //x=0,y=0 变量再内存中的关系未必按照定义的顺序
return 0;
}
1. a={}; 给数组赋值会出错;(只能初始化)
2. 数组名代表这个数组的第一个元素的地址;
3. a + i => &a[i]; *(a + i) => a[i]; a[i] => i[a];
4. 数组的另一种访问形式: int array[3]={1,2,3}; => 2[array] == 3;
#include
#include
int main()
{
char a[100]="hello world!!";
printf("%s\n",a); //hello world!!
printf("%d\n",sizeof("hello world!!")); //14 字符串会在末尾自动补上‘\0’
printf("%c\n","hello world!!"[2]); //l 没有名字的字符串
printf("%s\n","hello world!!"+3); //lo world!!
strcpy(a,"hello google!!"); //拷贝字符串(并覆盖)
puts(a); //hello google!!
strcat(a,"hello Baidu!!"); //末尾追加字符串(要确保位置足够)
puts(a); //hello google!!hello Baidu!!
printf("%d\n",strlen(a)); //27 字符数,不包括‘\0’
printf("%s\n",strchr(a,'h')); //hello google!!hello Baidu!! 从左向右寻找
printf("%s\n",strrchr(a,'h')); //hello Baidu!! 从右向左寻找
printf("%s\n",strstr(a,"goo")); //google!!hello Baidu!! 字符串查找
printf("%i\n",strcmp("abc","ab")); //1 a>b
printf("%i\n",strcmp("abc","abc")); //0 a==b
printf("%i\n",strcmp("ab","abc")); //-1 a
1.两个字符串、字符数组不能直接使用 == 来比较,使用比较符比较的都是在比较 ‘地址’;要使用strcmp函数比较;
2.”abcdefg” 这样单独的字符串是常量,是只读的。例如“ “hello”[0] = ‘H’; ”会报错。
#include
#include
typedef char CStr[100]; //类型重定义char[100]的定义方式!!!!
typedef enum {MALE,FEMALE} gender;
typedef struct {
char name[20];
int age;
double income;
gender s;
} person;
typedef struct {
char aa; //1
char a; //1
short b; //2
int c; //4
double d; //8
} test; //16
typedef struct {
char a; //1
double d; //8
char aa; //1
int c; //4
short b; //2
} test2; //24
int main()
{
person a = {"A",18,8005,MALE};
person b = { age:15,name:"B",income:9000,s:FEMALE};
person c =a;
CStr s="1212";
printf("person a : %s, %i, %g, %s\n",a.name,a.age,a.income,a.s == MALE?"man":"female");
printf("person b : %s, %i, %g, %s\n",b.name,b.age,b.income,b.s == MALE?"man":"female");
printf("person c : %s, %i, %g, %s\n",c.name,c.age,c.income,c.s == MALE?"man":"female");
printf("%d\n",sizeof(test)); //16
printf("%d\n",sizeof(test2)); //24
return 0;
}
1.结构体的成员变量内存分配会进行对齐,会按照结构体中最大的基本数据类型来决定倍数,当超过4时,以4为倍数;
2.可以使用pragma pack(X)设定对齐倍数x,pragma pack()则使用默认的对齐倍数(4),64位默认为8倍数;
3.为使结构体能保证效率的同时占用最少空间,一般越小的数据类型放越前面;
#include
void sayHello();
#include
#include"myFunc.h"
static char S[10]="For Test"; //此处定义的静态数据,只能在本文件中使用
char w0[7][10]={ //静态数据和全局数据没有垃圾数据
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
};
void sayHello()
{
printf("Hello World!!!\n");
}
#include
#include"myFunc.h"
extern char w0[7][10]; //告诉编译器w0已在外部文件中定义,而不要报错(或者放在头文件中声明)
char* weekday(int n)
{
return w0[n];
}
/*====可变长参数的函数====*/
int max(int num, ...)
{
va_list arg_ptr; //va_list是个类型,保存可变长度参数表
va_start(arg_ptr,num); //指定从哪个参数后面开始,用arg_ptr保存num之后的参数表
int i =0;
int maxvalue = va_arg(arg_ptr,int); //从参数表中取一个int类型的参数
for(i =0 ; i< num;++i)
{
int data = va_arg(arg_ptr,int); //要取出一个什么类型的数据
if(data>maxvalue)
maxvalue = data;
}
va_end(arg_ptr); //释放可变长度参数表
return maxvalue;
}
/*====递归====*/
int f(int x)
{
if(x<=0)
return 5;
else
return 2*f(x-1)+3;
}
int main()
{
sayHello();
printf("%s\n",weekday(2));
register int i; //寄存器,请求编译器把变量放到寄存器里不放到内存中。有可能成功。不能取地址
for(i =0;i<5;i+=)
{
printf("%d ",i);
}
printf("%d\n",max(5,44,23,13,55,23)); //55
return 0;
}
以上两个文件要同时编译和链接
kate(Linux中)输入:
gcc -c myFunc.c : 生成myFunc.o
gcc -c main.c : 生成main.o
gcc myFunc.o main.o : 生成a.out
( 或者gcc myFunc.c main.c ) 直接生成a.out,但是这种办法需要重新编译所有文件
volatile关键字:
1.类型修饰符。被设计用来修饰不同线程访问和修改的变量。编写多线程必须用到。
2.能够确保本条指令不被编译器优化而省略,且要求每次直接读值。
3.如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,
如果这个变量由别的程序更新了的话,将出现不一致的现象。不定长函数:(stdarg.h)
1.va_list
定义了一个指针arg_ptr,用于指示可选的参数;
2.va_start(arg_ptr, argN)
使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,argN是位于第一个可选参数之前的
固定参数, 或者说最后一个固定参数。如有一个va函数的声明是void va_test(char a, char b, char c, …),
则它的固定参数依次是a,b,c,最后一个固定参数argN为c, 因此就是va_start(arg_ptr, c);
3.va_arg(arg_ptr, type)
返回参数列表中指针arg_ptr所指的参数, 返回类型为type, 并使指针arg_ptr指向参数列表中下一个参数,返回
的是可选参数,不包括固定参数;
4.va_end(arg_ptr)
清空参数列表, 并置参数指针arg_ptr无效;
注意:
1.函数传递中形参数组和实参数组是同一个数组,数组在使用的时候使用的是值传递。
2.形式参数是由实参来初始化的,函数调用的时候分配空间,返回时释放空间。
#ifndef DEFINE_H //防止同一个C文件中重复包含,而报重复定义的错误
#define DEFINE_H
int i=5;
#endif
#include
#include"define.h"
int main()
{
printf("%d\n",i);
return 0;
}
//#include"define.h" //有一个.c文件包含了,这里又包含,会报重复定义的错误
条件编译指令:
#ifndef 、 #ifdef 、 #endif 、 #undef取消宏定义 、 #else 、 #define
其他常用宏定义:
FILE 文件名 ; LINE 行号(int) ; DATE 当前的日期 ; TIME 当前的时间;
注意:
1.条件编译是为了防止同一个.c文件中重复包含一个头文件而设定的,当出现两个.c文件包含同一个头文件时,
将可能报重复定义的错误;
2.宏定义可以带参数 例如:#define SWAP(T,x,y) {T t=x;x=y;y=t;};括号之间不能有空格符号
3.宏定义都是替换,如果带参数,一定要带上括号,避免优先级问题导致结果错误;
4.宏定义数组的格式: #define IARRAY int[100];
#include
char* func()
{
char a ='f';
return &a; //返回局部地址,是错误的
}
void f1(int* a,int* b){int* t=a; a=b; b=t;} //这里只是函数内的指针指向改变,改变的是局部变量,并不影响外面
void f2(int* a,int* b){int t=*a; *a=*b; *b=t;} //通过指针指向外部数据,能够改变外部的值
void f3(int a,int b){int t=a; a=b; b=t;} //改变的只是函数内的局部变量
void showArray(int array[], int num) //传递进去的还是指针,并不是数组。函数内不能用sizeof()求数组的长度;
{
return;
}
int main()
{
int iArray[10] = {1,2,3,4,5,6,7,8,9,0};
int* iPtr1; //野指针,这样定义很危险
printf("%p\n",iPtr1);
int* iPtr2 = NULL; //空指针。0代表空地址
printf("%p\n",iPtr2);
iPtr2 = iPtr1+3;
printf("iPtr1= %p, iPtr2= %p, iPtr2-iPtr1= %d\n",iPtr1,iPtr2,iPtr2-iPtr1);
iPtr1 = iArray; //表示数组第一个元素
printf("iArray[%d]: %d\n",0,iArray[0]); //1
printf("iArray[%d]: %d\n",1,*(iArray+1)); //2
printf("iArray[%d]: %d\n",2,iPtr1[2]); //3
printf("iArray[%d]: %d\n",3,*(iPtr1+3)); //4
printf("iArray[%d]: %d\n",4,(iPtr1+3)[1]); //5
printf("iArray[%d]: %d\n",5,*((iPtr1+4)+1));//6
printf("*iPtr1+1 : %d\n",*iPtr1+1); //2 *优先级高于 +/- 双目运算符
printf("*iPtr1++ : %d\n",*iPtr1++); //1 *优先级低于 前置或后置--/++单目运算符
printf("*--iPtr1 : %d\n",*--iPtr1); //1
int a=10;int b=20;
f1(&a,&b); //
printf("%d, %d\n",a,b); //10,20
f2(&a,&b); //
printf("%d, %d\n",a,b); //20,10
f3(a,b); //
printf("%d, %d\n",a,b); //20,10
/* const type* \ type const* */
int iValue1 = 5;
int iValue2 = 6;
const int icstValue1 =10;
const int icstValue2 = 11;
int* const PtrCst1 = &iValue1;
int* const PtrCst2 = &icstValue1; // !!!! warning : "a const pointer to variable" point to a "constant" ;
//int* cp = &icstValue2; //as same as the last line
const int* CstPtr1 = &icstValue1;
const int* CstPtr2 = &iValue1; //"a pointer to constant" is able to point to a variable;
//PtrCst1 = &iValue2; //error : "const pointer" can't change value(address)
*PtrCst1 = 50;
*PtrCst2 = 100; // !!!! change the constant by pointer
CstPtr1 = &icstValue2;
//*CstPtr1 = 110; //error : "pointer to constant" can't change value(variable value)
//*CstPtr2 = 50; //error : as same as the last line
printf("%d\n",icstValue1); // !!!! constant was changged
return 0;
}
1.我们使用的内存地址是虚拟地址,是通过内存映射到物理内存上去的。
2.常量指针:可以指向常量,和变量;(不能改变指向的常量或变量的值)const type*
3.指针常量:只能初始化时指向变量;(不能改变指向)type* const
4.多级指针保存比自身少一个 * 的地址;
5.解析地址符*优先级高于 +/-双目运算符,低于–/++单目运算符;
#include
int main(int argc, char* argv[]) //argc:argument count argv:argument content
{
printf("argc=%d\n",argc);
int i;
for(i = 0;i
kate(Linux中)输入:
gcc main.c -o hello : 生成hello
./hello world heihei haha : 执行hello文件
输出:
argc=4
0:./hello
1:world
2:heihei
3:haha
#include
#include
int str2int(const char* str, const char** q)
{
int r =0;
while(isdigit(*str)){ //isdigit是判断是否为数字,位于ctype.h中
r=r*10+(*str-'0'); //此处计算出整型数据的值
++str; //此处最终指向原字符串第一个字母开始的位置
}
*q = str; //注意,此处改变了传入的指针的指向
return r;
}
int main()
{
const char* p=NULL;
int num =str2int("3926abxys",&p);
printf("num=%d, p=%s\n",num,p); //num=3926, p=abxys
return 0;
}
#include
void showbyte(void* addr, int bytes)
{
while(bytes-- > 0)
printf("%02x ",*(unsigned char*)addr++);//02 表示不足两位,前面补0输出
printf("\n");
}
int main()
{
int n =1234567890;
float f =1234567890;
double d=1234567890;
short s=1234567890;
printf("%x,%hx\n",n,s);
showbyte(&n,sizeof(n));
showbyte(&f,sizeof(f));
showbyte(&d,sizeof(f));
showbyte(&s,sizeof(s));
return 0;
}
#include
int main()
{
int iArray[5] = {1,2,3,4,5};
int iiArray[3][5] = {{1,2,3,4},{5,6,7},{8}};
int* pArray[5]; //pArray是一个数组,每个元素都是int*类型
int (*iPtr)[5]; //iPtr是一个指针,只想5个int元素组成的数组
/*test_1*/
iPtr = iArray; //表示&iArray[0]
for(int i=0;i<5;++i)
printf("%d ",*(*iPtr+i)); //== (*iPtr)[i] == iArray[i];
printf("\n\n");
/*test_2*/
iPtr = &iArray; //表示数组地址,int(*)[5]类型
for(int i=0;i<5;++i)
printf("%d ",*(*iPtr+i)); //== (*iPtr)[i] == iArray[i];
printf("\n\n");
/*test_3*/
iPtr = iiArray; //iiArray代表iiArray[0]的地址
for(int i =0;i<3;++i,printf("\n"))
for(int j=0;j<5;j++)
printf("%d ",*(*(iPtr+i)+j)); //iPtr[i][j] //iiArray[i][j]
return 0;
}
1.int (*iPtr)[5]; int iArray[5]; *iPtr相当于是iArray首地址。iPtr+1 == *iPtr + 5;
2.iPtr = iArray 和 iPtr = &iArray 效果是一样的。
3.iPtr = iiArray;iPtr+1相当于iPtr移动了5个int的距离,指向下一个一维数组元素,*iPtr+1相当于iPtr
移动了1个int的距离,指向当前一维数组中的下一个int元素;
#include
void sayChinese()
{
printf("ni hao\n");
}
void sayEnglish()
{
printf("hello\n");
}
void sayJapanese()
{
printf("kon ni qi wa\n");
}
void getMoney(int num)
{
printf("Give you %d dallors\n",num);
}
int main(int argc,int* argv[])
{
int* fun(char); //fun是一个函数,形参char,返回值int*
void (*pFun_vc)(int); //pFun_vc是一个指针,指向一个形参为char且无返回的函数
void (*pFun_vv)(); //pFun_vv是一个指针,只想一个形参为任意且无返回的函数
printf("release %d times\n",argc);
if(argc<1) return 0;
pFun_vv = &main; //这里会报assignment from incompatible pointer type的警告
pFun_vv(argc-1,argv); //可以调用,没问题
pFun_vv = &sayChinese; //此处千万别加括号
pFun_vv(); //通过函数指针直接调用函数
pFun_vv = &sayEnglish;
pFun_vv();
pFun_vv = &sayJapanese;
pFun_vv();
pFun_vc = &getMoney;
pFun_vc(100);
return 0;
}
#include
void print(int* p){printf("%d ",*p);}
void add(int* p){*p+=10;}
void clear(int* p){*p = 0;}
void mul(int* p){*p *=10;}
void fill(int* p){static int n=0; *p = ++n;}
void foreach(int a[],int n,void(*fp)(int*))
{
int i;
for(int i=0; i
静态变量在多线程的时候会出现问题,我们使用堆区比较多。
#include
//typedef void (*T)(); //T就是 void(*)()
//typedef int (*U)(char); //U就是 int(*)(char)
//U x(T p); //x就是 int(*(void(*p)()))(char)
//int (*x(void(*p)()))(char); //这是一个函数,形参void(*p)()指向形参任意的函数
int rule1(double lh,double rh){return (lh>rh);}
int rule2(double lh,double rh){return (rh>lh);}
#define swap(x,y){double t=x;x=y;y=t;} //宏定义的好处,就是快
void sort(double a[], int n, int (*p)(double,double))
{
int i,j;
for(i=0;i
#include
#include
int main()
{
int b =sizeof(double);
double* p =(double*)malloc(b);
int cnt;
printf("Please put in elements numbers: ");
scanf("%d",&cnt);
int* a = calloc(cnt,sizeof(int));
if(a==NULL){
printf("Faile to apply for room ;\n");
return 1;
}
printf("p=%p, a=%p\n",p,a);
*p =123.45;
int i;
for(i =0;i
堆申请的内存最终需要通过函数free来释放
1.alloca是向栈申请内存,因此无需释放.
2.malloc分配的内存是位于堆中的,并且没有初始化内存的内容,因此基本上malloc之后,调用函数memset来初始化这部分的内存空间.
3.calloc则将初始化这部分的内存,设置为0.
4.realloc则对malloc申请的内存进行大小的调整.
#include
int main()
{
char name[20] = "DaShaBi";
FILE *ofPtr = fopen("txt/out.txt","w"); //路径不要带着主目录符号
if(ofPtr != NULL)
fprintf(ofPtr,"Hello, you are %s ;",name);
char say[50];
FILE *ifPtr = fopen("txt/in.txt","r"); //第二个参数表示打开方式
if(ifPtr != NULL)
fscanf(ifPtr,"%[^\n]%*c",&say); //这里指跳过一行,读取一整行,而不会遇到空格就结束
printf("%s\n",say);
fclose(ofPtr); //不用文件时,一定要关闭,不然会占用系统资源
fclose(ifPtr);
return 0;
}
文件描述C语言有一套标准,操作系统有一套标准,C++也有一套标准
有关于scanf fscanf sscanf
#include
int main()
{
char buffer[50];
printf("Plase put in a line of words :");
fgets(buffer,sizeof(buffer),stdin);
buffer[strlen(buffer)-1] = '\0'; //除去换行符
puts(buffer); //自动换行
printf("%s\n",buffer);
fputs(buffer,stdout); //不换行
return 0;
}
有关于fputc fputs putc putchar puts
linux中有个命令tee,可以读取标准输入的数据,并将其内容输出成文件。
语法:tee [-ai][–help][–version][文件…]
参数:
1.-a或–append 附加到既有文件的后面,而非覆盖它啊;
2.-i-i或–ignore-interrupts 忽略中断信号;
3.–help 在线帮助;
4.–version 显示版本信息;
#include
int main(int argc, char* argv[])
{
if(argc!=3){
printf("%s filename copyfile\n",*argv);
return 0;
}
FILE* ifPtr = fopen(argv[1],"r");
if(ifPtr==NULL){
printf("Can't open the file %s\n",argv[1]);
return 1;
}
FILE* ofPtr = fopen(argv[2],"w");
if(ofPtr == NULL){
printf("Can't open the file %s\n",argv[2]);
return 2;
}
int c;
while((c=fgetc(ifPtr))!=EOF){ //将输入文件的内容传输到输出文件中
putchar(c);
fputc(c,ofPtr);
}
fclose(ifPtr);
fclose(ofPtr);
return 0;
}
kate(Linux中)输入:
gcc -c practice.c 编译成practice.o文件
gcc practice.o 链接生成a.out可执行文件
./a.out ./txt/in.txt ./txt/out.txt 执行a.out文件;
#include
int main()
{
FILE* fp = fopen("./txt/write.txt","r+");
if(fp==NULL){
printf("Cant open the file\n");
return 1;
}
fseek(fp,1,SEEK_SET); //从开头向右偏移1个单位,指向第2个
char c2, c10;
c2 = getc(fp);
fseek(fp,7,SEEK_CUR); //当前指向第3,从当前位置向右偏移7个单位,指向第10个
c10 = getc(fp);
fseek(fp, -9, SEEK_CUR); //当前指向第11,从当前位置向左偏移9个单位,指向第2个
putc(c10,fp);
fseek(fp,9,SEEK_SET); //从开头偏移9个单位,指向第10个
putc(c2,fp);
fclose(fp); //1234567890原来的文件内容
//1034567892更改后的文件内容
return 0;
}
1.int fseek(FILE* stream, long offset, int whence); 这个函数用来定位设置当前的读写位置
参数:文件指针,偏移量,参考位置(SEEK_SET开头、SEEK_END末尾、SEEK_CUR当前);
2.long ftell(FILE* stream);返回文件当前的位置
3.void rewind(FILE* stream);把文件当前位置设置为开头(这个使用再大文件中,比如电影播放器记录拖动操作)
#include
#include
int main()
{
FILE* stream;
char msg[] = "this is a test";
char buf[20];
if((stream = fopen("DUMMY.FIL","w+")) == NULL){
fprintf(stderr,"Cannot open output file.\n"); //stderr 为标准错误输出设备
return 0;
}
fwrite(msg,strlen(msg)+1,1,stream); //从内存msg写入文件DUMMY.FIL
fseek(stream,0,SEEK_SET); //重新定位在文件开头
fread(buf,strlen(msg)+1,1,stream); //从文件DUMMY.FIL读取到neicunbuf中
printf("%s\n",buf); //输出 “this is a test”
fclose(stream);
return 0;
}
1.成片的数据操作,使用fread/fwrite在内存和文件之间用成片的数据操作。
把文件中的东西放到内存叫读
把内存中的东西放到文件叫写
2.size_t fread(void* buffer, size_t size, size_t count, FILE* stream);
参数:buffer用于接收数据的内存地址,大小至少是size*count;
size单个元素的大小,单位是字节;
count元素的个数,每个元素是size字节;
stream文件流;
返回值:实际读取的元素个数。如果返回值与count不同,可能文件结尾或遇到错误。
从ferror和feof获取错误信息,或检测是否到达结尾;
#include
typedef struct person{
char name[20]; //20b
char gender; //1b
int age; //4b
double salary; //8b
}person; //36 bytes
int main()
{
/* 写入文件 */
person a[5] = {{"Marry",'F',18,3500},{"Tom",'M',20,4500},{"Jack",'M',21,4000},{"Jones",'F',19,3900},{"Lucy",'F',24,6000}};
FILE* fp = fopen("person.dat","wb");
if(fp==NULL){
printf("Failed to open the file");
return 1;
}
int b[10]={11,22,33,44,55,66,77,88,99,1010};
short s =12345;
fwrite(a,sizeof(person),5,fp);
fwrite(b,sizeof(int),10,fp);
fwrite(&s,sizeof(short),1,fp);
fclose(fp);
/* 读取文件 */
person bufA[5]={};
int bufB[10]={};
short bufS=0;
fp = fopen("person.dat","rb");
if(fp==NULL){
printf("Failed to open the file");
return 1;
}
fread(bufA,sizeof(person),5,fp); //注意这里的读取顺序。
fread(bufB,sizeof(int),10,fp);
fread(&bufS,sizeof(short),1,fp);
fclose(fp);
for(int i=0;i<5;i++){
printf("%s: %s, %d, %g\n",
a[i].name,a[i].gender == 'M'?"Boy":"Girl",
a[i].age,a[i].salary);
}
for(int i=0;i<10;i++){
printf("%d ",bufB[i]); //11,22,33,44,55,66,77,88,99,1010
}
printf("\n");
printf("%hd\n",bufS); //12345
return 0;
}