C语言基础知识


前言

C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。


一、常量、变量和数据类型

标识符

  1. 标识符的命名规则
    ①只能由字母、数字或下划线组成。
    ②第1个字符必须是字母或下划线,不能是数字。
    ③区分字母的大小写。

  2. 标识符的分类
    C语言的标识符可以分为3类。
    ①关键字:C语言规定专用的标识符,它们有着固定的含义,不能更改。
    ②预定义标识符:在C语言中预先定义并具有特定含义的标识符。允许把这样的标识符重新定义,但建议不要这样做。
    ③用户标识符:由用户根据需要定义的标识符。

命名应注意做到“见名知义”。
不能与关键字同名。

常量

定义:在程序运行中,其值不能被改变的量。
常量的类型:整型常量、实型常量、字符常量、字符串常量及符号常量。

  1. 整型常量
    ①表示形式:十进制整型常量、八进制整型常量和十六进制整型常量。
    ②书写形式
    十进制整型常量:基本数字范围为0~9。
    八进制整型常量:以0开头,基本数字范围为0~7。
    十六进制整型常量:以0x开头,基本数字范围为0~15,其中10~15写为A~F或a~f。

  2. 实型常量
    ①表示形式:小数形式和指数形式。
    ②书写形式:十进制小数形式。
    ③指数形式:e前必须有数字,e后必须为整数。

  3. 字符常量
    一个字符常量代表ASCII字符集里的一个符,在程序中用单撇号()标识,区
    转义字符以“\”开头,后面跟同的意思。
    \n:换行的意思。
    \\:反斜杠字符“\”。
    \ddd:1~3位八进制数所代表的一个ASCII字符。
    \xhh:1~2位十六进制数所代表的一个ASCII字符。

  4. 字符串常量
    字符串常量是用双撇号(” ”)标识的一个或一串字符。

  5. 符号常量
    符号常量是由预处理命令“#define”定义的常量,在C程序中可用标识符代表一个常量。

变量

定义:值可以改变的量。
变量要有变量名,在使用前必须先定义。
在内存中占据一定的存储单元,不同类型的变量占据的存储单元大小不同。
存储单元里存放的是该变量的值。
变量的类型:整型变量、实型变量、字符变量。

  1. 整型变量
    ①分类:基本型(int)、短整型(short int或short)、长整型(long int 或long)和无符号型(unsigned int、unsigned short、unsigned long)。
    ②数值范围:
    整型[signed]int,占16位;
    短整型[signed]short[int],占16位;
    长整型[signed]long[int],占32位;
    无符号整型unsigned[int],占16位;
    无符号短整型unsigned short[int],占16位;
    无符号长整型unsigned long[int],占32位。

  2. 实型变量
    ①分类:单精度类型(float)和双精度类型(double)。
    ②定义方法:

float a;
double m;

③所占字节:float型在内存中占4字节(32位),double型占8字节(64位)。单精度实数提供7位有效数字,双精度实数提供15~16位有效数字。
④实型常量:不分float型和double型,一个实型
常量可以赋给一个float型或double型变量,但变量
根据其自身类型截取实型常量中相应的有效数字。

  1. 字符变量
    ①作用:用来存放字符常量。
    ②定义:用关键字char定义,每个字符变量中只
    能存放一个字符。
    ③定义形式:
char crl,cr2;

④赋值:

crl='m';
cr2='n';

⑤存储方法:存储字符对应的ASCII到内存单元中。

字符型数据与整型数据之间可以通用,一个字符能用字符的形式输出,也能用整数的形式输出。

字符型数据进行算术运算,相当于对它们的ASCII进行运算。


表中列出了ANSI C提供的各种基本类型及其相应的类型说明符和每种类型的数据在内存
中所占的字节数,列出了ANSI C中无值、指针及构造数据类型。表中的类型说明符由“[类型修饰符][类型标识符]”构成,“[ ]”表示该项关键字可以省略,但类型修饰符和类型标识符不能同时省略。具体规则如表中所示。例如“signed int”和“int”、“unsigned int”和“unsigned”
含义一样。

