C语言常识注意

1、宏定义define
用于程序开头,比如定义标识符来表示常量,后面要修改常量的值,这个常量的值在整个程序中就会被替换

#define size 10  //后面没有分号" ; ",如果写上分号就会出现错误

比如定义一个数组

int data[size]; //加上分号就会出现如下错误

加上分号的错误

2、关键字typedef
①typedef为数据类型起一个新的别名,就像人的“绰号”

typedef oldName newName;
//如typedef int INTEGER;
//用INTEGER来代替int,INTEGER a;就是int a;

②typedef 还可以给数组、指针、结构体等类型定义别名。
给数组类型定义别名的例子如下:

typedef char Array20[20]; //这里的Array20是char[20]的别名,如果定义Array20 a;等价于char a[20];

给结构体类型定义别名如下:

typedef struct stu{
....;
} STU;
//STU就是struct stu的别名,STU student;等价于struct stu student;

typedef还可以为函数类型定义别名,如

typedef int (*PTR_TO_FUNC)(int,int);
int max(int a,int b){....;}
PTR_TO_FUNC pfunc=max;
//调用max(10,20);   可直接(*pfunc)(10,20);

typedef和#define的区别
typedef 在表现上有时候类似于 #define,但它和宏替换之间存在一个关键性的区别。把 typedef 看成一种彻底的“封装”类型,声明之后不能再往里面增加别的东西。如

#define INTERGE int
unsigned INTERGE n;  //没问题

typedef int INTERGE;
unsigned INTERGE n;  //错误,不能在 INTERGE 前面添加 unsigned

3、C与C++库文件的区别
定义库文件用 #include<>
C语言里stdio.h头文件是主要的,而C只是C++的一个子集,且在C++中已不推荐使用C的类库,但为了对已有代码的保护,还是对原来的头文件支持。
C语言里定义库文件用

#include<xxx.h>
如 #include<stdio.h>

而C++里定义库文件用

#include<cxxx.h>
如#include<cstdio.h>
在C++里还使用 
#include<iostream>
using namespace std; //必须的
//iostream是C++里定义标准输入/输出流对象的头,输入输出可用cin,cout。

想要了解更多的库文件可登录网页http://www.cplusplus.com/
下面是一些常用的库文件
stdio.h执行输入/输出操作(C里定义输入输出函数的头,输出可用printf)
stdlib.h定义了几个通用函数,包括动态内存管理、随机数生成、与环境的通信、整数算术、搜索、排序和转换。
string.h定义了几个函数来操作C字符串和数组
math.h定义了几个函数执行数学操作
ctype.h声明了一组用于分类和转换单个字符的函数
time.h定义了获取和操作日期和时间信息的函数

string.h是C库头文件,对应基于char*的字符串处理函数
cstring是c++对标准c字符串处理函数的c++增强
string是C++标准库(STL)中string字符串类,定义了字符串的各种操作

4、C语言定义结构体
结构体成员的定义方式与变量和数组的定义方式相同,只是不能初始化。
①先定义结构体类型,再定义结构体变量

struct student{
结构体成员;
};
struct student stu1;

②定义结构体类型的同时定义结构体变量

struct student{
结构体成员;
}stu1;
//之后还可以继续定义结构体变量,如struct student stu2;

③不指定结构体类型而直接定义结构体变量

struct {
结构体成员;
}stu1;
//一般不使用这种方法,因为直接定义结构体变量stu1之后,就不能再继续定义该类型的变量。

④用typedef定义结构体变量

typedef  struct student {
结构体成员;
}STU;
//用STU代替struct student,之后定义变量可以直接STU stu1;

结构体用点号" . “获取单个成员,如stu1.成员名;
定义结构体时后面的分号” ; "不可少。需要注意的是,结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要内存空间来存储。

