前言:此篇blog主要为了回顾C语言的一些基本知识点,稍微梳理一下
C语言的一些基本概念及结构。并不作具体讲解。
(1)main是主函数的函数名,每个程序都必须有且只有一个main函数;程序总是从main函数开始执行。
(2)每个c语句以分号结尾。
(3)使用标准库函数应在程序开头一行写#include
(4)C语言注释的两种形式:
a.单行注释" // "
b.多行注释" / * 注释内容 * /
(5)scanf()输入函数:
应用方式scanf("%d%d",&a,&b);
&是地址符,“&a”的含义是“变量a的地址”;
若双引号中为"%d,%d"形式,则输入时也应加逗号;
(6)函数是c程序的主要组成部分,一个函数包含两部分:
函数首部和函数体:
函数首部组成:
函数类型 函数名 (函数参数类型 函数参数名 函数参数类型 函数参数名)
eg:int max (int x, int y)
函数体亦包含两部分:声明部分和执行部分,两部分都在{}内;
函数体{
声明部分(对变量,函数等的声明)
执行部分(要实现的一些操作和功能)
}
(1)符号常量和常变量的区别:
a.符号常量:
用 # define 指令,指定用一个符号名称代表一个常量
eg:#define PI 3.1416 // 注意行末没有分号
/*经过以上的指定,文件从此行开始所有的 PI 都代表3.1416
优点:
含义清楚
在需要改变程序中多处用到的同一个常量时,
能做到“一改全改”
符号常量不占内存,在预编译后符号就不存在了,故不能对符号常量
附以新值*/
b.常变量
eg:const int a = 3;
/*表示a被定义一个整型变量,指定其值为3,而且在变量存在期间其
值不能改变*/
/*常变量和常量的异同:常变量具有变量的基本属性:有类型,占存
储单元,只是不允许改变其值,可以说,常变量是有名字的不变量,
而常量是没有名字的不变量*/
(2)标识符:
用来对变量、符号常变量、函数、数组、类型等命名的有效字符序列。(可理解为对象的名字)
C语言中规定只能由字母、数字、下划线三种字符组成,且第一个字符必须为字母或下划线。
(3)字符型数据:
‘a’, ‘b’, ’ ‘, 等 空(null)字符(以’\0’表示)(字符数组中在输入字符串结束后会自动补加一个’\0’用以表示结束标志)’ '(空格字符的ASCII代码是十进制数32) '0’的ASCII码是十进制数48
(4)C语言中实型常量都是双精度浮点型常量(double型)
(5)自增、自减、运算符:
自增 ++i,i++;
++i 表示先自加1,然后再参与运算
eg:
a = 1;
b = ++a + 1;
则 b = 3;a = 2
i++表示先运算,再自加1
eg:
a = 1;
b = a ++ + 1;
则 b = 2;a = 2
(6)字符(char)型数据可以与整型数据进行运算,就是把字符的ASCII代码与整型数据进行运算。
如12 + ‘A’,等于77(A的ASCII代码为65)
(7)强制类型转换运算符:
(类型名)(表达式)
如(int)(x+y)
将x+y的值强制转换为int型
(8)%m.nf格式输出含义
eg:printf("x = %7.2f",x);
即指定输出的数据占7列,其中小数点占2列,对齐方式为右对齐;%-7.2f为左对齐
(9)使用%c格式输入时应注意空格字符和“转义字符”中的字符都将作为有效字符输入,所以输入时中间不能有空格。
(10)break和continue:
break:结束整个循环 continue:结束本次循环
break语句可用在循环结构和switch结构中
continue用在循环结构中,跳过当前循环的后续语句,执行下一次的循环
(11)求字节运算符sizeof(类型名/表达式)
计算出某种类型的量存储时/表达式计算结果所占用的字节数
(1)定义引用数组
类型名 数组名 [常量表达式];
int a[10];char c[10];
定义一个长度为10的整型数组,下标从0开始
引用数组元素
数组名 [下标]
t = a[2];
将数组元素中a[2]的值赋给t,
(2)字符串
将字符串作为字符数组来存储,为了测定字符串的实际长度,规定了一
个字符串结束标志'\0'用字符数组存储字符串会自动在结尾加一个'\0'
作为结束符('\0'代表ASCII码为0的字符,它不是一个可以显示的字符,
而是一个“空操作符”,即它什么也不做(谭浩强p157页))
(3)字符数组的输入输出
将字符串一次输入或输出
char c[]={"China"};
printf("%s\n",c);
scanf("%s",c) ;
注意:C语言将空格作为输入字符串之间的分隔符!
puts(str);
gets(str);//运用此函数时回车也将作为字符送入字符数组中
(4)字符串的一些常用函数
strcat(str1, str2); //字符串连接函数str1 and str2均为字符数组名
strcpy(str1, str2); //字符串复制函数str2可以是字符数组名,也
可以是字符串常量
strncpy(str1, str2, n); //将字符串2中前n个复制到str1中
strcmp(str1, str2); //自妇产比较函数,str1和str2均为字符串
strlen(字符数组/字符串); //测字符串长度的函数(实际长度)
strlwr(字符串)strupr(字符串); //转化为大小写的函数
注意:在使用字符串处理函数时,在开头加一个#include
(1)对于有参函数,实参可以是常量、变量、表达式、数组元素;从实参到形参,单向传递(值传递)。以及数组名(传递的是数组第一个元素的地址,在调用数组的函数中,函数可以使用数组中的所有值,同时,在该函数中进行的数组元素的运算,将会改变原数组中相应元素的值(数组元素在函数中的调用方式a[m]相当于指针)即使用数组名传递是双向的)。
(2)用数组名作函数参数时,应在主调函数和被调函数中分别定义数组,且实参数组和形参数组类型应一致。
(3)局部变量与全局变量
局部变量:在函数内部或复合语句中定义的变量,作用域为该函数,形
式参数也是局部变量。
复合语句(也称为分程序或程序块),在某一函数中,要完成一定功能,
用“{}”与所在函数“分开”。
全局变量:亦称为外部变量,在函数之外定义的变量,外部变量可以为
本文件中其他函数所公用,有效范围是从定义变量开始的地方到本文件
结束。
全局变量名的第一个字母一般用大写表示。
如果全局变量与局部变量重名,则局部变量有效。
(4)静态局部变量static
函数中局部变量的值在调用函数后不消失而继续保留原值,占用的存储单元不释放,在下次调用时该变量已有值,作用域仍为该函数(上次调用结束时的值)
(5)将外部变量(函数)的作用域扩展到其他源程序文件中,在源程序文件中加extern 变量(函数)进行声明;若要将外部变量(或函数)的作用域限制在本程序文件中(此时称为内部函数),在定义该外部变量时要加一个static声明。
(1)指针的概念
在对程序编译时,系统会给变量分配内存单元(即字节,一定长度的
内存空间)内存单元都有相应的编号(即地址)编号(地址)指向该
变量单元,通过地址可以找到该变量,地址形象化的称为“指针”。
程序经过编译之后将变量名转化为地址,通过变量名可以找到变量中
所存储的值。(这种直接按变量名进行的访问,称为“直接访问”)
间接访问:将变量的地址存放到另一变量中,通过该变量找到变量的
地址,进而访问变量的值。一个变量的地址称为该变量的“指针”。
(2)指针变量
专门用来存放另一个变量的地址的变量即为指针变量。指针变量就是地址变量,用来存放地址。
定义指针变量:
类型名 *指针变量名;
如int *p;表示此指针变量可以指向的变量类型为int型。
定义指针变量时可以对其初始化:int *p = &a;
注意:定义指针变量时,指针前的*号表示该变量的类型为指针型变量,
指针变量名为p,在后续操作中指针变量p用于接收地址,*p代表指针
变量中所存储的变量的值。
(3)指针变量作为函数参数
作用是将一个变量的地址传送到另一个函数中;
特点:共享内存,双向传递。(指针变量作为函数参数:在函数执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量的值依然保留下来)
(4)指针引用数组
若p的初值为&a[0] 则 p+i和a+i就是数组元素a[i]的地址,他们指向a数组序号为i的元素,*(p+i)或 *(a+i) 与a[i]等价且可用p[i](等价于* (p+i))引用a[i]
(5)实参数组名a代表一个固定的地址,或者说是指针常量,不能a++,但在函数调用数组名操作中,函数的形参数组名按指针变量处理,可以被赋值。
(6)二维数组a的有关指针 (int a[3][4])
《C程序设计(第四版)》谭浩强P247
表示形式 | 含义 | 地址 |
---|---|---|
a | 二维数组名,指向一维数组a[0],即0行首地址 | 2000 |
a[0], * (a+0), * a | 0行0列元素地址 | 2000 |
a+1, &a[1], | 1行首地址 | 2016 |
a[1], *(a+1) | 1行0列元素a[1][0]的地址 | 2016 |
a[1]+2, *(a+1)+2, &a[1][2] | 1行2列元素a[1][2]的地址 | 2024 |
*(a[1]+2),*(*(a+1)+2), a[1][2] | 1行2列元素a[1][2]的值 | 元素值为13 |
1.从二维数组的角度看,a代表二维数组首元素的地址,现在的首元素
不是一个简单的整型元素,而是由四个整型元素所组成的一维数组,因
此a代表的是首行(即序号为0的行)的首地址,a+1代表序号为1的行
的首地址。a+1指向a[1],或者说,a+1的值是a[1]的首地址。
2.a[0],a[1],a[2]是一维数组名,数组名代表数组首元素的地址,
因此,a[0]等价于&a[0][0];a[2]是一维数组名,该一维数组中序号
为1的元素地址用a[2]+1表示,在一维数组中,a[i]和*(a+i)等价,在
二维数组中,直接沿用该规则(书上解释的也是云里雾里,╮(╯▽╰)╭
无脑替换就行)
3.承上 一维数组中序号为1的元素地址用a[2]+1表示,故a[2]+1的值
可用*(a[2]+1)表示
(7)指向多维数组的指针变量
a.指向数组元素的指针变量int *p(和一维数组相似p+1指向下一个元素)
b.指向由m个元素组成的一维数组的指针变量int ( * p)[4]
如果p指向一维数组a[0] (此处p=&a[0],0行首地址)则p+1指向一维数组a[1]
(8)通过指针引用字符串
char * p = “I LOVE YOU”(定义并初始化)
引用方式为printf("%s",p)
字符指针变量存放的时字符串第一个字符的地址,可以对字符串中字符进行引用eg: p[2]或 *(p+2)
(9)指向函数的指针int (*p)(int, int)
使用方式 p=函数名;
后续调用(*p)(a,b)等价于函数调用。
(10)返回指针型的函数
类型名 *函数名(参数表列)返回一个指向(类型名)的指针
(11)指针数组
数组中元素均为指针类型数据(元素都存放一个地址,相当于一个指针变量)
类型名 * 数组名[数组长度]
指针数组比较适合用来指向若干个字符串
(12)指向指针数据的指针
定义一个指针变量,让它指向指针数组中的元素,则该变量就是指向指针的指针
对于char **name[5] name + 2是name[i]的地址,name+i就是指向指针类型的指针,定义char **p;
p=name+i
则*p即为name+i的值name[i] (它是一个字符指针),指向一个字符串,printf("%s",*p)作用为输出字符串。
(13)动态分配内存与指向他的指针变量
建立内存的动态分配:
malloc函数
函数原型
void *malloc(unsigned int size);
在内存的动态存储区中分配一个长度为size的连续空间,次函数的返回
值是所分配区域的第一个字节的地址,或者说,次函数是一个指针型函
数,反悔的指针指向该分配区域的开头位置。(未能成功执行,则返回
一个空指针(NULL))
calloc函数
void *calloc(unsigned n, unsigned size)
在内存的动态存储区分配n个长度为size的连续空间
free函数
void free(void *p)
释放指针变量p所指向的动态空间
realloc函数
void *realloc(void *p,unsigned int size)
重新分配通过malloc和calloc获得的空间大小(将空间大小改变为size)
p的值不变
进行类型转换,以指向相应类型数据
eg: int *pt;
pt = (int *)malloc(100)
以上四个函数都包含在 stdlib.h中,故引用是要加
#include
(1)结构体
概念:由不同类型数据组合成的组合型数据结构
一般形式:
struct 结构体名
{成员表列};
成员(子项):
类型名 成员名
定义结构体类型变量和一般类型定义变量相同,只是类型名是由自己
定义的
NO1 eg:
结构体类型名 结构体变量名
int a
struct Student student1
NO2 eg:
struct Student
{成员表列}student1,student2;
(对结构体变量中的成员(即域)可以单独使用)
(2)结构体变量的初始化及引用
在定义结构体变量时可以对他的成员初始化,初始化列表是用{}括起来
的一些常量,这些常量依次赋值给结构体变量中的各成员
对某一成员初始化:b = {.name ="XiaoMing"}
引用结构体变量中成员的值
结构体变量名.成员名
可以对变量的成员赋值
不能通过结构体变量名输出结构体变量所有成员的值,只能对各个成员
分别进行输入和输出
如果成员本身又属于一个结构体类型,则要用如干个成员运算符,一级
一级的找到最低一级的成员
同类结构体变量可以相互赋值
(3)定义结构体数组和指向结构体的指针的方式和其他类型相同
指针:struct Student *p
p = &stu_1
引用 (*p).num(p指向的结构体变量中的成员num) 等价于p->num
(4)链表
用结构体变量创建链表,,用指针型成员来存放下一节点的地址。
(5)共用体类型
几个不同的变量共享同一段内存,共用体变量所占内存长度等于最长的成员的长度,,但在每一瞬间智能存放其中一个成员,共用体变量中起作用的成员是最后一次被赋值的成员。
union 共用体名{
成员表列}变量表列;
(6)枚举类型
把可能的值一一列举出来,变量的值只限于列举出来的值得范围内。
enum [枚举名]{枚举元素表列};每一个枚举元素都代表一个整数,c语言编译按定义时的顺序默认他们的值为0,1,2,3。。。
(7)用typedef声明新类型名
方法:
按定义变量的方法,把变量名换上新类型名,并在最前面加“typedef”
(1)文件类型指针
每个被使用的文件都在内存中开辟一个相应的文件信息区,用来存放文
件的有关信息,这些信息保存在一个结构体变量中,该结构体类型是由
系统声明的,取名为FILE
声明FILE结构体类型的信息包含在stdio.h中 定义FILE类型的变量 :
FILE f1
一般通过设置一个指向FILE类型变量的指针变量来引用这些FILE类型
变量eg:
FILE *fp;
通过文件指针变量能够找到与它相关联的文件
(2)打开与关闭文件
打开:
fopen(文件名, 使用文件方式);
eg:
fopen("a1", "r");
fopen 函数返回值为指向a1文件的指针
FILE *fp
fp=fopen("a1", "r");
“r”(“rb”)只读(二进制文件);“w”(“wb”)只写(文件不存在时建立新
文件)“a”(“ab”)追加(向文本文件尾添加数据)此外还有“r+”“w+”
“a+”(带“+”都为读写)
(3)打开一个文件方法:
if(fp = fopen(“file1”,“r”) ==NULL)
{
printf(“cannot open this file\n”);
exit(0) ;
}
用fclose函数关闭数据文件
fclose(文件指针)
计算机在从ASCII文件读入字符时,遇到回车换行符,系统把它转化为一个换行符,在输出时把换行符转化为回车和换行两个字符
(4)顺序读写数据文件
fgetc(fp)从fp指向的文件中读入一个字符
(读成功,待会所读的字符,失败则返回文件结束标志EOF(即-1))
fputc(ch, fp)把字符ch写到文件指针变量fp所指向的文件(向磁盘文件输出一个字符)中(输出成功,返回值就是输出的字符,输出失败,返回EOF)
(5)向文件读写一个字符串
fgets(str, n, fp)
从fp指向的文件中读入一个长度为n-1的字符串,并在最后加一个’\0’字符存放到字符数组str中。
fputs(str, fp)(第一个参数可以为字符串常量,字符数组名,字符型指针)
(6)用格式化方式读写文件
fprintf(文件指针, 格式字符串, 输出表列)
fscanf(文件指针, 格式字符串, 输入表列)
(7)用二进制方式向文件读写一组数据
fread(buffer, size, count,fp)
fwrite(buffer, size, count,fp)
buffer 是一个存储区的地址,对fread来说(该存储区用来存放从文
件中读入的数据);对fwrite来说(把此地址开始的存储区中的数据
向文件输出)
size :要读写的字节数;
count:要读写多少个数据项(每个数据项的长度为size)
fp :FILE类型指针
在读写时以二进制形式进行
在打开文件时指定用二进制文件,就可以用这两个函数读写任何类型的
数据。(即这两个函数也可以用于对非二进制文件的操作,应该知道要
操作的数据的类型格式)
如果调用成功返回实际读取或输入的项的个数。
feof 函数:其功能是检测流上的文件结束符,文件结束:返回非0值,
文件未结束,返回0值 feof(fp)
(8)随机读写数据文件
a.文件位置标记的定位:
用rewind函数使文件位置标记指向文件开头
rewind(fp)(无返回值)
用fseek函数改变文件位置标记
fseek(文件类型指针,位移量,起始点) 起始点用0,1,2代替,
分别代表文件开头位置,当前位置,文件末尾位置
位移量 指以 起始点 为基点,向前移动的字节数,位移量应为
long型数据,(在数字的末尾加一个字母L)
用ftell函数测定文件位置标记的当前位置,出错时返回-1L
ftell(fp)
(9)文件读写的出错检测
ferror函数:ferror(fp)返回值为0(假)表示未出错,非零表示出错
clearerr使文件错误标志和文件结束标志置为0