类型的自动转换和强制转换

  1. 类型的自动转换。
    ①当同一表达式中各数据的类型不同时,编译程序会自动把它们转变成同一类型后再进行计算。
    ②转换优先级为char<int<float<double,左边的类型向右边转换。
    ③当做赋值运算时,若赋值运算符左右两边的类型不同,则赋值运算符右边的类型向左边的类型转换;若右边的类型高于左边的类型,则在转换时对右边的数据进行截取。
  2. 类型的强制转换
    表示形式:(类型)(表达式);。

二、运算符

在讲解具体运算符之前,介绍几个与之相关的术语:操作数(operand)、运算符(operator)、左值(lvalue)和右值(rvalue)。

操作数(operand)是程序操纵的数据实体,该数据可以是数值、逻辑值或其他类型。该操作数既可以是常量也可以为变量。例如:

int a=3;
int b=a+2;

加运算符 ‘+’,取出变量 a 中的值 3,与常量 2 相加,并把求和表达式 a+2 的结果 5 保存到变量 b 中。

运算符(operator)是可以对数据进行相应操作的符号。如对数据求和操作,用加法运算符 ‘+’,求积操作使用乘法运算符 ‘*’ 等。

根据运算符可操作的操作数的个数,可把运算符分为一元运算符、二元运算符和多元运算符(一般三元)。

C 语言提供了丰富的运算符,有:算术运算符、关系运算符、逻辑运算符、赋值运算符、移位运算符、逗号运算符及 sizeof 运算符。对应有:算术表达式、关系表达式、逻辑表达式、赋值表达式、移位表达式、逗号表达式及 sizeof 表达式等。

运算符

  1. 算术运算符
    用于各类数值运算。包括加(+)、减(-)、乘(*)、除(/)、求余(或称模运算,%)、自增(++)、自减(–)共七种。
  2. 关系运算符
    用于比较运算。包括大于(>)、小于(<)、等于(==)、 大于等于(>=)、小于等于(<=)和不等于(!=)六种。
  3. 逻辑运算符
    用于逻辑运算。包括与(&&)、或(||)、非(!)三种。
  4. 位操作运算符
    参与运算的量,按二进制位进行运算。包括位与(&)、位或(|)、位非(~)、位异或(^)、左移(<<)、右移(>>)六种。
  5. 赋值运算符
    用于赋值运算,分为简单赋值(=)、复合算术赋值(+=,-=,*=,/=,%=)和复合位运算赋值(&=,|=,^=,>>=,<<=)三类共十一种。
  6. 条件运算符
    这是一个三目运算符,用于条件求值( ? : )。
  7. 逗号运算符
    用于把若干表达式组合成一个表达式(,)。
  8. 指针运算符
    用于取内容(*)和取地址(&)二种运算。
  9. 求字节数运算符
    用于计算数据类型所占的字节数(sizeof)。
  10. 特殊运算符
    有括号(),下标[],成员(→,.)等几种。