5、路径分析
绝对路径:指文件在硬盘上真正存在的路径,如‪"E:\egg\count.cpp".
相对路径:相对于目标文件的位置。
如果1.txt在"E:\egg"目录下,和count.cpp同目录下,count.cpp读1.txt,路径route=“1.txt”。
如果1.txt在file目录下,而file与count.cpp同目录下,则count.cpp读1.txt,路径route=“file/1.txt”。
如果1.txt的位置是"E:\1.txt",在count.cpp的上一级目录,则count.cpp读1.txt,路径route="…/1.txt"。
根目录:指逻辑驱动器的最上一级目录,是相对于子目录来说的。
相对虚拟目录:如route="/file/1.txt";file前面有个"/“字符,这个“/”代表的是虚拟目录的根目录。
若把"E:\egg"设为虚拟目录,那么”/file/1.txt"的真实路径为"E:\egg\file\1.txt"。

6、C语言输入输出
①输出。在C语言有三个函数可以用来在显示器上输出数据。
a、puts():(output string)只能输出字符串,并且在输出结束后会自动换行。
b、putchar():只能输出单个字符。
c、printf():可以输出各种类型的数据,完全可以替代 puts() 和 putchar()。

printf输出
格式控制符		说明
	%c			输出一个单一的字符
%hd\%d\%ld		以十进制、有符号的形式输出 shortintlong 类型的整数
%hu\%u\%lu		以十进制、无符号的形式输出 shortintlong 类型的整数
%ho\%o\%lo		以八进制、不带前缀、无符号的形式输出 shortintlong 类型的整数
%#ho\%#o%#lo	以八进制、带前缀、无符号的形式输出 shortintlong 类型的整数
%hx\%x\%lx		以十六进制、不带前缀、无符号的形式输出 shortintlong 类型的整数。这里的x也可大写,若是大写的X,那么输出的十六
				进制和前缀也要大写
%#hx\%#x\%#lx	以十六进制、带前缀、无符号的形式输出 shortintlong 类型的整数.x与X与上面同理。
%f\%lf			以十进制的形式输出 floatdouble 类型的小数
	%s			输出一个字符串

printf()整齐输出用法:
printf()格式控制符的完整形式如下:

%[flag][width][.precision]type
//flag 是标志字符。如%#x中flag为 #,%-3d中flag为 - 。
标志符号			含义
  -			表示左对齐。如果没有,就按照默认的对齐方式,默认一般为右对齐。
  +			用于整数或者小数,表示输出符号(正负号)。如果没有,那么只有负数才会输出符号。
  空格		用于整数或者小数,输出值为正时冠以空格,为负时冠以负号。
  #			对于八进制(%o)和十六进制(%x / %X)整数,# 表示在输出时添加前缀;八进制的前缀是 0,十六进制的前缀是 0x / 0X。
  			对于小数(%f / %e / %g),# 表示强迫输出小数点。如果没有小数部分,默认是不输出小数点的,加上 # 以后,即使没有小数部分也会带上小数点。
  			
//width 表示至少占用几个字符的位置,如%-3d,这里的width=3表示输出结果最少占用3个字符的宽度。若输出结果的宽度不足width,以空格补齐。若没有对齐方式,默认会在左边补齐空格。

//.precision 表示输出精度,也就是小数的位数。
 - 当小数部分的位数大于 precision 时,会按照四舍五入的原则丢掉多余的数字。
 - 当小数部分的位数小于 precision 时,会在后面补 0- 
//.precision 也可以用于整数和字符串,但是功能却是相反的
 - 用于整数时,.precision 表示最小输出宽度。与 width 不同的是,整数的宽度不足时会在左边补 0,而不是补空格。
 - 用于字符串时,.precision 表示最大输出宽度,或者说截取字符串。当字符串的长度大于 precision 时,会截掉多余的字符;当字符串的长度小于 precision 时,.precision 就不再起作用。
 
//type 表示输出类型,如上面的d,f,c,x。

②输入。从键盘获得数据。
a、scanf():和printf类似,scanf()可以输入多种类型的数据。

