C语言知识点小结

本文详细介绍了C语言的基本概念、程序结构、算法设计、数据类型、流程控制、数组、函数、指针等内容,包括变量、常量、运算符、输入输出、选择结构、循环结构的使用,以及一维和二维数组、字符数组、字符串处理、函数调用、指针操作等核心概念。此外,还探讨了动态内存分配和函数指针的应用。
摘要由CSDN通过智能技术生成

第1章 程序设计和C语言

  1. 程序:是一组计算机能识别和执行的指令。
    计算机的本质:程序的机器。
  2. 计算机语言发展历史
    机器语言(二进制指令)->汇编语言(符号代替二进制)->高级语言(源程序经过编译转换为目标程序执行)。
  3. C语言特点:
    • 用途广泛,功能强大,使用灵活的面向过程的编程语言。
    • C语言是一个很小的内核语言,不直接提供输入输出语句,文件操作语句等,这些操作由编译系统提供的库函数来实现。
    • 语言限制不严格,书写灵活,例如对数组下标越界不进行检查。
    • C语言允许直接访问物理地址,能进行位操作,可直接对硬件进行操作。
  4. C语言程序结构
    • 一个程序由一个或多个源程序文件组成。
    • 一个源程序文件包括3个部分:预处理指令,全局声明,函数定义。函数是C程序的主要组成部分
  5. 运行C程序的步骤
    源文件.c进行编译前,先对程序中的预处理指令进行预处理,(将头文件中的内容读取进来,取代预处理指令那一行)由预处理结果与其他程序组成一个完整的源程序进行编译(检查语法错误,无误后把源程序转化为二进制形式的目标程序.obj),一个源文件编译后对应一个目标文件,将一个程序中所有的目标文件和库函数连接起来后,生成一个可执行程序.exe
  6. 软件是计算机程序和程序文档的总称

第2章 算法

  1. 程序=算法+数据结构
    数据结构:对数据的描述;
    算法:对操作的描述;
  2. 传统流程图 弊端
  3. 三种基本结构
  4. N-S流程图

