C语言-笔记
1.数据类型
基本类型:
整型:整型、短整型、长整型、无符号整型
浮点型:单精度、双精度、长双精度
字符型
枚举类型:enum enum response{no,yes,none};
构造类型:
数组
结构体
共用体
指针类型
无类型:void
2.局部变量与全局变量
全局变量:所有语句块外,作用域为整个程序
局部变量:作用在语句块内
3.变量的存储类型
自动变量:进入语句块时自动申请内存,退出语句块时自动释放内存,也称动态局部变量,在不同的并列语句块内可以定义同名变量,因为它们各自占据不同内存单元,并且有着不同的作用域。形参和实参可以同名
静态变量:
外部变量:
寄存器变量:
函数的参数传递是“单向的值传递”,即只能将实参的值单向传递给形参,而不能反向将形参的值传给实参,形参值的改变也不会影响实参
4.数组
数组名代表数组第一个元素的地址,因此用数组名作函数实参实际上是将数组的首地址传给被调函数
向函数传递一维数组:使用不带方括号的数组名作为函数实参调用函数即可
int Average( int score[ ], int n );
...
aver=Average( score , n );
数组作函数形参时,数组长度可以不出现在数组名后边的方括号内,通常用另一个整型形参来指定数组的长度。 如果数组名后出现数字,则只检查是否大于零,若是,则忽略,若为负数,则产生编译器错误。
向函数传递二维数组
当形参被声明为一维数组时,形参列表中数组的方括号可以为空。
当形参被声明为二维数组时,可以省略数组第一维的长度声明,但不能省略数组第二维的长度声明。
5.指针
变量在内存中所占存储空间的首地址,称为该变量的地址,而变量在存储空间中存放的数据,称为变量的值。
指针:存放变量地址的一种特殊类型变量
指针变量:具有指针类型的变量
定义格式: 类型关键字 * 指针变量名
定义指针变量时,须初始化指针变量,也可先将其初始化为NULL
指针变量只能指向同一基类型的变量
int * pa = &a; 等价于以下两条语句
int * pa;
pa = &a; 含义为:定义一个可以指向整型数据的指针变量pa,并用整型变量a的地址值对指针变量pa进行初始化,从而使指针变量pa具体地指向了整型变量a。
直接寻址:直接按变量名或者变量的地址存取变量的内容的访问方式
间接寻址:通过指针变量间接存取它所指向的变量的访问方式
间接寻址运算符 &
使用指针三条原则:
1)永远清楚每个指针指向了哪里,指针必须指向一块有意义的内存;
2)永远清楚每个指针指向的对象的内容是什么;
3)永远不要使用未初始化的指针
按值调用与按地址调用
按值调用不能在被调函数中改变调用语句中的实参值
按地址调用是一种常用的从函数中返回修改了的数据值的方法(使用return语句只能从被调函数中返回一个值)
函数指针:指向函数的指针,指向函数的指针变量中存储的是一个函数在内存中的入口地址
6.字符串
字符串:由若干有效字符构成且以字符 '\0' 作为结束的一个字符序列
C语言没有字符串数据类型,字符串的存取由字符型数组实现
字符串结束标志 '\0' 也占一个字节的内存,但它不计入字符串的实际长度,只计入数组的长度
字符数组的大小一定比字符串中实际的字符多1
按s格式符,将字符串作为一个整体输入/输出
scanf("%s", str[i]) 表示读入一个字符串,直到遇到空白字符(空格、回车符或制表符)为止
printf("%s", str[i]) 表示输出一个字符串,直到遇到字符串结束标志为止
用函数scanf()按s格式符不能输入带空格的字符串
使用字符串处理函数 get() ,可以输入带空格的字符串,因为空格和制表符都是字符串的一部分
函数gets()与scanf()对回车符的处理不同。gets()以回车符作为字符串的终止符,同时将回车从输入缓冲区读走,但不作为字符串的一部分。而scanf()不读走回车符,回车符仍留在输入缓冲区中
函数puts()用于从括号内的参数给出的地址开始,依次输出存储单元中的字符,当遇到第一个'\0'时输出结束,并且自动输出一个换行符
函数gets()不能限制输入字符串的长度,很容易引起缓冲区溢出,scanf()函数也存在这个问题
使用scanf()和gets输入字符串时,要确保输入字符串的长度不超过数组的大小,否则建议使用能限制输入字符串长度的函数, fgets ( name, sizeof (name) ,stdin ) ;
字符串处理函数:
求字符串长度 strlen(str);
字符串复制 strcpy(str1,str2);
字符串比较 strcmp(str1,str2);
字符串连接 strcat(str1,str2);
声明一个返回指针值的函数 char *MyStrcat(char *dstStr, const *srcStr);
返回指针值的函数与函数指针
char *f() 声明一个返回字符指针的函数f()
char (*f)(); 该函数指针指向的函数没有形参,返回值是字符型
***7.const类型限定符
当不希望数据被修改时,可以使用const对参数进行限定
当声明一个指针变量时,这个指针变量本身的值以及它所指向的数据都可以被声明为const。const位于声明语句中的不同位置,表示不同的含义。主要有以下几种情况:
(1)const放在类型关键字的前面
int a,b;
const int *p = &a;
按照从右到左的顺序,p是一个指针变量,指向一个整型常量。*p是一个常量而p不是。
(2)const放在类型关键字的后面和*变量名的前面
int const *p = &a;
按照从右到左的顺序,p是一个指针变量,可指向一个常量整数。*p是一个常量,而p不是。和第一种情况等价
(3)const放在类型关键字*的后面,变量名的前面
int * const p = &a;
按照从右到左的顺序,p是一个常量指针,可指向一个整数。p是一个常量,而*p不是。
(4)一个const放在类型关键字之前,另一个const放在类型关键字*之后和变量名之前
const int* const p = &a;
按照从右到左的顺序,p是一个常量指针,可指向一个整型常量。p和*p都是一个常量,都是只读的。
字符处理函数
int isdigit(int c); 如果c为数字,则返回真
int isalpha(int c) 如果c为字母,为真
int isalnum(int c) 数字或字母返回真
int islower(int c) 小写字母返回真
int isupper(int c) 大写字母返回真
int tolower(int c) 如果是大写字母,转换为小写字母返回,否则返回为改变的实参值
int toupper(int c) 如果是小写字母,转换为大写字母返回,否则返回未改变的实参值
int isspace(int c) 如果c是空白字符----换行符('\n'),空格符(' '),换页符('\f'),回车符('\r'),水平制表符('\t'),垂直制表符('\v'),则返回真
8.指针和二维数组的关系
a[i] [j]的4种表示法
a[i] [j] *(a[i] + j) *(*(a + i) + j) (*(a + i))[j]
9.动态数组
C程序在编译后获得并使用4块在逻辑上不同且用于不同目的的内存区。
只读存储区:存放只读数据
静态存储区:存储全局变量和静态变量
动态存储区 堆:自由存储区,程序可利用C的动态内存分配函数来使用它
栈:用于保存函数调用时的返回地址、函数的形参、局部变量以及CPU的当前状态等程序的运行信息
动态内存分配函数
指针的几点重要用处:
(1)指针为函数提供修改变量值的手段;
(2)指针为C的动态内存分配系统提供支持;
(3)指针为动态数据结构(如链表、队列、二叉树等)提供支持;
(4)指针可以改善某些子程序的效率
使用动态内存分配函数时,需加头文件<stdlib.h>
(1)函数malloc()
void *malloc( unsigned int size);
用于分配若干字节的内存空间,返回一个指向该内存首地址的指针,若系统不能够提供足够的内存单元,函数将返回空指针NULL。
int *pi=NULL;
pi = (int *)malloc(sizeof(int));
(2)函数calloc()
void *calloc(usigned int num, unsigned int size);
用于给若干同意类型的数据项分配连续的存储空间并赋值为0
(3)函数free()
void free(void *p)
释放向系统动态申请的由指针p指向分存储空间
(4)函数realloc()
void *realloc(void *p, unsigned int size);
用于改变原来分配的存储空间的大小
常见内存异常错误有两类:
一是非法内存访问错误,即代码访问了不该访问的内存地址
二是因持续的内存泄露导致系统内存不足
野指针
指向垃圾内存的指针
当内存被释放后,指向它的指针不会自动变成空指针。 野指针不是空指针。
野指针形成原因:
(1)指针操作超越了变量的作用范围,如用return语句返回动态局部变量的地址
(2)指针变量未被初始化,指针混乱往往使得结果变得难以预料和莫名奇妙
(3)指针变量所指向的动态内存被free后未置为NULL,让人误以为它仍是合法的指针
上述情况的解决对策:
(1)不要把局部变量的地址(即指向“栈内存”的指针)作为函数的返回值返回,因为局部变量分配的内存再退出函数时将被自动释放;
(2)在定义指针变量的同时对其初始化,要么设置为NULL,要么使其指向合法内存;
(3)尽量把malloc()集中在函数的入口处,free()集中在函数的出口处,避免内存被释放后继续使用
10.结构体
抽象数据类型(Abstract Data Type, ADT):一种数据类型,包括一组值的集合和作用在值集上的操作的集合
struct 结构体名
{
数据类型 成员1的名字;
数据类型 成员2的名字;
...
数据类型 成员n的名字;
};
用typedef定义数据类型
关键字typedef用于为系统固有的或程序员自定义的数据类型定义一个别名。
例: typedef int INTEGER;
为int定义了一个新的名字INTEGER,即INTEGER与int是同义词
typedef struct student STUDENT; 等价于
typedef struct student
{
...
}STUDENT;
STUDENT stu1, stu2; 等价于
struct student stu1, stu2;
结构体变量的引用
结构体变量名.成员名
11.共用体
将不同类型的数据组织在一起共同占用一段内存的一种构造数据类型
每次只能有一种数据类型起作用
12.枚举数据类型
枚举数据类型描述的是一组整型值的集合,由关键字enum来定义
例: enum response{no, yes, none}; 花括号内的标识符都是整型常量,称为枚举常量
enum response answer;
也可 enum {no, yes, none}answer;
13.动态数据结构----单向链表
利用动态内存分配、使用结构体并配合指针来实现的一种数据结构
struct temp
{
int data;
struct temp pt;
};
上述程序在Code::Blocks下编译将出现如下错误提示:
field 'pt' has incomplete type
在Visual C++下编译将出现以下错误:
'pt' uses undefined struct 'temp'
这说明,结构体声明时不能包含本结构体类型成员。因为本结构体类型尚未定义结束,它所占用的内存字节数尚未确定,因此系统将无法为这样的结构体类型分配内存
然而,在声明结构体类型时可以包含指向本结构体类型的指针成员。因为指针变量存放的数据是地址,系统为指针变量分配的内存字节数是固定的,不依赖于它所指向的数据类型。
包含指向本结构体类型的指针成员的结构体类型声明方式如下:
struct temp
{
int data;
struct temp *pt;
};
14.文件操作
C语言文件有两种类型:文本文件和二进制文件
文本文件中的每一位数字都单独占用一个字节的存储空间,而二进制文件则是把整个数字作为一个二进制数来存储,并非数值的每一位数字都占用单独的存储空间
对文件的存取是以字节为单位的
打开文件函数fopen()
FILE *fopen(const char *filename, const char *mode);
第一个形参filename表示文件名,可包含文件路径和文件名两部分
第二个形参mode表示文件打开方式:
“r" 以只读方式打开文本文件
”w" 以只写方式,创建并打开文本文件,已存在的文件将被覆盖
“a" 以只写方式打开文本文件,位置指针移到文件末尾,向文件尾部添加数据,原文件保留。若文件不存在,则会出错
”+" 与上面的字符串组合,表示以读写方式打开文本文件。既可向文件中写入数据,也可从文件中读取数据
“b" 与上面的字符串组合,表示打开二进制文件
关闭文件函数fclose()
int fclose(FILE *fp); 其中文件指针fp定义为: FILE *fp
当文件关闭成功,返回0值,否则返回其他值
读写文件中的字符
函数fgetc()用于从一个以只读或读写方式打开的文件上读字符 int fgetc(FILE *fp);
若文件读到末尾,则返回EOF(EOF是一个符号常量,在stdio.h中定义为-1)
函数fputc()用于将一个字符写到一个文件上 int fputc(int c, FILE *fp);
按格式读写文件
函数fscanf()用于按指定格式从文件读数据 int fscanf(FILE *fp, const char * format, ...);
函数fprintf()用于按指定格式向文件写数据 int fprintf(FILE *fp, const char *fpormat, ...);
按数据块读写文件
unsigned int fread(void *buffer, unsigned int size, unsigned int count, FILE *fp);
fread()的功能是从fp所指的文件中读取数据块并存储到buffer指向的内存中。 函数返回的是实际读到的数据块个数
unsigned int fwrite( const void *buffer, unsigned int size, unsigned int count, FILE *fp);
fwrite()的功能是将buffer指向的内存中的数据块写入fp所指的文件中 函数返回的是实际写入的数据块个数