对于scanf(),输入数据的格式和控制字符串的格式保持一致。如:
scanf("%d  %d",&m,&n);这里的%d之间是有两个空格的,所以在键入m和n的值时,也要有空格(不管有几个只要有就行),如5  7。
如果输入m后按下回车键,scanf到缓冲区读取数据,如果符合要求,程序继续等待输入。如果不符合要求就读取失败,不再让用户输入。这个是针对空格的情况,回车键相当于空格键。
如果scanf("%d,%d",&m,&n);要求输入的m和n之间有 ",",这时输入m就按下回车键,会读取失败。
如果scanf("%d ,%d",&m,&n);","之前有个空格,这时输入m就按下回车键,会再让用户输入,但是必须输入",n"才能正确读取。

以上情况是对于一个scanf()的。若是两个scanf()如:
scanf("a=%d",&a);
scanf("b=%d",&b);
这里需要输入"a=10b=5"才能符合,中间并没有空格。
但如果scanf("a=%d ",&a);%d后面有空格就可以按下回车键。

scanf()printf()非常相似,只是scanf的变量前要带有符号 "&",这个是取地址符号,取变量在内存中的地址。

我们从键盘输入的数据并没有直接交给 scanf(),而是放入了缓冲区中,直到我们按下回车键,scanf() 才到缓冲区中读取数据。如果缓冲区中的数据符合 scanf() 的要求,那么就读取结束;如果不符合要求,那么就继续等待用户输入,或者干脆读取失败。

在C语言中没有专门的字符串类型,我们只能使用数组或者指针来间接地存储字符串。如

char str1[]="aaadvffg";
char *str2="ccccccc";
//这两种形式其实是有区别的,第一种形式的字符串所在的内存既有读取权限又有写入权限,第二种形式的字符串所在的内存只有读取权限,没有写入权限。printf()、puts() 等字符串输出函数只要求字符串有读取权限,而 scanf()、gets() 等字符串输入函数要求字符串有写入权限,所以,第一种形式的字符串既可以用于输出函数又可以用于输入函数,而第二种形式的字符串只能用于输出函数。
scanf("%s",str);
str前面可以不加&,因为字符串的名字会自动转换为字符串的地址。
**scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串**

b、getchar()、getche()、getch():这三个函数都用于单个字符。
getchar()就是scanf("%c", c),getchar() 就是 scanf() 的一个简化版本。

getche()没有缓冲区,输入一个字符后会立即读取,不用等待用户按下回车键,这是它和 scanf()、getchar() 的最大区别。
getche() 位于 conio.h 头文件中,而这个头文件是 Windows 特有的,不能在 Linux 和 Mac OS 下使用。

getch() 也没有缓冲区,输入一个字符后会立即读取,不用按下回车键,这一点和 getche() 相同。getch() 的特别之处是它没有回显,看不到输入的字符。
getch() 也位于 conio.h 头文件中,也不是标准函数,默认只能在 Windows 下使用,不能在 Linux 和 Mac OS 下使用。

c、gets():获取一行数据,并作为字符串处理。
gets() 是有缓冲区的,每次按下回车键,就代表当前输入结束了,gets() 开始从缓冲区中读取内容,这一点和 scanf() 是一样的。gets() 和 scanf() 的主要区别是:

  • scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。
  • gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。

7、文件操作
常见的文件有Word、txt、源文件等,而在操作系统里不同的硬件设备也被看成一个文件,对这些文件的操作也等同于磁盘上普通文件的操作。如:
通常把显示器成为标准输出文件,printf就是向这个文件输出数据。
通常把键盘称为标准输入文件,scanf就是从这个文件读取数据。

stdin	标准输入文件,一般指键盘;scanf()getchar() 等函数默认从 stdin 获取输入。
stdout	标准输出文件,一般指显示器;printf()putchar() 等函数默认向 stdout 输出数据。
stderr	标准错误文件,一般指显示器;perror() 等函数默认向 stderr 输出数据。
stdprn	标准打印文件,一般指打印机。