第3章 顺序程序设计

  1. 数据的两种表现形式:常量和变量。
  2. 区分输出"\\""//"的结果。前者输出一个\ ,后者输出//。
  3. 符号常量:用#define指令,指定用一个符号名称代表一个常量。#define PI 3.14预处理时将所有的PI 替换为3.14。符号常量不占内存,只是一个临时符号 ,预编译后就不存在了,不能对符号常量赋新值。
  4. 变量:是一个有名字的,具有特定属性的存储单元,变量名实际上是以一个名字 代表的一个存储单元。变量必须先定义后使用
  5. 常变量:定义变量时,前面加一个const关键字,表示变量存在期间其值不能改变。
  6. 区分常变量和符号常量
    eg:常变量 const double pi=3.14; 符号变量 #define PI 3.14
    #define 指令是预编译指令,仅预编译时进行一个简单的字符串替换,预编译后符号常量PI就不存在了,对符号常量是不分配存储单元的;
    而常变量要占用存储单元,有变量值,只是该值不能被改变。
  7. 标识符:用来对变量,符号常量,函数,数组,类型等命名的有效字符序列。规定标识符只能用字母数字下划线组成,且一个个字符不能为数字。标识符会区分大小写。
  8. 整型数据存储方式:整数的补码形式(整数的补码与原码相同,负数的补码是将其绝对值的二进制形式按位取反加一)。
    • int的取值范围 -(2 ^31 ) ~ ( 2 ^31)-1;unsigned int取值范围0~(2 ^32)-1。一般默认有符号
    • 只有整型(含字符型)数据可加signed或unsigned修饰符,浮点型不能加。
    • 无符号整型数据用 %u 输出
  9. 字符型数据存储方式:按其ASCII码形式存储。
    区分字符’1’和整数1:字符’1’按其对应ASCII码49存储,占1个字节;整数1按其补码形式存储,占4个字节。
  10. 浮点型数据存储方式:以指数形式存储;
  11. 运算符和表达式
    • 算术运算符中,%要求参加的运算对象是整数 ,其他不要求(整型,浮点,枚举均可)。
    • 不同类型间混合运算,会自动类型转换,小->大。当自动类型转换不能实现目的时,可使用强制类型转换,不过可能丢失精度。
  12. 数据的输入输出
    scanf("%lf%f",&a,&b);%lf表示输入的是double型数据,%f表示输入的是float型数据。变量前面要用 &
    1. 输入数值时,数据间需要用空格,tab键或回车间隔开,表示一个数值已输入完毕。但是在输入字符时,即输入字符格式为%c时,输入的数据应是连续的,不能空格,否则会将空格也作为一个字符输入。
      printf("%7.2f\n",x);%7.2f表示输出数据x的数据长度占7列,其中小数占2列,且右对齐,如果数据长度超出7列,则按原来的数据长度输出。 %f既可输出float类型,也可输出double型
    • 格式字符还有%d,%c(可以将整数按此格式输出,如果整数过大时,只输出最后一个字节),%s…
  13. 字符输入输出函数
    • putchar© 输出自变量c的值,c可以是字符常量,字符变量,整型常量,整型变量(整数不能超过0~127);也可输出转义字符。eg:putchar(‘\'’);输出一个'
    • getchar() 输入一个字符,用getchar函数得到的字符可以赋给一个字符变量或整型变量。putchar(getchar()); 将输入得到的数据输出

第4章 选择结构程序设计

  1. 两种选择语句

    • if语句 注意if else语句大括号匹配正确
    • switch语句
      • switch(表达式); 表达式的值应为整数(包括字符型);
      • 可以没有default语句,如果没有符合条件的情况时,就跳到switch语句的下一条语句;default语句可以不必写break。
      • case和default的书写顺序随便。
      • 每一个case常量必须互不相同,否则互相矛盾。
      • case标号只起标记的作用,没有条件检查判断的作用,如果没有break语句的话,则执行完某一条case语句后,会顺序执行下面的case语句,直到遇到break。
      • 可多个case标号共用一条语句,表示多种情况下执行同一条指令。
  2. 算术运算符:+ - * / %
    关系运算符:< > <= >= == !=
    逻辑运算符: && || ! 逻辑表达式的结果为“真(1)”“假(0)”,非零数值表示为“真”
    优先级顺序:!> 算术运算符 > 关系运算符 > &&,|| > 赋值运算符

第5章 循环结构程序设计

  1. 一般情况下,3种循环(while,do …while,for循环)可以互相代替。
  2. 不等价情况
    for(表达式1;表达式2;表达式3) 语句
    	
    	转换为while形式:
    	
    	表达式1;
    	while(表达式2)	
    	{
    		语句
    		表达式3
    	}
    
    当循环体内有continue时,for循环执行到continue后,后面的语句不执行,表达式3仍会执行;
    while循环执行到continue时,后面的语句,包括表达式3均不执行。
  3. for循环特点
    • 表达式1可省略,但要使程序正常运行,需要在循环前初始化循环变量
    • 表达式2可省略,无限循环
    • 表达式3可省略,需要在循环体内使变量自增或自减
    • 表达式1和3可以是几个简单的表达式,中间用逗号隔开
    • 表达式2可以是关系表达式,也可逻辑表达式,也可数值表达式或字符表达式,只要其值非0,就执行循环体
  4. break语句跳出当前循环体,只能用在3个循环语句和switch语句中。
  5. continue语句跳出本次循环

第6章 数组

一维数组
  1. 定义:int a[4]; int b[3+1]; 错误示例:int n=4; int c[n];
  2. 初始化
    • 定义时对全部元素赋初值:int a[4]={1,2,3,4};此时[ ]中的数组长度可省略
    • 定义时对部分元素赋值:int a[4]={1,2};未赋值的部分自动赋值为0(字符型数组,初始化为’\0’,指针型数组,初始化为NULL),int a[4]={};表示对全部元素赋值为0;
二维数组
  1. 定义int a[2][3];(二维数组几行几列是逻辑上的概念,内存中各元素是连续存放的,是线性的)。
  2. 初始化
    • 分行赋值int a[2][3]={{1,2,3},{4,5,6}};
    • 按内存排列顺序赋值:int a[2][3]={1,2,3,4,5,6};
    • 对部分元素赋值:int a[2][3]={{1},{4}};只对每一行第一个元素赋值;也可int a[2][3]={{1,3},{4}};
    • 如果对全部元素赋初值,定义数组的第一维的长度可以不指定,第2维长度不能省略;如果只对部分元素赋初值,但又省略了第1维的长度,应该分行赋值。
字符数组

C语言中没有字符串类型,也没有字符串变量,字符串是存放在字符型数组中的。

  1. 初始化
    • char c[10]={'I','a','w','c'};未被初始化的元素 自动设为空字符(’\0’);数组长度可省略
    • char c[ ]={"afaajoifj"};实际字符串长度为有效长度+1,因为用字符串对字符数组初始化时,会自动加一个’\0’。也可把大括号去掉,效果一样。
  2. C语言将字符串作为字符数组处理,C语言规定了字符串结束标志’\0’(‘\0’代表ASCII码为0的字符,是一个空操作符)
  3. 字符数组的输入输出:逐个字符输出用"%c",整个字符串输出"%s"。
    • 用scanf输入一个字符串时,scanf会自动在字符串后面加一个’\0’。
  4. 处理字符串的函数
    • puts(字符数组名); 将字符串输出到终端,puts输出的字符串中可以包括转义字符,同printf;用puts输出时,将结束标志’\0’转换为’\n’,即输出完字符后换行。参数也可为字符串
    • gets(字符数组名); 从终端输入一个字符串到字符数组,并得到一个函数值,该函数值是字符数组的起始地址。参数也可为字符串
    • puts和gets函数只能输出或输入一个字符串,即只能有一个参数
    • strcat(字符数组1,字符数组2); 连接字符串:把字符数组2接到字符数组1的后面(字符数组1的长度必须足够长),返回字符数组1的地址。参数2可为字符串,但参数1不行
    • strcpy(字符数组1,字符串2); 将字符串2复制到字符数组1中,连同’\0’也一起过去同strcat,参数1必须是字符数组名,参数2可字符串也可字符数组
    • strncpy(字符数组1,字符数组2,n); 将参数2的前n个字符复制到参数1中去。
    • strcmp(字符串1,字符串2); 比较字符串(将两个字符串从左到右逐个字符按照ASCII码大小相比较,直到出现不同的字符或遇到’\0’,若相同返回0,若参数1>参数2,返回一个正整数,若<,返回一个负整数)。
    • strlen(字符数组名); 测字符串长度,不包括’\0’在内
    • strlwr(字符数组名); 转化为小写的 ;strupr(字符数组名); 转化为大写
  5. 不要忘记 #include<string.h>

第7章 函数

  1. 函数调用时,实参和形参之间可自动类型转换。
  2. 形参在函数被调用时才被临时分配内存空间,调用结束,形参被释放
  3. 执行被调用函数时,形参的值发生改变,并不能影响实参的值,因为他们之间是值传递,值传递是单向传递,他们在内存中占用的是不同的存储单元
  4. 当被调函数写在main函数之后时,须在main函数中先写函数声明,才可以调用,函数声明的参数个数和参数类型必须与被调函数一致,参数名可不写或写成不一样的。
函数的递归调用
  1. 求n!
int fac(int n)
{
	int f;
	if(n<0)
		printf("n<0,data error");
	else if(n==0||n==1)     //0和1的阶乘是1
		f=1;
	else  f=fac(n-1)*n;
	return f;
}
  1. 汉诺塔问题
hanoi(m,'A','B','C');

void hanoi(int n,char  one ,char two,char three)   //将n个盘从one座移到three座,借助two座
{
	void move(char x,char y);
	if(n==1)
		move(one,three);
	else
	{
		hanoi(n-1,one,three,two);
		move(one,three);
		hanoi(n-1,two,one,three);
	}
}

void move(char x,char y)
{
	printf("%c->%c\n",x,y);
}
数组元素做函数参数
  1. 不能做形参, 因为形参是在函数被调用时,临时分配存储单元的,而数组是一个整体,不可能为数组元素单独再分配空间。
  2. 数组元素做形参是值传递,数组名做形参传的是数组首元素地址
  3. 数组名做形参时,数组大小没有任何意义,可接受任意长度的数组,形参数组和实参数组指的是同一个地址
  4. 编译时,系统把形参数组float array[]转换为指针变量float * array
变量的作用域:局部变量和全局变量

不同函数中可以定义同名的变量,因为他们在内存中占不同的存储单元,不会混淆

变量的生存期
  1. 对静态局部变量是编译时赋初值,所以每次调用时都保留了上次函数调用时的值。
  2. 在定义局部变量时不赋初值的话,对于静态局部变量,自动赋值为0,或’\0’;对于自动变量,值是不可知的。
  3. 静态局部变量在生存期同全局变量一样,但作用域同局部变量一样。
  4. 外部变量声明 extern extern可扩展变量的作用域,也可用于扩展函数的作用域,扩展函数作用域时,可不写extern关键字,即可直接声明。
  5. static声明局部变量和全局变量的区别:static修饰局部变量是将局部变量的生存期扩大到整个程序,存储在静态存储区中;static修饰全局变量时,是将全局变量的作用域限制在了本文件中,其他文件不可通过extern来扩展。
  6. 区分声明和定义:需要建立存储空间的称为定义 ,int a; 不需要建立存储空间的称为声明,extern a; 外部变量的定义只有一次(在所有函数之外),但可对同一外部变量多次声明(函数内外都可)。
  7. 内部外部函数;根据函数能否被其他源文件调用划分。内部函数又叫静态函数,前面用static修饰。
  8. extern的使用所有函数前面都默认有一个extern(可省略不写),表示可被其他文件引用,若不想的话,加static;在其他文件中引用这个函数时,需要在函数声明前面加一个extern(也可省略)。所以在本文件还是其他文件中引用函数时都一样,声明即可。

第8章 指针

  1. 指针即地址,C语言中地址包括位置信息和所指向数据的类型信息,是“带类型的地址”。
  2. 数据的直接访问和间接访问printf("%d\n",i);
    • 直接访问:从变量名与地址对应表中,根据变量名找到地址,再按照其类型读出i,再按十进制格式输出
    • 间接访问:将变量i的地址存放在另一变量中,然后根据该变量找到i的地址,从而访问i。&i_pointer=&i;此时 &pointer就是一个指针变量,专门用来存放地址。
  3. 表示指针地址:指向整型数据的指针类型表示为int *,简称int指针
通过指针引用数组
  1. 指针指向一个数组元素时,允许对指针进行加减运算:+,-,+=,-=,p++,p–,p1-p2(只有p1和p2均指向同一数组时有意义。)
  2. p+1是指向该数组中下一个元素,不是将p的值+1,而是加上一个数组元素所占用的字节数
  3. 引用数组中各元素的值3种方法:
    • 下标法,如a[3]
    • 通过数组名引用,如*(a+3) a的值是不会变的,a是指针型常量
    • 用指针变量指向数组元素,如 int * p=a; *(p+3)
  4. 如果给指针变量p加下标,如p[2],代表的是p指向的当前值的下两个元素
  5. 区分 p++; *p;*p++ :前者是先将p自增指向下一个元素,再引用该元素;后者是先引用当前元素,即先执行*p,再使p++,注意不是引用的元素自增,而是使指针变量p自增
  6. 用数组名做函数参数:实参数组名代表该数组首元素的地址,所以形参数组应定义为指针变量,用来接收地址;形参数组各元素值发生变化,实参也随之改变。但实参数组名是指针常量,形参数组名是指针变量。
  7. a[i]与*(a+i)无条件等价
  8. 要想在函数调用中修改数组中元素的值,数组名与指针变量都既可做形参,也可做实参。如果用指针变量做实参,则必须先将指针变量指向一个已定义的对象。
通过指针引用多维数组
  1. 二维数组指针在不同位置上的含义
  2. a+i和&a[i]等价,指向行,基类型是一维数组;a[i]和*(a+i)等价,指向列,基类型是元素类型
  3. 区别 int * p[4]和 int (* p)[4]: 前者表示定义了一个基类型为int的指针数组,长度为4,p是数组名;后者表示定义了一个指针变量p指向长度为4的int型的一维数组。
  4. 实参与形参如果是指针类型,应当注意他们的基类型必须一致
通过指针引用字符串
  1. 引用字符串方法:
    • 将字符串存放在字符数组中,可通过 %s%c分别输出字符串或其中某个字符
    • 用字符指针变量指向一个字符串常量(该字符串常量依然是放在一个字符数组中的,只不过没有名字,只能通过指针来访问)
  2. 用指针变量指向字符串时,可以先定义,再赋值,还可对指针变量进行再次赋值,但是不可对指针指向的字符串常量进行修改;字符数组则不行,因为字符数组名是常量,不可修改,字符数组中的某一元素可被修改。
程序改进

要求:指针变量from指向字符数组a,指针变量to指向字符数组b,将a的内容复制到b中。程序设计如下:

void copyString(char * from,char * to)
{
   for(;*from!='\0';from++,to++)
   {
   	*to=*from;
   }
   *to='\0';
}

改进一:将赋值语句与循环条件合并
void copyString(char * from,char * to)
{
   while((*to=*from)!='\0')    //先赋值后判断,所以不需要再补充*to='\0';了
   {
   	from++;to++;
   }
}

改进二:将自增语句再与他们合并
void copyString(char * from,char * to)
{
   while((*to++=*from++)!='\0') ;    //where后面不需要大括号了,直接分号
}

改进三:字符'\0'可用其对应ASCII码0来代替,所以*from!='\0' 等价于 *from!=0 等价于 *from (非零数值表示为真)
void copyString(char * from,char * to)
{
   while(*to++=*from++') ;    
}
也可用for循环:for(;*to++=*from++;);
指向函数的指针
  1. 函数名代表函数的起始地址,定义一个函数 int max(int a,int b);
  2. 定义指向函数的指针变量 int (*p) (int ,int ); 将指针变量指向函数:p=max; 调用函数c=(*p)(a,b); 等价于 c=max(a,b);
  3. 指向函数的指针变量的一个重要用途:将函数入口地址作为参数传递到其他函数中,这样就可以在其他函数中调用该函数了。当其他函数内部每次需要调用不同的函数时,用这种方法就比较方便
  4. 区别:返回值为指针的函数 :int * max(int a,int b); 返回值为 int *类型的max函数
  1. 指针数组 int * p[4];数组p是指针类型,每一个元素都是指针,指向一个int型的数据
  2. 指向一维数组的指针变量 int (*p) [4];指针变量p指向int型的长度为4的一维数组
  3. 指向指针数据的指针变量 int * * p;p是一个指针变量,这个指针变量又指向一个int型的数据
动态内存分配与指向它的指针变量
  1. 对内存的动态分配通过系统提供的库函数来实现,有malloc,calloc,free,realloc4个。
  • 开辟动态存储区
    1. void * malloc(unsigned int size); 在动态存储区分配一个长度为size的连续空间;unsigned int表示无符号整型,不能为负数。p=malloc(100);
    2. void * calloc(unsigned n,unsigned size); 分配n个长度为size的连续空间
  • 重新分配动态存储区。p=calloc(4,100);
    1. void * realloc(void * p,unsigned int size); 已经通过malloc或者calloc分配动态存储区后,需要改变其大小,用realloc重新分配。在原来的空间上修改其长度,空间的首地址不变。realloc(p,50);
  • 释放动态存储区
    1. void free(void * p); 释放指针p所指向的动态空间。free(p);
  1. 这4个函数声明在stdlib.h头文件中。
指针小结

指针小结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值