运算符号的优先级

  1. 优先级1级
    结合方向 左结合(自左至右

( ) 圆括号
[ ] 下标运算符
-> 指向结构体成员运算符
. 结构体成员运算符(请注意它是一个实心圆点)

  1. 优先级2级
    结合方向 右结合(自右至左)单目运算符

~ 按位取反运算符
! 逻辑非运算符
++ 自增运算符
--自减运算符
-负号运算符
(类型) 类型转换运算符
*指针运算符
& 地址与运算符
sizeof 长度运算符

  1. 优先级3级
    结合方向 左结合 双目运算符

/ 除法运算符
*乘法运算符
% 取余运算符

  1. 优先级4级
    结合方向 左结合 双目运算符

+加法运算符
-减法运算符

  1. 优先级5级
    结合方向 左结合 双目运算符

<< 左移运算符
>>右移运算符

  1. 优先级6级
    结合方向 左结合 双目运算符

>、 <、<=、>、>= 关系运算符

  1. 优先级7级
    结合方向 左结合 双目运算符

== 等于运算符 (判断)
!= 不等于运算符(判断)

  1. 优先级8级
    结合方向 左结合 双目运算符

& 按位与运算符

  1. 优先级9级
    结合方向 左结合 双目运算符

^ 按位异或运算符

  1. 优先级10级
    结合方向 左结合 双目运算符

| 按位或运算符
举例:0xfe|0xef 即为1111 1110 与1110 1111按位或运算则答案为:1111 1111 即0xff。

  1. 优先级11级
    结合方向 左结合 双目运算符

&& 逻辑与运算符

  1. 优先级12级
    结合方向 左结合 双目运算符

|| 逻辑或运算符

  1. 优先级13级
    结合方向 右结合 三目运算符

? : 条件运算符

  1. 优先级14级
    结合方向 右结合 双目运算符

= 赋值运算符
+= 加后赋值运算符 如s+=1表示s=s+1
-= 减后赋值运算符 如s-=1表示s=s-1
*= 乘后赋值运算符
/= 除后赋值运算符
%= 取模后赋值运算符
<<= 左移后赋值运算符
>>=右移后赋值运算符
&= 按位与后赋值运算符
^=按位异或后赋值运算符
|= 按位或后赋值运算符

  1. 优先级15级
    结合方向 左结合

逗号运算符

三、表达式

表达式是由运算符和运算对象组成的。最简单的表达式是一个单独的运算对象。C表达式的一个最重要特性就是,每个表达式都有一个值。

四、基本语句

1.语句时C程序的基本构建块。一条语句相当于一条完整的计算机指令。在C中,大部分语句以分号结尾。最简单的语句是空语句,即只有一个分号。C把末尾上加上一个分号的表达式都看作是一条语句,所以8;4+3;类似这样写也是可以的。虽然一条有用的语句相当于一条完整的指令,但并不是所有的指令都是语句,如:x = 6 + (y = 5);此处的y = 5便是一条完整的指令,但是它只是语句的一部分。

2.复合语句:用花括号括起来的一条或多条语句,复合语句也称为块。
请看下面程序段:

while (index++ < 10)
{
    sam = 10 * index + 2;
    printf("%d\n",sam);
}

五、循环

while循环

while循环的一般形式为:

while(表达式){
    语句块
}

意思是,先计算“表达式”的值,当值为真(非0)时, 执行“语句块”;执行完“语句块”,再次计算表达式的值,如果为真,继续执行“语句块”……这个过程会一直重复,直到表达式的值为假(0),就退出循环,执行 while 后面的代码。

我们通常将“表达式”称为循环条件,把“语句块”称为循环体,整个循环的过程就是不停判断循环条件、并执行循环体代码的过程。

用 while 循环计算1加到100的值:

#include <stdio.h>
int main()
{
    int i=1, sum=0;
    while(i<=100)
    {
        sum+=i;
        i++;
    }
    printf("%d\n",sum);
    return 0;
}

运行结果: 5050

代码分析:

  1. 程序运行到 while 时,因为 i=1,i<=100 成立,所以会执行循环体;执行结束后 i 的值变为 2,sum 的值变为 1。

  2. 接下来会继续判断 i<=100是否成立,因为此时 i=2,i<=100 成立,所以继续执行循环体;执行结束后 i 的值变为 3,sum 的值变为3。

  3. 重复执行步骤 2。

  4. 当循环进行到第100次,i 的值变为 101,sum 的值变为5050;因为此时 i<=100 不再成立,所以就退出循环,不再执行循环体,转而执行while循环后面的代码。

while 循环的整体思路是这样的:设置一个带有变量的循环条件,也即一个带有变量的表达式;在循环体中额外添加一条语句,让它能够改变循环条件中变量的值。这样,随着循环的不断执行,循环条件中变量的值也会不断变化,终有一个时刻,循环条件不再成立,整个循环就结束了。

如果循环条件中不包含变量,会发生什么情况呢?

1.循环条件成立时的话,while 循环会一直执行下去,永不结束,成为“死循环”。例如:

#include <stdio.h>
int main(){
    while(1){
        printf("1");
    }
    return 0;
}

运行程序,会不停地输出“1”,直到用户强制关闭。

2.循环条件不成立的话,while 循环就一次也不会执行。例如:

#include <stdio.h>
int main(){
    while(0){
        printf("1");
    }
    return 0;
}

运行程序,什么也不会输出。

do-while循环

除了while循环,在C语言中还有一种 do-while 循环。

do-while循环的一般形式为:

do{
    语句块
}while(表达式);

do-while循环与while循环的不同在于:它会先执行“语句块”,然后再判断表达式是否为真,如果为真则继续循环;如果为假,则终止循环。因此,do-while 循环至少要执行一次“语句块”。

用do-while计算1加到100的值:

#include <stdio.h>
int main(){
    int i=1, sum=0;
    do{
        sum+=i;
        i++;
    }while(i<=100);
    printf("%d\n", sum);
    return 0;
}

运行结果: 5050

注意while(i<=100);最后的分号;,这个必须要有。
while循环和do-while各有特点,可以适当选择,实际编程中使用while循环较多。

for循环

c语言中for循环一般形式:

for(表达式1;表达式2;表达式3)
{
执行代码块;
}

它的执行过程如下:

执行表达式1,对循环变量做初始化;
判断表达式2,若其值为真(非0),则执行for循环体中执行代码块,然后向下执行;若其值为假(0),则结束循环;
执行表达式3,(i++)等对于循环变量进行操作的语句;
执行for循环中执行代码块后执行第二步;第一步初始化只会执行一次;
循环结束,程序继续向下执行。

注意:for循环中的两个分号一定要写

六、分支和跳转

1.简单if语句
C语言中的分支结构语句中的if条件语句。
简单if语句的基本结构如下:

if(表达式)
{
执行代码块;
}

其语义是:如果表达式的值为真,则执行其后的语句,否则不执行该语句。

注意:if()后面没有分号,直接写{}

2.简单if-else语句
简单的if-else语句的基本结构:

if(表达式)
{
执行代码块1;
}
else
{
执行代码块2;
}

语义是: 如果表达式的值为真,则执行代码块1,否则执行代码块2。

注意:if()后面没有分号,直接写{},else后面也没有分号,直接写{}

3.多重if-else语句
C语言中多重if-else语句,其结构如下:

if(表达式1)
{
执行代码块1;
}
......
else if(表达式m)
{
执行代码块m;
}
.......
else
{
执行代码块n;
}

语义是:依次判断表达式的值,当出现某个值为真时,则执行对应代码块,否则执行代码块n。

注意:当某一条件为真的时候,则不会向下执行该分支结构的其他语句。

七、数组

一维数组的定义和引用

1.一维数组的定义
一维数组是指数组中的每个元素只带有一个下标的数组。一般形式:

类型说明符数组名[常量表达式];

2 一维数组元素的引用
数组元素的引用形式:

数组名[下标表达式];

①一个数组元素实质上是一个变量名,代表内存中的一个存储单元,一个数组占据的是一连串连续的存储单元。
②引用数组元素时,数组的下标可以是整型常量,也可以是整型表达式。
③数组必须先定义后使用。
④只能逐个引用数组元素而不能一次引用整个数组。

3 一维数组的初始化
当数组定义后,系统会为该数组在内存中开辟一串连续的存储单元,但这些存储单元中并没有确定的值。可以在定义数组时为所包含的数组元素赋初值,例如:

int a[6]=|0,1,2,3,4,5;

①所赋初值放在一对花括号中,数据类型必须与所定义类型一致。
②所赋初值之间用逗号隔开,系统将按这些数值的排列顺序,从a[0]元素开始依次给数组a中的元素赋初值。
③不能跳过前面的元素给后面的元素赋初值,但是允许将前面元素赋值为0。
④当所赋初值个数少于所定义数组的元素个数时,将自动给后面的其他元素补初值0。
⑤可以通过赋初值来定义一维数组的大小,定义数组时方括号中可以不指定数组的大小。

二维数组的定义和引用

1.二维数组的定义
①在C语言中,二维数组中元素排列的顺序是按行存放,即在内存中先顺序存放第1行的元素,再
存放第2行的元素。二维数组元素的存储总是占用一块连续的内存单元。
②一般形式。

类型说明符数组名[常量表达式1][常量表达式2];

2.二维数组元素的引用
数组元素的引用形式:

数组名[下标表达式1][下标表达式2];

①数组的下标可以是整型表达式。
②数组元素可以出现在表达式中,也可以被赋值。

3.二维数组的初始化
①可以在定义二维数组的同时给二维数组的各元素赋初值。
②全部初值放在一对花括号中,每一行的初值又分别标识在一对花括号中,之间用逗号隔开。
③当某行一对花括号内的初值个数少于该行中元素的个数时,系统将自动地给后面的元素赋初值0。
④不能跳过每行前面的元素而给后面的元素赋初值。

4.通过赋初值定义二维数组的大小
对于一维数组,可以在数组定义语句中省略方
括号中的常量表达式,通过所赋初值的个数来确定
数组的大小;对于二维数组,只可以省略第1个方括
号中的常量表达式,而不能省略第2个方括号中的
常量表达式。

字符数组

1.字符数组的定义
字符数组就是数组中的每个元素都是字符。定义方法同普通数组的定义方法相同,即逐个对数组元素赋值。

2.字符数组的初始化及引用
①初始化:对字符数组初始化,可逐个元素地
赋值,即把字符逐个赋给数组元素。

如果花括号中提供的初值个数(即字符个数)大于数组长度,则编译时会按语法错误处理。
如果初值个数小于数组长度,则将这些字符赋给数组中前面那些元素,其余的元素赋值为空字符(`\0`)。

②引用形式:
采用下标引用,即

数组名[下标];

3.字符串和字符串结束标志
C语言中,将字符串作为字符数组来处理。为了测定字符串的实际长度,C语言规定了一个字符串结束标志,即字符\0’。也就是说,遇到字符\0',表示字符串结束,由它前面的字符组成字符串。

4.字符数组的输入/输出
字符数组的输入/输出有以下两种方法。
①用“%c”格式符,将字符逐个输入或输出。
②用“%s”格式符,将整个字符串一次输入或输出。

5.字符串处理函数
C语言没有提供对字符串进行整体操作的运算
符,但在C语言的函数库中提供了一些用来处理字
符串的函数。在调用这些函数前,须在程序前面的命令行中包含标准头文件“string.h”。

  • puts():调用形式为puts(字符数组),将_个
    字符串(以\0结束)输出到终端设备。
  • gets():调用形式为gets(字符数组),从终端输
    入一个字符串到字符数组中,并且得到一个函数值。
  • strcpy():调用形式为strcpy(字符数组1,字符 数组2),把字符数组2所指字符串的内容复制到字符
    数组1所指存储空间中。函数返回字符数组1的值,
    即目标字符串的首地址。
  • strcat():调用形式为strcat(字符数组1,字符 数组2),该函数将字符数组2所指字符串的内容连
    接到字符数组1所指的字符串后面,并自动覆盖字
    符数组1字符串末尾的\0。该函数返回字符数组1
    的地址值。
  • strlen():调用形式为strlen(字符数组),此函
    数计算出以“字符数组”为起始地址的字符串的长度,
    并将其作为函数值返回。
  • stremp():调用形式为stremp(字符数组1,字 符数组2),该函数用来比较字符数组1和字符数组2所些宝符出的大小。若字符数组1大于字符数组2,则函数值大于0(正数);若字符数组1等于字符数组2,则函数值等于0;若字符数组1小于字符数组2,则函数值小于0(负数)。

八、函数

函数概述

在C语言中,子程序的作用是由函数实现的。一个C程序可由一个主函数和若干个其他函数构成,且只能有一个主函数。由主函数来调用其他函数,其他子函数之间也可以互相调用。

C程序的执行总是从main()函数开始。调用其他函数完毕后,程序流程回到main()函数,继续执行主函数中的其他语句,直到main()函数结束,则整个程序的运行结束。

从用户使用的角度看,函数分类如下:

标准函数,即库函数。这些函数由系统提供,可以直接使用。
自定义的函数,用于解决用户需要时设计并定义的函数。

从函数的形式看,函数分为无参函数和有参函数。

函数参数和函数返回值

1.形式参数和实际参数
①当定义函数时,函数名后面圆括号中的变量称为“形式参数”(简称“形参”)。
②在主调函数中,函数名后面圆括号中的参数(可以是一个表达式)称为“实际参数”(简称“实参”)。

2.函数的返回值
①定义:函数的返回值就是通过函数调用使主
调函数得到一个确定的值。
②表达形式:
return表达式;
或者return(表达式);
或者return;
③return语句中的表达式值的类型必须与函数首部所说明的类型一致。若类型不一致,则以函数值的类型为准,由系统自动进行强制转换。
④当函数没有指明返回值,或没有返回语句时,函数返回一个不确定的值。为了使函数不返回任何值,可以使用void定义无类型函数。

函数的调用

1.函数调用的一般形式

函数名(实参列表);

函数的调用可分为调用无参函数和调用有参函数两种。
①调用无参函数,不用“实参列表”,但圆括号不能省略。
②调用有参函数时,若实参列表中有多个实参,则各参数间用逗号隔开。实参与形参要求类型一致。

2.函数的说明
C语言中,除了主函数外,对于用户定义的函数要遵循先定义后使用的规则。若把函数的定义放在调用之后,则应该在调用之前对函数进行说明(或函数原型说明)。
函数说明的一般形式:

类型名 函数名(参数类型1,参数类型2,…,参数类型n);

或者

类型名 函数名(参数类型1 参数名1,参数类型2 参数名2,......,参数类型n 参数名n);

函数的嵌套调用与递归调用

1.函数的嵌套调用
C语言函数定义都是独立的、互相平行的,C语句不允许嵌套定义函数。即一个函数内不能定义另一个函数,但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数。

2.函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身的,称为函数的递归调用。使用递归法解决问题,需符合的条件如下。
①可以把要解决的问题转化为一个新的问题。而这个新的问题的解决方法仍与原来问题的解决方法相同,只是所处理的对象有规律地递增或递减。
②可以应用这个转化过程使问题得到解决。
③必须有一个明确的结束递归的条件。

数组元素和数组名作为函数实参

1.数组元素作为函数实参
数组元素可以作为函数实参,与变量作为实参一样,按照单向值传递的方式传递。

2.数组名作为函数实参
可以用数组名作为函数实参。此时函数的形参是与数组类型一致的指针变量,这里的数组名是整个数组的首地址。

全局变量和局部变量

1.在函数内部定义的变量称为局部变量,只能在本函数内部使用。

2.在函数外部定义的变量称为外部变量,外部变量是全局变量。全局变量可以为本文件中其他函数所共用,它的有效范围从定义变量开始到本文件结束。
3.如果在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用。

变量的存储类别

1.auto变量
当在函数内部或复合语句内定义变量时,如果没有指定存储类别,或使用了auto说明符,系统就认为所定义的变量具有自动类别。
2.register变量
register变量也是自动类变量。它与auto变量的区别仅在于:用register说明变量是建议编译程序将变量的值保留在CPU的寄存器中,而不是像一般变量那样占用内存单元。
3.静态存储类别的局部变量
当函数体(或复合语句)内部用static来说明一个变量时,可以称该变量为静态局部变量。它与auto变量、register变量的本质区别如下:

  • 在整个程序运行期间,静态局部变量在内存中的静态存储区中占据永久性的存储单元。即使退出函数,下次再进入该函数时,静态局部变量仍使用原来的存储单元。由于不释放这些存储单元,这些存储单元中的值得以保留,因此可以继续使用存储单元中原来的值。
  • 静态局部变量的初值是在编译时赋予的,在程序执行期间不再赋以初值。对未赋值的局部变量,C语言编译程序自动给它赋初值0。

九、指针

地址和指针

在C语言中,将地址形象地称为“指针”。一个变量的地址称为变量的指针。用来存放另一个变量的地址的变量(即指针),称为指针变量。

变量的指针和指问变量地址的指针变量

1.指针变量的定义
定义指针变量的一般形式:

类型名 *指针变量名1,指针变量名2,...;

例如:

int *p,*t;

2.指针变量的引用
指针变量中只能存放地址(指针),与指针相关的两个运算符是“&”(取地址运算)和“*”(指针运算符)。

3.指针变量作为函数参数

指针类型数据可以作为函数参数来进行传递。

作用:将一个变量的地址传送到另一个函数中,参与该函数的运算。

数组与指针

1.指向数组元素的指针
C语言规定数组名代表数组的首地址,也就是数组中第0号元素的地址。

定义指向数组元素的指针变量的方法,与定义指向变量的指针变量相同。

2.通过指针引用数组元素
如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。

3.数组名作为函数实参
①当数组名作为参数被传递时,若形参数组中各元素发生了变化,则原实参数组各元素的值也随之变化。
②如果用数组元素作为实参,情况就与变量作为实参时一样,是“值传递”方式。

4.指向多维数组的指针和指针变量
多维数组可以看作一维数组的延伸,多维数组的内存单元也是连续的内存单元。C语言实际上是把多维数组当成一维数组来处理的。

字符串与指针

1.字符串的表示形式
①用字符数组存放一个字符串,然后输出该字符串。
②用字符指针指向一个字符串。用字符指针指向字符串中的字符。

2.字符串指针作为函数参数
将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法,即用字符数组名作为参数或用指向字符串的指针变量作为参数,进行传递。

3.字符数组和字符指针变量的区别

  • 字符数组由若干个元素组成,每个元素中存放一个字符,而字符指针变量中存放的是地址,不是将字符串的内容存放到字符指针变量中。
  • 赋值方式不同。字符数组可以在定义时对其整体赋初值,但在赋值语句中不能完成整体赋值。而字符指针变量既可以在定义时赋初值,也可以在赋值语句中赋初值。
  • 编译时不同。
  • 在程序中指针变量的值可以改变。而数组名虽然代表了地址,但它的值是一个固定的值,不能改变。

指向函数的指针

指针变量可以指向一个函数,编译时,一个函数将被分配给一个入口地址,这个入口地址就称为该函数的指针。因此,可以通过使用一个指向函数的指针变量调用此函数。
说明:
①指向函数的指针变量的一般定义形式如下。

数据类型(*指针变量名)();

②当给函数指针变量赋值时,只需给出函数名而不必给出参数。
③当用函数指针变量调用函数时,只需将(*s)代替函数名即可(s为已经定义过的指向函数的指针变量名),在(*s)之后的圆括号中根据需要写上实参。
④对指向函数的指针变量,有些运算如++s--ss++等都是没有意义的。

指针数组和指向指针的指针

1.指针数组的概念
若在一个数组中,其元素均为指针类型数据,这样的数组称为指针数组。
定义一维指针数组的一般形式:

类型名 *数组名[数组长度];

2.指向指针的指针
指向指针数据的指针变量,简称为指向指针的指针,通常称为二级指针。
定义一个指向指针数据的指针变量的一般形式:

类型名 **指针变量名;

十、结构体和共用体

用typedef说明一种新类型

1.一般形式。

typedef 类型名 标识符;

其中,“类型名”一定是在此语句之前已有定义的类型标识符。“标识符”是一个由用户定义的标识符,用来标识新的类型名。

2.typedef 语句的作用:用标识符来代表已存在的类型名,并没有产生新的数据类型,因此,原有的类型名依然有效。

3.声明一个新的类型名的具体步骤如下。
①按定义变量的方法写出定义的主体(如float a;)。
②将变量名换成新类型名(如将a换成FLO)。
③在最左侧加上关键字typedef(如typedef float FLO;)。
④用新类型名去定义其他的变量(如FLO b;)。

结构体数据类型

1.声明一个结构体类型的一般形式如下。

struct 结构体名{成员列表};

2.结构体类型可以用以下形式说明。

struct 结构体 标识名
{
类型名1结构体成员名表1;
类型名2结构体成员名表2;
...
类型名n结构体成员名表n;
};

说明:

  • “结构体标识名”和“结构体成员名表”都必须是合法的用户定义的标识符。
  • 每个结构体成员名表中都可以含有同类型的成员名,它们之间以逗号分隔。
  • 结构体类型说明中的“类型名1”~“类型名n”,不仅可以是简单数据类型,也可以是某种结构体类型。当结构体说明中又包含结构体时,称为结构体的嵌套。

结构体类型变量的定义

1.先声明结构体类型再定义变量名
例如,已经定义了一个结构体类型struct time,则

 struct time      time 1, time 2;
//结构体类型名     结构体变量名;

time 1time 2struct time 类型变量,即它们都具有struct time类型的结构。

2.在声明类型的同时定义变量
一般形式:

struct 结构体名 {成员列表} 变量名列表;

3.直接定义结构体类型变量
一般形式:

struct {成员列表} 变量名列表;

即不出现结构体名。

结构体类型变量的引用

引用结构体变量时应注意如下几点:
1.对结构体变量中的数据可以逐步引用成员进行操作。结构体变量中的成员用以下方式引用:结构体变量名.成员名

2.如果结构体的某个成员本身又是一个结构体类型,则可以使用若干个成员运算符“.”,一级一级地找到最低的一级成员。只能对最低一级的成员进行赋值、存取及运算。

3.结构体变量的初始化,是指逐个对结构体变量的各个成员进行初始化的过程。

结构体数组

1.一般形式:

struct 结构体变量名 {成员列表} 数组名[常量
表达式];

2.结构体数组的初值应顺序地放在一对花括
号中。

指向结构体类型数据的指针

1.指向结构体变量的指针
①“->”称为指向运算符。
结构体变量。成员名”“(*结构体指针变量名).成员名”“结构体指针变量名一>成员名”这3种形式是等价的。

2.指向结构体数组的指针
结构体数组及其元素也可以用指针变量来指
向。当使用指针变量指向结构体数组时,只要把该
结构体数组中的每个元素当作普通的结构体变量使
用即可。

3.结构体变量和指向结构体的指针作为函数参数
将一个结构体变量的值传递给另一个函数,有如
下方法。
①结构体变量的成员作为实参传递给主调函数。
②可以用结构体变量作为一个整体实参。
③C语言中,允许将结构体变量的地址作为实参传递,这时,对应的形参应该是一个基类型相同的结构体类型的指针。

十一、宏定义

不带参数的宏定义

1.定义形式

#define 宏名 替换文本

或者

#define 宏名

2.说明:

  • 在define宏名和宏替换文本之间要用空格隔开。
  • 可以用#undef命令终止宏定义的作用域。
  • 当进行宏定义时,可以引用已定义的宏名。
  • 同一个宏名不能重复定义。

带参数的宏定义

1.定义形式。

#define 宏名(参数表) 字符串

宏定义不只进行简单的字符串替换,还可进行参数替换。

2.执行过程。
①如果程序中有带实参的宏,则按#define命令行中指定的字符串从左到右进行置换。
②如果字符串中包含宏中的形参(如xy),则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。
③如果宏定义的字符串中的字符不是参数字符(如(x*y)中的“*”号),则保留。这样就形成了置换的字符串。


  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值