操作文件的正确流程为:打开文件 --> 读写文件 --> 关闭文件。文件在进行读写操作之前要先打开,使用完毕要关闭。打开文件,就是获取文件的有关信息,例如文件名、文件状态、当前读写位置等,这些信息会被保存到一个 FILE 类型的结构体变量中。关闭文件就是断开与文件之间的联系,释放结构体变量,同时禁止再对该文件进行操作。数据从文件复制到内存的过程叫做输入流,从内存保存到文件的过程叫做输出流。

①打开文件
<stdio.h>头文件里的fopen()函数打开文件,用法为:

FILE *fopen(char *filename, char *mode);
//会返回指针,即保存相关信息的结构体变量(FILE类型的)
//如FILE *fp = fopen("1.txt","r");fp指向该文件,若打开文件出错,fopen()会返回一个空指针NULL。
//filename文件名(包括文件路径),mode表示打开方式,他们都是字符串
//mode为打开文件方式

控制读写权限的字符串(必须指明)
| 打开方式 | 说明 |
| "r"  	  |	以“只读”方式打开文件。只允许读取,不允许写入。文件必须存在,否则打开失败。|
| "w"	  |	以“写入”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(删了再创)|
| "a"	  |	以“追加”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾|
| "r+"	  |	以“读写”方式打开文件。既可以读取也可以写入,也就是随意更新文件。文件必须存在,否则打开失败。|
| "w+" 	  | 以“写入/更新”方式打开文件,相当于w和r+叠加的效果。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容|
| "a+"	  |	以“追加/更新”方式打开文件,相当于a和r+叠加的效果。|

控制读写方式的字符串(可以不写)
| 打开方式 | 说明 |
| "t"	  |	 文本文件。如果不写,默认为"t"|
| "b"	  |  二进制文件|

读写权限和读写方式可以组合使用,但是必须将读写方式放在读写权限的中间或者尾部,就是说不能将读写方式放在读写权限的开头。
将读写方式放在读写权限的末尾:“rb”、“wt”、“ab”、“r+b”、“w+t”、“a+t”
将读写方式放在读写权限的中间:“rb+”、“wt+”、“ab+”

文件打开方式由 r、w、a、t、b、+ 六个字符拼成,各字符的含义是:

  • r(read):读
  • w(write):写
  • a(append):追加
  • t(text):文本文件
  • b(banary):二进制文件
  • +:读和写

②关闭文件
fclose()函数把文件关闭,如fclose(fp);

③读写文件
a、字符读取函数fgetc(file get char,即从文件中读取一个字符)。用法如下:

int fgetc(FILE *fp);
//fgetc() 读取成功时返回读取到的字符,读取到文件末尾或读取失败时返回EOF(end of file).是定义在stdio.h的宏,它的值是一个负数,往往是-1。
//文件内部有一个位置指针,用来指向当前读写到的位置。在文件打开时,该指针总是指向文件的第一个字节。使用 fgetc() 函数后,该指针会向后移动一个字节,所以可以连续多次使用 fgetc() 读取多个字符。

很多函数在读取出错时也返回 EOF,我们可以借助 stdio.h 中的两个函数来判断文件读取完毕了还是读取出错了.
feof() 函数用来判断文件内部指针是否指向了文件末尾,用法如下:

int feof ( FILE * fp );
//当指向文件末尾时返回非零值,否则返回零值。

ferror() 函数用来判断文件操作是否出错,用法如下:

int ferror ( FILE *fp );
//出错时返回非零值,否则返回零值

b、字符写入函数 fputc(file output char,向指定的文件中写入一个字符)。用法如下:

int fputc ( int ch, FILE *fp );
//ch 为要写入的字符,fp 为文件指针。fputc() 写入成功时返回写入的字符,失败时返回 EOF. 
//若文件不存在时则创建该文件。
//每写入一个字符,文件内部位置指针向后移动一个字节

