標準c基礎知識筆記七
====》IO
INPUT與OUTPUT
常規下用scanf/printf即可;從輸入/輸出緩沖區讀
#include <stdio.h>
int main()
{
printf("立馬顯示出來");
fflush(stdout);//刷新顯示
printf("hello");
sleep(10);//在windows里面編譯不能通過
printf("world");
return 0;
}
scanf 字符串===》數據
printf 內存里的數據====》字符序列
什么時候會立馬輸出到屏幕上
1、有輸入請求的時候,會立馬輸出到屏幕
2、輸出有換行符的時候,也會馬上輸出到屏幕上
3、程序結束的時候也會馬上輸出到屏幕上
4、輸出緩沖區滿的時候
#include <stdio.h>
//sscanf,sprintf
int main()
{
char buf[100];
sprintf(buf,"hello,i'm %s ,today is %d-%d-%d\n",
"wow",2012,05,16);
//把信息放到buffer數組中
puts(buf);
int age;
char name[20];
double salary;
const char * str="21 sxl 2000" ;
sscanf(str,"%d%s%lf",&age,&name,&salary);
printf("我是%s,今年%d,月薪%g\n",name,age,salary);
return 0;
}
1、從鍵盤輸入5各日期,用一個日期數組保存,寫一個通用排序函數,能夠根據傳入的排序規則對日期進行排序,再寫一個函數用來輸出排序
后的日期。要求寫3個排序規則:一個按年從大到小,一個按月從小到大,一個按整個日期從早到晚。
2、寫一個過濾函數,根據傳入的過濾規則對一組整數進行過濾,輸出所有符合規則的數據并返回符合規則的數據的個數。
3、寫一個函數,用來返回一個文件名字符串,格式為imageXXX.jpg,其中XXX是從000開始的三位整數。每次返回一個文件名,每一次跟上一次
不一樣,到999之后回到000。
內存分配
代碼區
——————————————————————————
靜態全局數據區
——————————————————————————
堆區(自由,一般自己收回)
——————————————————————————
棧區-----一般局部變量;受作用范圍限制
malloc 與 free成對出現
理解指針:
指向數組的指針
指向函數的指針
指向結構變量的指針
指向堆空間的指針
堆空間----用3個函數之一來分配空間malloc/calloc/realloc
棧空間
指針只能保存地址
memset(地址,數值,字節數)
sscanf--->sscanf(字符串
---->fscanf(文件,===》文件用FILE*指針來表示
sprintf--->sprintf(字符數組
--->fprintf(文件,
-------------------------------------------
操作系統級別一般用一個int fd來表示文件;
C語言用file*指針來表示文件
c++用對象來表示文件
———————————————————————————————————————————
在C語言中file*指針有3個可用:stdout標準輸出文件,stderr標準錯誤文件,stdin標準輸入文件
其中stderr是沒有緩沖的;而stdout與stdin是有緩沖的
而標準輸入和輸出是可以重定向的
fflush(stdout);//刷新標準輸出文件
#include <stdio.h>
int main()
{
int n;
double d;
char str[100];
fsprintf(stdout,"請輸入姓名、年齡和體重:");
fscanf(stdin,"%s%d%lf",str,&n,&d);
fprintf(stdout,"%s:%d歲,%g公斤\n",str,n,d);
return 0;
}
打開文件用fopen,關閉用fclose
FILE *fopen(const char *path,const char *mode);
FILE *Fdopen(int fildes,const char *mode);
FILE *freopen(const char *path,const char *mode,FILE*stream);
FILE*代表一個文件
打開方式
r從文件開始讀取
r+讀和寫,從文件開始
w清0從頭開始寫
w+如果不存在創建新的,否則將清空,定位在文件開始
a追加
a+
有時間一定去man一下看看
man stdio.h
stdlib.h
string.h
time.h
math.h
如何實現FILE*呢?
FOPEN
類型 * 地址
vi fio.c
#include <stdio.h>
int main()
{
FILE* fi=fopen("in","r");//會返回一個FILE*,代表的是一個文件
//檢查打開文件是否成功?
if(fi==NULL)
{
printf("打開文件in失敗\n");
return 1;
}
char name[20];
int age;
double weight;
fscanf(fi,"%s",name);
fscanf(fi,"%d%lf",&age,&weight);
fclose(fi);
printf("姓名:%s,年齡:%d,體重:%g\n",name,age,weight);
FILE* fo=fopen("out","w");
if(fo=NULL){
printf("打開文件out失敗\n");
return 2;
}
fprintf(fo,"向文件寫內容\n");
fprintf(fo,"姓名:%s,年齡:%d,體重:%g\n",name,age,weight);
fclose(fo);
return 0;
}
//一定要記得關閉,因為寫的文件可能在緩沖區中并沒有寫到文件里面,否則有可能丟失
格式串,在輸出的時候還有些格式控制:
1、整數:%與%之間可以指定寬度,用什么來填充;
2、%%之間:如果是小數還可以指定寬度.小數位數f
3、可以指定靠左還是靠右,-表示靠左;默認靠右
4、%寬度.字符數s
以上規則:對于鍵盤,屏幕以及文件都適用
#include <stdio.h>
int main()
{
char * s="helloworld"
printf("%d,%10d,%-10d,%010d,%+d\n",123,123,123,123,123);
printf("%f,%10f,%-10f,%6.2f\n",1.2,1.2,1.2,1.2);//%f固定6位小數
printf("%s,%10s,%-10s,%6.3s\n",s,s,s,s);
int w=10;
for(w=10;w<15;w++)
{
printf("%c,%*c\n",'a',w,'a');
}
//在這里寬帶使用*,可變寬度
printf("input an integer:");
int x,y;
scanf("%3d%5d",&x,&y);
printf("x=%d,y=%d\n",x,y);
//輸入1234567890,輸出為x=123 y=45678
//輸入12 3,輸出x=12 y=3
//輸入12345 輸出x=123 y=45
scanf("%*d%d",&x);//在scanf中這個*表示拋棄;而在上面printf中表示參數
printf("x=%d\n",x);
char str[100],st[100];
scanf("%[a-z]%[^a-z]",str,st);//讀取在方括號內的字符,比如讀取小寫字符
//[^]表示不是這個范圍的
printf("str=%s,st=%s\n",str,st);
return 0;
}
//其他的輸出格式:
可以通過man printf來看
從文件讀和從鍵盤讀
scanf/printf fopen==>FILE* fclose
puts/gets fgets/fputs
gets會拋棄換行符
puts在寫時會加上換行符
自動換行
fgets從文件讀取一行,不會拋棄換行符,把它作為字符串的一部分
fputs向文件寫的時候不會加換行符
一般情況下puts/fgets;fputs/gets交叉使用。
#include <stdio.h>
int main()
{
char buf[1000];
printf("請輸入一行文字:\n");
//gets(buf);
//scanf("%[^\n]%*c",buf);
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]='\0';//去掉末尾換行符
puts(buf);
printf("%s",buf);
fputs(buf,stdout);//fputs本身并不換行
return 0;
}
//配置文件,用戶信息文件/etc/passwd 一般都是一行一行的。
讀寫一個字符
getchar/putchar
等價scanf("%c" / printf("%c")
fgetc/fputs
getc/putc
fgetc一定是一個函數;getc有可能是個函數也可能是個宏
返回值為int而非char
不管什么字符都讀取
#include <stdio.h>
int main()
{
int i;
int d;
for(i=0;i<3;i++)
{
// printf("請輸入一個整數:");
// scanf("%d",&d);
// scanf("%*[^\n]");scanf("%*c");
// printf("您輸入的是%d\n",d);
// getchar();
d=getchar();
if(d==EOF){
printf("讀取終止\n");
break;
}
printf("%c(%d)\n",d,d);
}
return 0;
}
#include <stdio.h>
//int fgetc(FILE*)/int fputc(int,FILE*)
int main(int argc,char* argv[])
{
//a.out filename copyfile
if (argc!=3){
printf("%s filename copyfile\n",*argv);
return 0;
}
FILE * fi=fopen(argv[1],"r");
if(fi==NULL){
printf("無法打開文件%s"\n,argv[1]);
return 1;
}
FILE* fo=fopen(argv[2],"w");
if(fo==NULL){
printf("無法打開文件%s\n",argv[2]);
return 2;
}
char c;
while((c=fgetc(fi))!=EOF){//EOF在編譯前會替換成-1
putchar(c);
fputc(c,fo);
}
fclose(fi);
fclose(fo);
return 0;
}
vi position.c
#include <stdio.h>
int main()
{
FILE* fp=fopen("file","r+");
if(fp==NULL)
{
printf("無法打開文件file\n");
return 1;
}
int c;
while((c=fgetc(fp))!=EOF){
fputc(c,fp);
}
fclose(fp);
return 0;
}
vi file
abcdefghijklmnopqrstuvwxyz
如何定位文件當前的讀寫呢?fseek函數,設置當前讀寫位置
feek(哪個文件,位置參數,從哪里算起的偏移量)
可以從當前位置或者某個特定的位置開始的偏移量seek_set,seek_cur,seek_end
ftell取當前位置
rewind把當前位置設置為文件的最開頭
什么時候使用呢?比如1、音頻或視頻的播放器;2、數據庫
我們讀取file文件,把第10個和第20個字符交換位置
1、打開文件
2、讀取出第10個字符
3、讀取出第20個字符
4、
#include <stdio.h>
int main()
{
FILE* fp=fopen("file","r+");
if(fp==NULL){
printf("無法打開文件file\n");
return 1;
}
fseek(fp,9,SEEK_SET);
char c10,c20;
c10=getc(fp);
fseek(fp,9,SEEK_CUR);//getc讀取完畢后,其位置加1,所以是9
c20=getc(fp);
fseek(fp,-11,SEEK_CUR);//用負數,是代表向前
putc(c20,fp);
fseek(fp,-8,SEEK_END);//為什么是-8,需要考慮換行符
putc(c10,fp);
fclose(fp);
return 0;
}
在內存和文件進行大量的讀寫時,則用fread/fwrite;從文件到內存叫讀;將內存的東西放到文件里面叫寫。
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);
對于內存中的數據,主要關注地址而非類型
vi fwrite.c
#include <stdio.h>
//fread(內存地址,每條記錄的字節數,記錄的個數,哪個文件)
//fwrite
typedef struct person{
char name[20];
char gender;
int age;
double salary;
}person;
int main()
{
person a[5]={{"abc",'F',18,3500},{"def",'M',20,4500},{"ghi",'F',20,3000},{"jkl",'F',23,2000},{"mno",'M',22,8000}};
FILE* fp=fopen("person.dat","wb",);//b在這里的意思是不做任何轉換
if(fp==NULL){
printf("打開person.dat文件失敗\n");
return 1;
}
int b[10]={11,22,33,44,55,66,77,88,1010};
short s=12345;
fwrite(a,sizeof(person),5,fp);
fwrite(b,sizeof(int),10,fp);
fwrite(&s,sizeof(short),1,fp);
fclose(fp);
return 0;
}
以上是將相關信息寫到了person.dat文件中去了。
我們通過fread將信息從person.dat中讀到內存中去
vi fread.c
#include <stdio.h>
typedef struct person{
char name[20];
char gender;
int age;
double salary;
}person;
int main()
{
person a[5]={};
int b[10]={};
short s=0;
FILE* fp=fopen("person.dat","rb");
if (fp==NULL){
printf("打開person.dat文件失敗\n");
return 1;
}
fread(a,sizeof(person),5,fp);
fread(b,sizeof(int),10,fp);
fread(&s,sizeof(short),1,fp);
fclose(fp);
int i;
for (i=0;i<5;i++){
printf("%s:%s,%d,^g\n",a[i].name,a[i].gender='M'?"man":"women",a[i].age,a[i].salary);
}
for (i=0;i<10;i++){
printf("%d ",b[i]);
}
printf("\n");
printf("%hd\n",s);
return 0;
}
//ungetc向文件里面退出一個字符;下一次就讀這個字符
舉例:讀取172.18.9.6或者ftp.xxx.xxx.xxx
vi ungetc.c
#include <stdio.h>
int main()
{
printf("請輸入一些內容\n");
char str[1000];
double data;
register int c;
for(;;){
c=getchar();
if(c==EOF) break;
if(isspace(c)) continue;//isblank是不是空白
ungetc(c,stdin);
if(c>='0'&&c<='9'){
scanf("%lf",&data);
printf("data=%lf\n",data);
}
else{
scanf("%s",str);
printf("str=%s\n",str);
}
}
return 0;
}
//fgetc(),fgets(),fread(),fwrite()
//feof(FILE*)//是否超越了文件末尾