C语言总结day06

day06

1、定义和使用结构体变量

  • C语言允许用户建立由不同类型数据组成的组合型的数据结构,它称为结构体。
  • 声明格式:struct 结构体名{成员列表}; 定义结构体类型变量:struct 结构体名 结构体变量;
  • 在声明类型的同时定义变量:struct 结构体名{成员列表}变量名表列;
  • 不指定类型名而直接定义结构体类型变量:struct {成员列表}变量名表列;

2、结构体指针(指向结构体变量的指针)

3、共用体:使几个不同的变量共享同一段内存的结构,故同时只能存一种类型的数据,最后进行存储的数据会覆盖前面的数据。

  • union 共用体名{成员列表}变量表列;
  • 与结构体区别:结构体变量所占内存长度是各成员所占的内存长度之和。而共用体变量所占的内存长度等于最长的成员的长度。

4、枚举类型:一个变量只有几种可能的值,则可以定义为枚举类型。

  • 例如:声明:enum Weekennd{sun,mon,tue,wed,thu,fri,sat};定义:enum Weekend weekend;其中weekend是变量,但是只能给其赋{}里面的值。
  • 注意C编译系统对枚举类型的枚举元素按常量处理,故称枚举常量。故不能对它们赋值,如sun=0;是错误的。
  • 每一个枚举元素都代表一个整数,C编译按定义时的顺序默认它们的值为0,1,2,3,4,5…若有赋值语句weekend=mon;相当于weekend=1;