c、读字符串函数 fgets,从指定的文件中读取一个字符串,并保存到字符数组中,用法如下:

char *fgets ( char *str, int n, FILE *fp );
//str 为字符数组,n 为要读取的字符数目,fp 为文件指针。
//返回值:读取成功时返回字符数组首地址,也即 str;读取失败时返回 NULL;如果开始读取时文件内部指针已经指向了文件末尾,那么将读取不到任何字符,也返回 NULL。
//读取到的字符串会在末尾自动添加 '\0',n 个字符也包括 '\0',实际只读取到了 n-1 个字符。

在读取到 n-1 个字符之前如果出现了换行,或者读到了文件末尾,则读取结束。fgets() 最多只能读取一行数据,不能跨行。
fgets() 遇到换行时,会将换行符一并读取到当前字符串。gets() 不一样,它会忽略换行符。

d、写字符串函数 fputs,向指定的文件写入一个字符串。用法如下:

int fputs( char *str, FILE *fp );
//str 为要写入的字符串,fp 为文件指针。写入成功返回非负数,失败返回 EOF。

e、读写数据块
fread()用来从指定文件中读取块数据。块数据,就是若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制。用法如下:

size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );

fwrite() 函数用来向文件中写入块数据。用法如下:

size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );
  • ptr 为内存区块的指针,它可以是数组、变量、结构体等。fread() 中的 ptr 用来存放读取到的数据,fwrite() 中的 ptr 用来存放要写入的数据。
  • size:表示每个数据块的字节数。
  • count:表示要读写的数据块的块数。
  • fp:表示文件指针。

size_t 是在 stdio.h 和 stdlib.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。
返回值:返回成功读写的块数,也即 count。如果返回值小于 count:

  • 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。
  • 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测。

函数rewind(),头文件是#include<stdio.h>。用于将文件指针重新指向文件的开头,同时清除和文件流相关的错误和eof标记。用法如下:

void rewind(FILE * stream);
//stream为打开文件的指针,相当于上面的fp;

相当于调用
fseek(stream, 0, SEEK_SET);

函数ftell()获得当前的位置指针。

注意:fgetc和fputc是每次操作一个字符,fgets和fputs是每次操作一行,fread和fwrite是操作块数据,可以是一个字符,可以是一个字符串,可以是多行数据。

④格式化读写文件
fscanf() 和 fprintf() 函数与前面使用的 scanf() 和 printf() 功能相似,都是格式化读写函数,两者的区别在于 fscanf() 和 fprintf() 的读写对象不是键盘和显示器,而是磁盘文件。两个函数的原型是:

int fscanf ( FILE *fp, char * format, ... );
int fprintf ( FILE *fp, char * format, ... );
//与 scanf() 和 printf() 相比,它们仅仅多了一个 fp 参数。
//scanf()从键盘读入数据,fscanf()是从文件读入数据。若fp设置为stdin,那么 fscanf() 函数将会从键盘读取数据,与 scanf 的作用相同。
//printf()输出数据到显示器,fprintf()输出数据到文件。若fp设置为 stdout,那么 fprintf() 函数将会向显示器输出内容,与 printf 的作用相同。

⑤随机读写文件
移动文件内部位置指针的函数主要有两个,即 rewind() 和 fseek()。
rewind() 用来将位置指针移动到文件开头。用法如下:

void rewind ( FILE *fp );

fseek() 用来将位置指针移动到任意位置。用法如下:

int fseek ( FILE *fp, long offset, int origin );
//fp 为文件指针,也就是被移动的文件
// offset 为偏移量,也就是要移动的字节数。之所以为 long 类型,是希望移动的范围更大,能处理的文件更大。offset 为正时,向后移动;offset 为负时,向前移动。
//origin 为起始位置,也就是从何处开始计算偏移量。
起始点		常量名		常量值
文件开头		SEEK_SET	0
当前位置		SEEK_CUR	1
文件末尾		SEEK_END	2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值