5、文件

  • 操作系统把各种设备都统一作为文件来处理。从操作系统的角度看,每一个与主机相连的输入输出设备都看作一个文件。例如,终端键盘是输入文件,显示屏和打印机是输出文件。

  • 文件的分类:分为ASCII文件(又称为文本文件:在存储前将二进制转换成ASCII代码格式)和二进制文件(数据在内存中是以二进制形式存储的,如果不加转换地输出到外存,就是二进制文件)。

  • 文件缓存区:ANSI C标准采用"缓冲文件系统"处理数据文件,所谓缓冲文件系统 是指系统自动地在内存区为程序中每一个正在使用的文件开辟一个文件缓冲区。从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘去。如果从磁盘向计算机读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(给程序变量)。

  • 文件类型指针:FILE *f1;其中FILE是定义在stdio.h头文件中的一个结构体类型。

  • 打开与关闭文件

    • 所谓"打开"是指为文件建立相应的信息区(用来存放有关文件的信息)和文件缓冲区(用来暂时存放输入输出的数据);"关闭"是指撤销文件信息区和文件缓冲区。
    • ANSI C规定了用标准输入输出函数fopen来实现打开文件。fopen函数的调用方式为fopen(文件名,使用文件方式);FILE *f1 = fopen(“a1”,“r”);该函数的返回值是指向a1文件的指针(即a1文件信息区的起始地址);
      • 使用文件方式

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ED1eU6YB-1611750543456)(…/f1.png)]

    • 标准使用格式:
      if((fp=fopen(“file”,“r”))==NULL){printf(“cannot open this file\n”);exit(0);}

    • 关闭文件:fclose(fp);

    • 顺序读写数据文件

      • 向文件读写字符
        • fgetc(fp):从fp指向的文件读入一个字符。
        • fputc(ch,fp):把字符ch写到文件指针变量fp所指向的文件中。
      • 向文件读写字符串
        • fgets(str,n,fp):从fp所指向的文件读入一个长度为(n-1)的字符串,存放到字符数组str中。
        • fputs(str,fp):把str所指向的字符串写到文件指针变量fp所指向的文件中。
      • 用格式化的方式读写文件
        • fprintf(文件指针,格式字符串,输出列表);fprintf(fp,“%d,%6.2f”,i,f);
        • fscanf(文件指针,格式字符串,输入列表);fscanf(fp,“%d,%f”,&i,&f);
      • 用二进制方式向文件读写一组数据
        • C语言允许用fread函数从文件中读一个数据块,用fwrite函数向文件写一个数据块。在读写时是以二进制形式进行的。在向磁盘写数据时,直接将内存中一组数据原封不动、不加转换地复制到磁盘文件上,在读入时也是将磁盘文件中若干字节的内容一批读入内存。
        • fread(buffer,size,count,fp);fread(f,4,10,fp);其中f是一个float型数组名(代表数组首元素地址)。这个函数从fp所指向的文件读入10个4个字节的数据,存储到数组f中。
        • fwrite(buffer,size,count,fp);
        • 其中,buffer:是一个地址;size:要读写的字节数;count:要读写多少个数据项(每各数据项长度为size);fp:FILE类型指针。
    • 随机读写数据文件

      • 文件位置标记:为了对读写进行控制,系统为每个文件设置了一个文件读写位置标记(简称文件位置标记或文件标记),用来指示"接下来要读写的下一个字符的位置"。
      • 可以强制使文件位置标记指向人们指定的位置。
        • rewind函数使文件位置标记指向文件开头.(rewind(fp)😉
        • fseek(文件类型指针,位移量,起始点);例如:fseek(fp,100L,1)将文件位置标记向前移动到离当前位置50个字节处;fseek(fp,-10L,2)将文件位置标记从文件末尾处向后退10个字节
          • 起始点:用0、1或2代替。0代表"文件开始位置",1代表"当前位置",2代表"文件末尾位置"
          • 位移量:指以"起始点"为基点,向前移动的字节数。注意:位移量应是long型数据(在数字末尾加一个字母L,就表示long型)
  • 详解stdin 、 stdout 、 stderr用法
    1、 我们在写C程序时经常遇到printf(),fprintf(),perror(),这些东西到底有什么作用。说到这不得不提及stdin,stdout,stderr。
    2、 在linux中经常会看到stdin,stdout和stderr,这3个可以称为终端(Terminal)的标准输入(standard input),标准输出( standard out)和标准错误输出(standard error)。
    3、 解释:我们在用C写关于文件的操作时,File fp=fopen(),这个fp就是我们向系统申请的,相当于一通往文件的通道(即C语言内部和系统文件的关联)。其实,stdin,stdout,stderr就是这个fp,而在Linux中,当一个用户进程被创建的时候,系统会自动为该进程创建三个数据流,也就是题目中所提到的这三个
    4、数据流(stream):我们知道,一个程序要运行,需要有输入、输出,如果出错,还要能表现出自身的错误。这是就要从某个地方读入数据、将数据输出到某个地方,这就够成了数据流。
    5、其中0就是stdin,表示输入流,指从键盘输入,1代表stdout,2代表stderr,1,2默认是显示器。printf()其实就是向stdout中输出,等同于fprintf(stdout,“
    ”),perror()其实就是向stderr中输出,相当于fprintf(stderr,“*”)。
    7、标准输入(standard input):
    这两个语句的功能一样,都是用来从键盘中读取数据。
    scanf(“%s”, str);
    fscanf(stdin, “%s”, str);
    8、标准输出(standard out):
    这两个语句的功能一样,都是将字符串显示到终端上。
    printf(“%s\n”, “hello”);
    fprintf(stdout, “%s\n”, “hello”);
    9、我们可以标准输入输出和错误不只能反应在终端显示。可以利用重定向的方法将标准输入和输出重定向到文件中:
    例如在linux中使用ls > a.txt的方法一样。
    printf(“stdout Helo World!!\n”); 运行./test > test.txt(默认是将stdout里的内容重定向到文件中),这样就把test程序输出的内容输出到test.txt文件中。还有一种更明晰的写法./test 1 > test.txt 2 > testerr.txt,这里的1就代表stdout。2代表stderr
    6、stdout,和stderr区别:
    stdout(标准输出),输出方式是行缓冲。输出的字符会先存放在缓冲区,等按下回车键时才进行实际的I/O操作。
    stderr(标准错误),是不带缓冲的,这使得出错信息可以直接尽快地显示出来。
    即stderr是没有缓冲的,他立即输出,而stdout默认是行缓冲,也就是它遇到‘\n’,才向外输出内容,如果你想stdout也实时输出内容,那就在输出语句后加上fflush(stdout),这样就能达到实时输出的效果。

    1、标准输入、输出主要由缓冲区和操作方法两部分组。缓冲区实际上可以看做内存中的字符串数组,而操作方法主要是指printf、scanf、puts、gets,getcha、putcahr等操作缓冲区的方法。在C++以及Java等面向对象的编程语言中,将缓冲区以及操作缓冲区的方法封装成一类对象,这类对象就称为流。

    缓冲区最大的特点主要体现在数据的一次性,即数据被printf、scanf从缓冲区中取出后就被使用了,或者说消耗了。可以把缓冲区比喻成管道,缓冲区中的数据比喻成水流,printf、scanf等方法比喻成开关,当打开开关,水就会慢慢流逝,而流出去的水就再也收不回来了。

    由于不同系统,不的硬件底层实现输入输出的具体方法可能不一样,C语言要求系统为每个程序提供两个指针,这两个指针分别指向两个结构体,这两个结构体分别表示了键盘和屏幕在内存中的抽象表示(缓冲区的地址值被记录在这个结构体中),并将指向这两个结构体的指针命名为stdin和 stdout.这两个指针就是所谓的标准输入和标准输出。

    还有一点应该始终铭记,标准输入和输出缓冲区中存储的是字符的ASCII码值。比如你想从键盘上输入了123给一个变量,那么在缓冲区中存储是三个字节,分别是字符‘1’的ASCII码值,字符‘2’的ASCII码值,字符‘3’的ASCII码值,然后将这个这三个ASCII值序列转换为一个数值给这个变量。同理,从屏幕输出“123”,计算机并不认为它输出的是一个数值,计算机实际上仅仅是描绘了一个‘1’的ASCII码值对应的图形,‘2’的ASCII的值对应的图形,‘3’的ASCII码值对应的图形
    2、getchar、putchar
    putchar的作用主要是向输出缓冲区中写入一个字符。
    getchar的作用主要是向输入缓冲区中读取一个字符。如果碰到文件结尾,返回-1
    getchar源代码

int getchar(void){
static char buf[BUFSIZ];
static char* bb = buf;
static int n = 0;
if (n == 0) {
n = read(0, buf, BUFSIZ);
bb = buf;
}
return(–n >= 0) ? (unsigned char)*bb++ : EOF;
}
EOF是一个宏,表示-1。getchar的返回值是int,对于文件来说-1表示了文件的结尾。我们可以在键盘上利用Ctrl+Z来实现类似的效果。

从getchar的源代码中可以看出,如果发现字符数组buf已空(n0),则调用read方法从键盘读取数据(该方法会导致阻塞),并让指针指向数组的首地址。如果缓冲区还有字符没有被读取(n > 0),则读取它,同时n-1,指针(bb)向后移动一位。当缓冲区已空(n0),且read函数读取失败时(读取到了文件末尾),返回EOF。

从scanf的源代码中可以看出getchar可以读入任何字符,包括空白符(空白符包括:空格、换行符、制表符等)。
3、 gets、puts
puts函数主要向输出缓冲区写入一个字符串,并再字符串输出结束以后,再额外输出一个换行符 ‘\n’。

gets用于从输入流的缓冲区中读取字符到指定的数组。读取过程中会忽略所有的前导空白符,读入的第一个字符为非空白符,直到遇到换行符才停止读入,结束的换行符(‘\n’)被gets函数读从缓冲区读取走了,存于数组中,然后被替换成’\0’。

gets 源代码(只需要看for循环这部分代码,FLOCKFILE(stdin)表示对输入缓冲区加锁对;FUNLOCKFILE(stdin) 表示对输入缓冲区解锁)。

char* gets(char *buf){
int c;
char *s;
static int warned;
static const char w[] = “warning: this program uses gets(), which is unsafe.\n”;
FLOCKFILE(stdin); ORIENT(stdin, -1);
if (!warned) {
(void)_write(STDERR_FILENO, w, sizeof(w) - 1);
warned = 1;
}
for (s = buf; (c = __sgetc(stdin)) != ‘\n’😉
if (c == EOF)
if (s == buf) {
FUNLOCKFILE(stdin); return (NULL);
} else
break;
else
*s++ = c; *s = 0;
FUNLOCKFILE(stdin); return (buf);
}

从源代码可以看出,如果读入了’\n’则停止,并替换成’\0’
4、 printf的使用
定义函数 int printf(const char * format,…);

函数说明 printf()会根据参数format字符串来转换并格式化数据,然后将结果写出到标准输出设备,直到出现字符串结束(‘\n’)为止。

参数format字符串可包含下列三种字符类型:

(1)一般文本(即普通字符,如逗号、空格),伴随直接输出。

(2)转义字符,如\t、\n等。

(3)格式转换字符,格式转换为一个百分比符号(%)及其后的格式字符所组成。一般而言,每个%符号在其后都必需有一printf的参数与之相呼应(只有当%%转换字符出现时会直接输出%字符)

格式转换字符详解 “%[符号][宽度][.精度]类型”

[宽度]:表示输出的数据所占的列数,例若"%5d",表示输出数据占5列,输出的数据显示在此5列区域的右侧。

[符号]:“-”表示对齐方式

(1)%-8,左对齐,当显示字符不足8个时,右补空格

(2)%08,右对齐,当显示字符不足8个时,左补0

[.精度]对于浮点数表示小数点后的位数

数值小数点后的位数大于显示精度,则只能显示[.精度]个小数位数(四舍五入),如果数值小数点后的位数小于显示精度,则补零。%.5 小数点后显示5位

类型:

(1)%d:用于显示十进制有符号数,char,short,int,long long(若输出long(长整型)数据,在格式符d前加字母l(代表long).即"%ld".若输出long long(双长整型)数据,在格式符d前加两个字母ll(代表long long).即"%lld")

(2)%u:用于显示十进制无符号数,unsinged short,unsigned int,

unsigned long long

(3)%x: 用于显示十六进制整数,所有有符号及无符号整型

(4)%f:用于显示十进制浮点数,float,double
-基本型,用%f;不指定输出数据的长度,由系统根据数据的实际情况决定数据所占的列数。系统处理的方法一般是:实数中的整数部分全部输出,小数部分输出6位。
-指定数据宽度和小数位数,用%m.nf;数值小数点后的位数大于显示精度,则只能显示[.精度]个小数位数(四舍五入),如果数值小数点后的位数小于显示精度,则补零。%.5 小数点后显示5位.例"%7.2"格式指定了输出的数据占7列,其中包括2位小数。如果把小数部分指定为0,则不仅不输出小数,而且小数点也不输出。例如"%7.0f"的话,之后输出整数部分。如果是1.0/3的,输出0;

(5)%c:显示字符(一个整数,若在0~127范围中,也可以用"%c"使之按字符形式输出,在输出前,系统会将该整数作为ASCII码转换为对应的字符)

(6)%s:显示字符串

(7)%e:指定以指数形式输出实数。

printf(“%s”,xxx)与puts(xxx)的区别:puts函数会自动添加换行,而printf(“%s”,……)不会。
5、 scanf的使用
定义函数 int scanf(const char * format,…);

函数说明 scanf()会将输入的数据根据参数format字符串来转换并格式化数据。Scanf()格式转换的一般形式如下:

“%[宽度][数据所占字节数]输入类型”

[宽度]:最多输入的字符个数

[数据类型]:

h表示两字节,短整型数据,short 如"%hd"

l表示八字节,用于long long和 double

什么都没有表示四字节

[数据类型]输入类型

(1)%d:int

(2)%f:float

(3)%lf:double

(4)%hd:short

scanf(“%c”,&x) 等价于 x = getchar(),虽然getchar的返回值是int类型,但不影响使用

(5)%s:字符串

用scanf读取字符串时,忽略前导的空白符,再次遇到空白符会结束输入,并将再次遇到的空白符留在缓冲区内,自动添加字符串数组的结束标志’\n’。
-注意:scanf(“a=%f,b=%f,c=%f”,&a,&b,c&);正确输入为:a=1,b=2,c=3 而如果只输入1 2 3就错了,因为系统会把它和scanf函数中的格式字符串逐个字符对照检查的,只是在%f的位置上代以一个浮点数。(在"a=1"的后面输入一个逗号,与scanf函数中的"格式控制"的逗号对应;scanf(“a=%f b=%f c=%f”,&a,&b,c&);正确输入为:a=1 b=2 c=3;scanf(“a=%f:b=%f:c=%f”,&a,&b,c&);正确输入为:a=1:b=2:c=3)
(6)%c:字符
用"%c"格式声明输入字符时,空格字符和"转义字符"中的字符都作为有效字符输入。例如:scanf(“%c%c%c”,&c1,&c2,&c3);输入时为abc(中间不能有空格)当输入a b c(会把第一个字符’a’送给c1,第二个字符时空格字符’ ',送给c2,第三个字符b送给c3)
注意:在输入数据时,如输入空格、回车Tab键或非法字符(不属于数值的字符),认为该数据结束。例如scanf(“%d%c%f”,&a,&b,&c)若输入1234a123o.26;则会将1234给a,a给b,123给c,后边的无效。
#include <stdio.h>
void main(int argc, char* argv[]){
char a[20]; int ch; scanf_s(“%s”,a,20);
printf(“%s\n”, a);
while ((ch = getchar()) != EOF ){
putchar(ch);
}
}
我们输入i love you(ctrl+z)

scanf_s 读取字符’i’以后结束(i后是空格),通过getchar函数第一个读取的字符就是空格,getchar会一直读取缓冲区中,直到缓冲区为空。
6、 fgets、fputs、fscanf、fprintf、fgetchar、fputchar
上述方法只是多了个参数FILE * stream,表示这时的输入以stream指定的文件作为输入或者输出

char* fgets(char* _Buf, int _MaxCount, FILE* _File);

int fputs(const char * _Str,FILE* _File);

int fprintf(FILE* _File, const char * _Format, ...);

int fscanf(FILE* _File, const char * _Format, ...);

int fgetc (FILE* _File) ;

int fputc(int _Ch, FILE* _File);	

7、 其它相关函数

int sprintf( char *_Dest, const char * format,...);

函数说明sprintf和printf函数很类似,printf是将结果写入到标准输出流中,而sprintf是将结果写入到字符串数组_Dest中。返回值返回值返回参数str字符串长度,失败则返回-1。

#include<stdio.h>
void main(){ 
char* a = "This is string A!"; 
char buf[80]; 
sprintf_s(buf,"begin %s end\n", a); 
printf("%s",buf); 
}
int sscanf_s(const char * _Src, const char * _Format, ...);

sscanf函数与scanf类似,只不过scanf是从输入流中读取数据,而sscanf是从字符串数组_Src中读取数据
#include<stdio.h>
void main(int argc, char* args[]){
int i; double n;
char str[20] = “123 3.1415”;
sscanf_s(str, “%d%lf”, &i, &n);
printf(“%d\n%f\n”, i, n);
}
8、设置流缓冲

int fflush(FILE* stream);

void setbuf(FILE* stream, char* buf);

int setvbuf(FILE* stream, char* buf, int mode);

数据总是先写入(或者读取)到流中,当缓冲区满了后,在将其写入到设备(或者获取读取到程序中),这样的工作方式效率更高。但是有时候我们可能需要更快的相应速度,我们可以调用fflush方法来冲刷缓冲区,注意这里冲刷的意思不是将缓冲区的内容删除,而是将还未满的缓冲区中的内容写入到设备(或者读取到程序中)。

setbuf中可以由参数buf自己设定缓冲区的位置和大小(大小由buf数组的大小决定)。

setvbuf中的第三个参数决mode定了缓冲区的缓冲类型。它由三种取值

_IOFBU:全满缓冲类型

_IOLBU:行满缓冲类型

_IONBU:无缓冲类型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值