C语言数据类型
1970年,AT&T的Bell实验室的D.Ritchie和K.Thompson共同发明了C语言。研制C语言的初衷是用它编写UNIX系统程序
1.基本类型
- 数值类型
- short短整型(修饰符)
- int整型
- long长整型()
- float单精度
- double双精度
- 字符串类型 char
2.构造类型
- 数组
- 结构体 struct
- 共同体 union
- 枚举类型 enum
3.指针类型
4.空类型void
c的五种基本类型: Int(整型) double(双精度浮点) float(浮点) char (字符)viod(空值)
c语言void和int
void在C语言中代表空值,在接口定义中用来做返回值表示该接口无返回值或者返回的是个空值,在函数内部没有return XXX的用法;但是如果要提前返回,结束函数执行可以调用return; void表示空 没返回值(空类型) ; int 一个返回整数类型,有返回值;
二、C语言
一、序言
1.什么是C语言(who)
c语言是人类和计算机交流的一种方式
ANSI C是C语言的标准
2.C语言的特点(what)
- 简单
- 快速
- 高性能
- 兼容性号
- 功能强大
- 易于学习
3.C语言最适合做什么
- linux嵌入式
- 小巧
- 灵活
- 适合做小工具
- 操作系统
- 硬件编程
- 高性能软件(NGINX)
二、第一个程序
#include <stdio.h>
int main()
{
printf("hello word!\n");
return 0;
}
$gcc a.c
三.多个源文件
max.c
int max (int a,int b)
{
if(a>b)
{
return a;
}
else
{
return b;
}
}
hello.c
#include <stdio.h>
#include "max.c"
int main()
{
int a1 = 33;
int a2 = 21;
int maxNum=max(a1,a2);
printf("the max value is %d\n",maxNum);
return 0;
}
$gcc hello.c -o main.out
4.头文件与函数分离
max.c
int max (int a,int b)
{
if(a>b)
{
return a;
}
else
{
return b;
}
}
max.h
int max(int a,int b);
hello.c
#include <stdio.h>
#include "max.h"
int main()
{
int a1 = 33;
int a2 = 21;
int maxNum=max(a1,a2);
printf("the max value is %d\n",maxNum);
return 0;
}
$gcc max.o hello.c
#include <stdio.h>
int max (int a,int b)
{
if(a>b)
{
return a;
}
else
{
return b;
}
}
int main()
{
int a1 = 33;
int a2 = 21;
int maxNum=max(a1,a2);
printf("the max value is %d\n",maxNum);
return 0;
}
//the max value is 33
5.Makefile
Makefile 使文件
hello.out:max.o min.o hello.c
gcc max.o min.o hello.c -o hello.out
max.o:max.c
gcc -c max.c
min.o:min.c
gcc -c min.c
$make
三、vim
sudo apt-get update 乌班图的更新软件
sudo apt-get install vim 安装vim
gcc协议,gcc就是cc ;gcc -v 是查看版本
i前面
a后面。:shift+a 行首插入
q推出
o 行尾
shift +o
1.文件和目录 (乌班图中)
cd〜或cd / home进入主目录1
cd .. 返回上一目录
cd ../ .. 返回上两级目录2
pwd 显示当前工作路径
ls 查看目录中的文件
ls -F 查看目录中的文件3
ls -l 显示文件和目录的详细资料
ls -a 显示系统隐藏文件
ls * [0-9] * 显示包含数字0-9的文件和目录 4
mkdir xxx 创建xxx目录
mkdir xx1 xx2 同时创建xx1和xx2目录 5
rm -f file1 删除文件file1
rmdir xxx1 删除xxx1目录
rm -rf dir1 删除dir1目录以及该目录的所有内容6
rm -rf dir1 dir2同时删除这两个目录下的所有内容
mv dir1 dir2 将dir1重命名为dir2 7
cp dir1 dir2 拷贝dir1新的拷贝贝项为dir2
cp目录/ * 拷贝目录目录下所有的文件到当前目录下 8
cp -a / tmp / dir1将dir1目录复制到当前目录 9
touch -t(YYMMDDhhmm)file1修改文件file1的时间戳 10
Makefile文件
# this is make file
hello.out:max.o min.o hello.c -o hello.out
hello.out:max.o min.o hello.c
gcc max.o min.o hello.c
max.o:max.c 对max.o进行编译
gcc -c max.c
min.o:max.c
gcc -c min.c
字符串指针和c中问好用法
C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中
#include <stdio.h>
#include <string.h>
int main(){
char str[] = "http://c.biancheng.net";
int len = strlen(str), i;
//直接输出字符串
printf("%s\n", str);
//每次输出一个字符
for(i=0; i<len; i++){
printf("%c", str[i]);
}
printf("\n");
return
//Gpu cpu 一行中出现?(问好):
# include <stdio.h>
int main()
{
int a =1;
int b = 2;
char c;
(a>b)?printf("d"):printf("ds\n");
return 0;
}
三、C语言的内存
1.GDB
用于调试的一种工具,可以轻松的看到程序内部运行结构
gcc -g main.c -o main.out #将文件转成可支持gdb调试的调试文件
gdb ./main.out #进行调试
gdb中的使用方法:
-l #显示源代码
enter #继续执行代码
start #开始调试
p/print a #打印a运行结果
n #继续执行
$1/$2/$3 代表第一第二第三执行结果
s #代表进入函数内部
bt #查看函数堆栈
f 1 #表示切换到1这个函数栈
q #退出调试
x/3d <x0ffffffffffffffffff> # 从开始的地方按照十进制的类型连续显示三位;
2. 计算机中数据(重要)
数据的表示方法:计算机中一般以16进制的数来自动分配保存的地址;
一个16进制的数等于四个2进制的数如(0xF = 1111 = 15);
从上往下分为:
系统内核: #用于给系统自己处理的内存空间:24个十六进制字节
栈内存: #系统自动分配当执行代码程序的时候,需要在栈内分配数据的内存
自由分配区: #用于个人处理数据自由分配的空间
堆 #堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程 序结束时可能由OS回收,分配方式倒是类似于链表
数据段: #用于存储 global const 等全局变量常量的数据
代码段: #存储代码的部分,main函数入口也在此区域
3.指针和内存的实质
//无指针的情况下
#include<stdio.h>
int change(int a,int b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 5;
int b = 3;
change(a,b);
printr("a:%d;b:%d",a,b);
}
//以上结果输出:a:5;b:3 #结果并没有改变;
// 有指针的情况下
#include<stdio.h>
int change(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int a = 5;
int b = 3;
change(&a,&b);
printr("a:%d;b:%d",a,b);
}
//以上结果输出:a:3;b:5 #结果改变;
通过以上,得知:
#### 指针*:
#### 保存的就是我们的内存地址;在有*的情况下,他会根据内存地址找到相应变量的值
#### 如果变量保存的也是内存地址,那么他会根据指针找到变量下的内存的值;指针也就是我们说的线索
#### gdb 中:
#### p a => (a : x0ffffffffffffffff);
#### p *a => 5;
#### 变量:
#### 变量实质上就是一个代号,里面可以是值,也可以是内存地址;
#### \&a;
#### 实质上是吧变量a的内存地址取出来;gdb中 p &a => (a : x0ffffffffffffffff); p a=> 5;
#### 注意:在我们强行取出一个没有定义的值时,系统会给出一个不确定的值,该值可能带来程序的不可控性;
4.内存中各个类型的内存大小:
#### 在分配地址中,编译器会进行内存分配优化,会将所有同类型的分配在相邻;
#### 1. 整型类型: 32位b 4字节;
#### 2. 64位系统下指针会占 64位b 8字节;
#### 3. 32位系统下指针会占 32位b 4字节;
####
5. 栈内存和代码段分配的内存大小
#### 在分配地址中,编译器会进行内存分配优化,会将所有同类型的分配在相邻;
#### 1. 整型类型: 32位b 4字节;
#### 2. 64位系统下指针会占 64位b 8字节;
#### 3. 32位系统下指针会占 32位b 4字节;
6. 数组声明的内存排列
#### 在内存中,数组的排列顺序的连续的
#### 数组的定义:int array[3];
3 代表数组有多少个值;
###
四、指针
1. 函数指针:
(* pdemo)(a); pdemo 是一个函数的内存地址
通过*来指向该内存下的函数
前面()代表:告诉系统这是代码段下的一个函数不是栈内和堆内的内存地址;让他去代码段内找到该函数
后面的()代表运行并传参;
2.指针的运算;
指针加: #会先判断指针下的值是什么类型,然后在根据类型所占空间大小增加字节位数;
指针偏移: p代表指针; p+=3; 代表讲指针p向下移动三个(字节)!;
五、数组指针
数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。以int arr[] = { 99, 15, 100, 888, 252 };
为例,该数组在内存中的分布如下图所示:
定义数组时,要给出数组名和数组长度,数组名可以认为是一个指针,它指向数组的第 0 个元素。在C语言中,我们将第 0 个元素的地址称为数组的首地址。以上面的数组为例,下图是 arr 的指向:
数组名的本意是表示整个数组,也就是表示多份数据的集合,但在使用过程中经常会转换为指向数组第 0 个元素的指针,所以上面使用了“认为”一词,表示数组名和数组首地址并不总是等价。初学者可以暂时忽略这个细节,把数组名当做指向第 0 个元素的指针使用即可
下面的例子演示了如何以指针的方式遍历数组元素:
#include <stdio.h>
int main(){
int arr[] = { 99, 15, 100, 888, 252 };
int len = sizeof(arr) / sizeof(int); //求数组长度
int i;
for(i=0; i<len; i++){
printf("%d ", *(arr[i] ); //*(arr+i)等价于arr[i]
}
printf("\n");
return 0;
}
我们也可以定义一个指向数组的指针,例如:
int arr[] = { 99, 15, 100, 888, 252 };
int *p = arr;
arr 本身就是一个指针,可以直接赋值给指针变量 p。arr 是数组第 0 个元素的地址,所以int *p = arr;
int *p = &arr[0];
强调一遍,“arr 本身就是一个指针”这种表述并不准确,严格来说应该是“arr 被转换成了一个指针”
如果一个指针指向了数组,我们就称它为数组指针(Array Pointer)。
数组指针指向的是数组中的一个具体元素,而不是整个数组,所以数组指针的类型和数组元素的类型有关,上面的例子中,p 指向的数组元素是 int 类型,所以 p 的类型必须也是int *
。
反过来想,p 并不知道它指向的是一个数组,p 只知道它指向的是一个整数,究竟如何使用 p 取决于程序员的编码。
2.C指针
i++和++i是C语言运算符,i++是后缀递增的意思,++i是前缀递增的意思。
1、i++是后缀递增的意思,i++是先进行表达式运算,再进行自增运算。把i++的运算过程拆分开,等效于i=i+1可以看到运算结果是一致的。 x = i ++; //先让x变成i的值1,再让i加1
2、++i是前缀递增的意思,++i是先进行自增或者自减运算,再进行表达式运算。运算结果可以发现,仅从i的值来看,++i和i++最终的i值是一样的,都是i自增加了1。
x = ++i; //先让i加1, 再让x变成i的值1
i++是先访问i然后再自增,
而 ++i 则是先自增然后再访问i的值;[笑cry]
#include <studio.h>
int main() {
int i,x;
i = 1;
x = 1;
x = i ++; //先让x变成i的值1,再让i加1
print("%d", x); //输出的x为1
print("%d", i); //输出的i为2
i = 1;
x = 1;
x = ++i; //先让i加1, 再让x变成i的值2
print("%d", x); //输出的x为2
print("%d", i); //输出的i为2
}
解释
x = i++ 等价于 x= i ; i= i+1
x = ++i 等价于 i =i+1 ; x= i
1.初始指针
#include <stdio.h>
int main()
{
int a=5;
int b=3;
// change(&a,&b);
printf("num a=%d\nnum b=%d\n",a,b);
return 0;
}
// num a=5
// num b=3
// [Finished in 0.7s]
main.c
#include <stdio.h>
void change(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int a=5;
int b=3;
change(&a,&b);
printf("num a=%d\nnum b=%d\n",a,b);
return 0;
}
//num a=3
//num b=5
//[Finished in 0.7s]
&a 传递内存地址
2.gdb工具
-
要使用gdb工具调试c程序,需要在编译时加入-g参数
gcc -g main.c -o main.out
-
gdb ./main.out
-
l查看源代码
回车继续
-
start开始调试
-
n下一行
先显示,后执行
-
p a
打印a变量
-
change(a,b)
按s 进入该方法
-
bt查看堆栈
#0 change (a=5, b=3) at main2.c:6 #1 0x000055555555468e in main () at main2.c:15
-
f 0 表示切换0
-
quit 退出
3.内存管理
- 32位系统地址总线32位,64位系统地址总线64位
- 2的32次方约等于4G
- 64位操作系统用户可用48位,剩余内存运行系统
- 内存管理
4.指针
指针的本质就是内存地址
5.操作系统对内存的管理
#include <stdio.h>
int global=0;
int rect(int a,int b)
{
static int count=0;
count++;
global++;
int s=a*b;
return s;
}
int quadrate(int a)
{
static int count=0;
count++;
global++;
int s = rect(a,a);
return s;
}
int main()
{
int a=3;
int b=4;
int *pa = &a;
int *pb = &b;
int *pglobal = &global;
int (*pquadrate)(int a)=&quadrate;
int s=quadrate(a);
printf("%d\n",s);
}
//9
gcc -g ./ex.c -o ex.out
gdb ./ex.out
//代码段1
p &rect
$1 = (int (*)(int, int)) 0x5555555546aa <rect> //函数内存地址
(gdb) p &quadrate
$2 = (int (*)(int)) 0x5555555546e1 <quadrate> //函数内存地址,函数指令越多,内存差值越多
//数据段2
(gdb) p &global
$3 = (int *) 0x555555755014 <global>//数据内存地址
//函数段3
//一个函数可以被多次调用
(gdb) p &a
$4 = (int *) 0x7fffffffddcc //int 4字节
(gdb) p &b
$5 = (int *) 0x7fffffffddd0
(gdb) p &pa
$6 = (int **) 0x7fffffffddd8//64位系统指针8字节,32位系统指针4个字节
(gdb) p &pb
$7 = (int **) 0x7fffffffdde0
(gdb) p &s
$10 = (int *) 0x7fffffffddd4//int 都放在一起声明,所以int类型都连续
5.函数栈以及代码段
(gdb) p &s
$1 = (int *) 0x7fffffffddac
(gdb) s
rect (a=3, b=3) at ./ex.c:7
7 count++;
(gdb)
8 global++;
(gdb)
9 int s=a*b;
(gdb) bt
#0 rect (a=3, b=3) at ./ex.c:9
#1 0x0000555555554719 in quadrate (a=3) at ./ex.c:18
#2 0x0000555555554776 in main () at ./ex.c:30
(gdb) p &s
$2 = (int *) 0x7fffffffdd84
(gdb) p &count
$3 = (int *) 0x55555575501c <count>
(gdb) f 0
#0 rect (a=3, b=3) at ./ex.c:9
9 int s=a*b;
(gdb) p &count
$4 = (int *) 0x555555755018 <count>
(gdb) p &global
$5 = (int *) 0x555555755014 <global>
(gdb) f 0
#0 rect (a=3, b=3) at ./ex.c:9
9 int s=a*b;
(gdb) p &global
$6 = (int *) 0x555555755014 <global>
//不同方法中同一变量在不同内存地址中
//静态变量,变量在数据段中
//全局变量也在数据段中
6.指针指向与数据访问
- p a //a的值
- p pa //a的地址
- p *pa //先取a的地址,再获得a的值
7.数据声明的内存排列
#include <stdio.h>
int main()
{
int a=3;
int b=2;
int array[3];
array[0]=1;
array[1]=10;
array[2]=100;
int *p=&a;
int i;
for(i=0;i<6;i++)
{
printf("*p=%d\n",*p);
p++;
}
printf("----------------------------------------------------\n");
p=&a;
for(i=0;i<6;i++)
{
printf("*p[%d]=%d\n",i,p[i]);
}
}
c整理
C 语言特点(二)
C语言是一门面向过程、抽象化的通用程序设计语言,广泛应用于底层开发。
C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。
尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括一些类似嵌入式处理器嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。
C 程序结构
C 程序主要包括以下部分:
- 预处理器指令
- 函数
- 变量
- 语句 & 表达式
- 注释
实例
#include <stdio.h>
int main()
{
/* 我的第一个 C 程序 */
printf("Hello, World! \n");
return 0;
}
- 程序的第一行 *#include
* 是预处理器指令,告诉 C 编译器在实际编译之前要包含 stdio.h 文件。 - 下一行 int main() 是主函数,程序从这里开始执行。
- 下一行 /…/ 将会被编译器忽略,这里放置程序的注释内容。它们被称为程序的注释。
- 下一行 printf(…) 是 C 中另一个可用的函数,会在屏幕上显示消息 “Hello, World!”。
- 下一行 return 0; 终止 main() 函数,并返回值 0。
编译 & 执行 C 程序
- 打开一个文本编辑器,添加上述代码。
- 保存文件为 hello.c。
- 打开命令提示符,进入到保存文件所在的目录。
- 键入 gcc hello.c,输入回车,编译代码。
- 如果代码中没有错误,命令提示符会跳到下一行,并生成 a.out 可执行文件。
- 现在,键入 a.out 来执行程序。
- 您可以看到屏幕上显示 “Hello World”。
$ gcc hello.c
$ ./a.out
Hello, World!
如果是多个 c 代码的源码文件,编译方法如下:
$ gcc test1.c test2.c -o main.out
$ ./main.out
C 基本语法
C 的令牌(Tokens)
令牌可以是关键字、标识符、常量、字符串值,或者是一个符号。
分号;
在 C 程序中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。
printf("Hello, World! \n");
return 0;
注释
C 语言有两种注释方式:
// 单行注释
以 // 开始的单行注释,这种注释可以单独占一行。
/* 单行注释 */
/*
多行注释
多行注释
多行注释
*/
/* */ 这种格式的注释可以单行或多行。
不能在注释内嵌套注释,注释也不能出现在字符串或字符值中。
标识符
数字字符下划线,不能以数字开头,区分大小写,不允许出现标点符号
C 标识符是用来标识变量、函数,或任何其他用户自定义项目的名称。一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,代码后跟零个或多个字母、下划线和数字(0-9)。
C 标识符内不允许出现标点字符,比如 @、$ 和 %。C 是区分大小写的编程语言。因此,在 C 中,Manpower 和 manpower 是两个不同的标识符。下面列出几个有效的标识符:
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
关键字
下表列出了 C 中的保留字。这些保留字不能作为常量名、变量名或其他标识符名称。
关键字 | 说明 |
---|---|
auto | 声明自动变量 |
break | 跳出当前循环 |
case | 开关语句分支 |
char | 声明字符型变量或函数返回值类型 |
const | 声明只读变量 |
continue | 结束当前循环,开始下一轮循环 |
default | 开关语句中的”其它”分支 |
do | 循环语句的循环体 |
double | 声明双精度浮点型变量或函数返回值类型 |
else | 条件语句否定分支(与 if 连用) |
enum | 声明枚举类型 |
extern | 声明变量或函数是在其它文件或本文件的其他位置定义 |
float | 声明浮点型变量或函数返回值类型 |
for | 一种循环语句 |
goto | 无条件跳转语句 |
if | 条件语句 |
int | 声明整型变量或函数 |
long | 声明长整型变量或函数返回值类型 |
register | 声明寄存器变量 |
return | 子程序返回语句(可以带参数,也可不带参数) |
short | 声明短整型变量或函数 |
signed | 声明有符号类型变量或函数 |
sizeof | 计算数据类型或变量长度(即所占字节数) |
static | 声明静态变量 |
struct | 声明结构体类型 |
switch | 用于开关语句 |
typedef | 用以给数据类型取别名 |
unsigned | 声明无符号类型变量或函数 |
union | 声明共用体类型 |
void | 声明函数无返回值或无参数,声明无类型指针 |
volatile | 说明变量在程序执行中可被隐含地改变 |
while | 循环语句的循环条件 |
C 中的空格
只包含空格的行,被称为空白行,可能带有注释,C 编译器会完全忽略它。
在 C 中,空格用于描述空白符、制表符、换行符和注释。空格分隔语句的各个部分,让编译器能识别语句中的某个元素(比如 int)在哪里结束,下一个元素在哪里开始。因此,在下面的语句中:
int age;
在这里,int 和 age 之间必须至少有一个空格字符(通常是一个空白符),这样编译器才能够区分它们。另一方面,在下面的语句中:
fruit = apples + oranges; // 获取水果的总数
fruit 和 =,或者 = 和 apples 之间的空格字符不是必需的,但是为了增强可读性,您可以根据需要适当增加一些空格。
C 数据类型
据类型指的是用于声明不同类型的变量或函数的一个广泛的系统。变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式。
C 中的类型可分为以下几种:
序号 | 类型与描述 |
---|---|
1 | 基本类型: 它们是算术类型,包括两种类型:整数类型和浮点类型。 |
2 | 枚举类型: 它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量。 |
3 | void 类型: 类型说明符 void 表明没有可用的值。 |
4 | 派生类型: 它们包括:指针类型、数组类型、结构类型、共用体类型和函数类型。 |
数组类型和结构类型统称为聚合类型。函数的类型指的是函数返回值的类型。
整数类型
类型 | 存储大小 | 值范围 |
---|---|---|
char | 1 字节 | -128 到 127 或 0 到 255 |
unsigned char | 1 字节 | 0 到 255 |
signed char | 1 字节 | -128 到 127 |
int | 2 或 4 字节 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
unsigned int | 2 或 4 字节 | 0 到 65,535 或 0 到 4,294,967,295 |
short | 2 字节 | -32,768 到 32,767 |
unsigned short | 2 字节 | 0 到 65,535 |
long | 4 字节 | -2,147,483,648 到 2,147,483,647 |
unsigned long | 4 字节 | 0 到 4,294,967,295 |
为了得到某个类型或某个变量在特定平台上的准确大小,可以使用 sizeof 运算符。表达式 sizeof(type) 得到对象或类型的存储字节大小。
#include <stdio.h>
#include <limits.h>
int main()
{
printf("int 存储大小 : %lu \n", sizeof(int));
return 0;
}
%lu 为 32 位无符号整数,详细说明查看 C 库函数 - printf()。在 Linux 上编译并执行上面的程序时,它会产生下列结果:
int 存储大小 : 4
浮点类型
类型 | 存储大小 | 值范围 | 精度 |
---|---|---|---|
float | 4 字节 | 1.2E-38 到 3.4E+38 | 6 位小数 |
double | 8 字节 | 2.3E-308 到 1.7E+308 | 15 位小数 |
long double | 16 字节 | 3.4E-4932 到 1.1E+4932 | 19 位小数 |
头文件 float.h 定义了宏,在程序中可以使用这些值和其他有关实数二进制表示的细节。
#include <stdio.h>
#include <float.h>
int main()
{
printf("float 存储最大字节数 : %d \n", sizeof(float));
printf("float 最小值: %E\n", FLT_MIN );
printf("float 最大值: %E\n", FLT_MAX );
printf("精度值: %d\n", FLT_DIG );
return 0;
}
%E 为以指数形式输出单、双精度实数,详细说明查看 C 库函数 - printf()。
在 Linux 上编译并执行上面的程序时,它会产生下列结果:
float 存储最大字节数 : 4
float 最小值: 1.175494E-38
float 最大值: 3.402823E+38
精度值: 6
void 类型
void 类型指定没有可用的值。它通常用于以下三种情况下:
序号 | 类型与描述 |
---|---|
1 | 函数返回为空 C 中有各种函数都不返回值,或者您可以说它们返回空。不返回值的函数的返回类型为空。例如 void exit (int status); |
2 | 函数参数为空 C 中有各种函数不接受任何参数。不带参数的函数可以接受一个 void。例如 int rand(void); |
3 | 指针指向 void 类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size );返回指向 void 的指针,可以转换为任何数据类型。 |
C 变量
每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为 C 是大小写敏感的。基于前一章讲解的基本类型,有以下几种基本的变量类型:
类型 | 描述 |
---|---|
char | 通常是一个字节(八位)。这是一个整数类型。 |
int | 对机器而言,整数的最自然的大小。 |
float | 单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。 |
double | 双精度浮点值。双精度是1位符号,11位指数,52位小数。 |
void | 表示类型的缺失。 |
变量定义
变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表,如下所示:
type variable_list;
type 必须是一个有效的 C 数据类型,可以是 char、w_char、int、float、double 或任何用户自定义的对象,variable_list 可以由一个或多个标识符名称组成,多个标识符之间用逗号分隔。下面列出几个有效的声明:
int i, j, k;
char c, ch;
float f, salary;
double d;
变量可以在声明的时候被初始化(指定一个初始值)。初始化器由一个等号,后跟一个常量表达式组成,如下所示:
type variable_name = value;
extern int d = 3, f = 5; // d 和 f 的声明与初始化
int d = 3, f = 5; // 定义并初始化 d 和 f
byte z = 22; // 定义并初始化 z
char x = 'x'; // 变量 x 的值为 'x'
不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为 NULL(所有字节的值都是 0),其他所有变量的初始值是未定义的。
变量声明
变量的声明有两种情况:
- 1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
- 2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
- 除非有extern关键字,否则都是变量的定义。
extern int i; //声明,不是定义
int i; //声明,也是定义
实例
变量在头部就已经被声明,但是定义与初始化在主函数内:
#include <stdio.h>
// 函数外定义变量 x 和 y
int x;
int y;
int addtwonum()
{
// 函数内声明变量 x 和 y 为外部变量
extern int x;
extern int y;
// 给外部变量(全局变量)x 和 y 赋值
x = 1;
y = 2;
return x+y;
}
int main()
{
int result;
// 调用函数 addtwonum
result = addtwonum();
printf("result 为: %d",result);
return 0;
}
结果为:
result 为: 3
如果需要在一个源文件中引用另外一个源文件中定义的变量,我们只需在引用的文件中将变量加上 extern 关键字的声明即可。
addtwonum.c 文件代码:
#include <stdio.h>
/*外部变量声明*/
extern int x ;
extern int y ;
int addtwonum()
{
return x+y;
}
test.c 文件代码:
#include <stdio.h>
/*定义两个全局变量*/
int x=1;
int y=2;
int addtwonum();
int main(void)
{
int result;
result = addtwonum();
printf("result 为: %d\n",result);
return 0;
}
左值和右值
C 中有两种类型的表达式:
- 左值(lvalue):指向内存位置的表达式被称为左值(lvalue)表达式。左值可以出现在赋值号的左边或右边。
- 右值(rvalue):术语右值(rvalue)指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。
变量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。下面是一个有效的语句:
int g = 20;
C 常量
常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。
常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。
常量就像是常规的变量,只不过常量的值在定义后不能进行修改。
整数常量
整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。
整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。
下面列举几个整数常量的实例:
212 /* 合法的 */
215u /* 合法的 */
0xFeeL /* 合法的 */
078 /* 非法的:8 不是八进制的数字 */
032UU /* 非法的:不能重复后缀 */
85 /* 十进制 */
0213 /* 八进制 */
0x4b /* 十六进制 */
30 /* 整数 */
30u /* 无符号整数 */
30l /* 长整数 */
30ul /* 无符号长整数 */
浮点常量
浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。带符号的指数是用 e 或 E 引入的。
下面列举几个浮点常量的实例:
3.14159 /* 合法的 */
314159E-5L /* 合法的 */
510E /* 非法的:不完整的指数 */
210f /* 非法的:没有小数或指数 */
.e55 /* 非法的:缺少整数或分数 */
字符常量
字符常量是括在单引号中,例如,’x’ 可以存储在 char 类型的简单变量中。
字符常量可以是一个普通的字符(例如 ‘x’)、一个转义序列(例如 ‘\t’),或一个通用的字符(例如 ‘\u02C0’)。
在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。下表列出了一些这样的转义序列码:
转义序列 含义
\\ \ 字符
\' ' 字符
\" " 字符
\? ? 字符
\a 警报铃声
\b 退格键
\f 换页符
\n 换行符
\r 回车
\t 水平制表符
\v 垂直制表符
\ooo 一到三位的八进制数
\xhh . . . 一个或多个数字的十六进制数
字符串常量
字符串字面值或常量是括在双引号 “” 中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
您可以使用空格做分隔符,把一个很长的字符串常量进行分行。
下面的实例显示了一些字符串常量。下面这三种形式所显示的字符串是相同的。
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
定义常量
-
使用 #define 预处理器。
#define identifier value
#include <stdio.h> #define LENGTH 10 #define WIDTH 5 #define NEWLINE '\n' int main() { int area; area = LENGTH * WIDTH; printf("value of area : %d", area); printf("%c", NEWLINE); return 0; }
value of area : 50
-
使用 const 关键字。
const type variable = value;
#include <stdio.h> int main() { const int LENGTH = 10; const int WIDTH = 5; const char NEWLINE = '\n'; int area; area = LENGTH * WIDTH; printf("value of area : %d", area); printf("%c", NEWLINE); return 0; }
value of area : 50
C 存储类
存储类定义 C 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出 C 程序中可用的存储类:
- auto
- register
- static
- extern
auto 存储类
auto 存储类是所有局部变量默认的存储类。
{
int mount;
auto int month;
}
上面的实例定义了两个带有相同存储类的变量,auto 只能用在函数内,即 auto 只能修饰局部变量。
register 存储类
register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 ‘&’ 运算符(因为它没有内存位置)。
{
register int miles;
}
寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义 ‘register’ 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。
static 存储类
static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
全局声明的一个 static 变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static 变量或方法同一个文件中。
#include <stdio.h>
/* 函数声明 */
void func1(void);
static int count=10; /* 全局变量 - static 是默认的 */
int main()
{
while (count--) {
func1();
}
return 0;
}
void func1(void)
{
/* 'thingy' 是 'func1' 的局部变量 - 只初始化一次
* 每次调用函数 'func1' 'thingy' 值不会被重置。
*/
static int thingy=5;
thingy++;
printf(" thingy 为 %d , count 为 %d\n", thingy, count);
}
实例中 count 作为全局变量可以在函数内使用,thingy 使用 static 修饰后,不会在每次调用时重置。
可能您现在还无法理解这个实例,因为我已经使用了函数和全局变量,这两个概念目前为止还没进行讲解。即使您现在不能完全理解,也没有关系,后续的章节我们会详细讲解。当上面的代码被编译和执行时,它会产生下列结果:
thingy 为 6 , count 为 9
thingy 为 7 , count 为 8
thingy 为 8 , count 为 7
thingy 为 9 , count 为 6
thingy 为 10 , count 为 5
thingy 为 11 , count 为 4
thingy 为 12 , count 为 3
thingy 为 13 , count 为 2
thingy 为 14 , count 为 1
thingy 为 15 , count 为 0
extern 存储类
extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候,如下所示:
第一个文件:main.c
#include <stdio.h>
int count ;
extern void write_extern();
int main()
{
count = 5;
write_extern();
}
第二个文件:support.c
#include <stdio.h>
extern int count;
void write_extern(void)
{
printf("count is %d\n", count);
}
第二个文件中的 extern 关键字用于声明已经在第一个文件 main.c 中定义的 count。
$ gcc main.c support.c
结果:
count is 5
C 运算符
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 杂项运算符
算术运算符
下表显示了 C 语言支持的所有算术运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:
运算符 | 描述 | 实例 |
---|---|---|
+ | 把两个操作数相加 | A + B 将得到 30 |
- | 从第一个操作数中减去第二个操作数 | A - B 将得到 -10 |
* | 把两个操作数相乘 | A * B 将得到 200 |
/ | 分子除以分母 | B / A 将得到 2 |
% | 取模运算符,整除后的余数 | B % A 将得到 0 |
++ | 自增运算符,整数值增加 1 | A++ 将得到 11 |
– | 自减运算符,整数值减少 1 | A– 将得到 9 |
关系运算符
下表显示了 C 语言支持的所有关系运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为真。 | (A == B) 不为真。 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A > B) 不为真。 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 | (A < B) 为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A >= B) 不为真。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A <= B) 为真。 |
逻辑运算符
下表显示了 C 语言支持的所有关系逻辑运算符。假设变量 A 的值为 1,变量 B 的值为 0,则:
运算符 | 描述 | 实例 |
---|---|---|
&& | 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 | (A && B) 为假。 |
|| | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 | (A || B) 为真。 |
! | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 | !(A && B) 为真。 |
位运算符
位运算符作用于位,并逐位执行操作。&、 | 和 ^ 的真值表如下所示: |
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
下表显示了 C 语言支持的位运算符。假设变量 A 的值为 60,变量 B 的值为 13,则:
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与操作,按二进制位进行”与”运算。运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1; |
(A & B) 将得到 12,即为 0000 1100 |
| | 按位或运算符,按二进制位进行”或”运算。运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1; |
(A | B) 将得到 61,即为 0011 1101 |
^ | 异或运算符,按二进制位进行”异或”运算。运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0; |
(A ^ B) 将得到 49,即为 0011 0001 |
~ | 取反运算符,按二进制位进行”取反”运算。运算规则:~1=0; ~0=1; |
(~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
« | 二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 | A « 2 将得到 240,即为 1111 0000 |
» | 二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。 | A » 2 将得到 15,即为 0000 1111 |
赋值运算符
下表列出了 C 语言支持的赋值运算符:
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
«= | 左移且赋值运算符 | C «= 2 等同于 C = C « 2 |
»= | 右移且赋值运算符 | C »= 2 等同于 C = C » 2 |
&= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
|= | 按位或且赋值运算符 | C |= 2 等同于 C = C | 2 |
杂项运算符 ↦ sizeof & 三元
下表列出了 C 语言支持的其他一些重要的运算符,包括 sizeof 和 ? :。
运算符 | 描述 | 实例 |
---|---|---|
sizeof() | 返回变量的大小。 | sizeof(a) 将返回 4,其中 a 是整数。 |
& | 返回变量的地址。 | &a; 将给出变量的实际地址。 |
* | 指向一个变量。 | *a; 将指向一个变量。 |
? : | 条件表达式 | 如果条件为真 ? 则值为 X : 否则值为 Y |
运算符优先级
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 |
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | « » | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | | | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | || | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=»= «= &= ^= |= | 从右到左 |
逗号 | , | 从左到右 |
C 判断
语句 | 描述 |
---|---|
if 语句 | 一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。 |
if…else 语句 | 一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。 |
嵌套 if 语句 | 您可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。 |
switch 语句 | 一个 switch 语句允许测试一个变量等于多个值时的情况。 |
嵌套 switch 语句 | 您可以在一个 switch 语句内使用另一个 switch 语句。 |
if 语句
if(boolean_expression)
{
/* 如果布尔表达式为真将执行的语句 */
}
如果布尔表达式为 true,则 if 语句内的代码块将被执行。如果布尔表达式为 false,则 if 语句结束后的第一组代码(闭括号后)将被执行。
C 语言把任何非零和非空的值假定为 true,把零或 null 假定为 false。
if…else 语句
if(boolean_expression)
{
/* 如果布尔表达式为真将执行的语句 */
}
else
{
/* 如果布尔表达式为假将执行的语句 */
}
如果布尔表达式为 true,则执行 if 块内的代码。如果布尔表达式为 false,则执行 else 块内的代码。
C 语言把任何非零和非空的值假定为 true,把零或 null 假定为 false。
if…else if…else 语句
一个 if 语句后可跟一个可选的 else if…else 语句,这可用于测试多种条件。
当使用 if…else if…else 语句时,以下几点需要注意:
- 一个 if 后可跟零个或一个 else,else 必须在所有 else if 之后。
- 一个 if 后可跟零个或多个 else if,else if 必须在 else 之前。
- 一旦某个 else if 匹配成功,其他的 else if 或 else 将不会被测试。
if(boolean_expression 1)
{
/* 当布尔表达式 1 为真时执行 */
}
else if( boolean_expression 2)
{
/* 当布尔表达式 2 为真时执行 */
}
else if( boolean_expression 3)
{
/* 当布尔表达式 3 为真时执行 */
}
else
{
/* 当上面条件都不为真时执行 */
}
嵌套 if 语句
在 C 语言中,嵌套 if-else 语句是合法的,这意味着您可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。
if( boolean_expression 1)
{
/* 当布尔表达式 1 为真时执行 */
if(boolean_expression 2)
{
/* 当布尔表达式 2 为真时执行 */
}
}
switch 语句
一个 switch 语句允许测试一个变量等于多个值时的情况。每个值称为一个 case,且被测试的变量会对每个 switch case 进行检查。
switch(expression){
case constant-expression :
statement(s);
break; /* 可选的 */
case constant-expression :
statement(s);
break; /* 可选的 */
/* 您可以有任意数量的 case 语句 */
default : /* 可选的 */
statement(s);
}
switch 语句必须遵循下面的规则:
- switch 语句中的 expression 是一个常量表达式,必须是一个整型或枚举类型。
- 在一个 switch 中可以有任意数量的 case 语句。每个 case 后跟一个要比较的值和一个冒号。
- case 的 constant-expression 必须与 switch 中的变量具有相同的数据类型,且必须是一个常量或字面量。
- 当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到 break 语句为止。
- 当遇到 break 语句时,switch 终止,控制流将跳转到 switch 语句后的下一行。
- 不是每一个 case 都需要包含 break。如果 case 语句不包含 break,控制流将会 继续 后续的 case,直到遇到 break 为止。
- 一个 switch 语句可以有一个可选的 default case,出现在 switch 的结尾。default case 可用于在上面所有 case 都不为真时执行一个任务。default case 中的 break 语句不是必需的。
嵌套 switch 语句
可以把一个 switch 作为一个外部 switch 的语句序列的一部分,即可以在一个 switch 语句内使用另一个 switch 语句。即使内部和外部 switch 的 case 常量包含共同的值,也没有矛盾。
switch(ch1) {
case 'A':
printf("这个 A 是外部 switch 的一部分" );
switch(ch2) {
case 'A':
printf("这个 A 是内部 switch 的一部分" );
break;
case 'B': /* 内部 B case 代码 */
}
break;
case 'B': /* 外部 B case 代码 */
}
? : 运算符(三元运算符)
Exp1 ? Exp2 : Exp3;
其中,Exp1、Exp2 和 Exp3 是表达式。
? 表达式的值是由 Exp1 决定的。如果 Exp1 为真,则计算 Exp2 的值,结果即为整个 ? 表达式的值。如果 Exp1 为假,则计算 Exp3 的值,结果即为整个 ? 表达式的值。
#include<stdio.h>
int main()
{
int num;
printf("输入一个数字 : ");
scanf("%d",&num);
(num%2==0)?printf("偶数"):printf("奇数");
}
C 循环
循环类型 | 描述 |
---|---|
while 循环 | 当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。 |
for 循环 | 多次执行一个语句序列,简化管理循环变量的代码。 |
do…while 循环 | 除了它是在循环主体结尾测试条件外,其他与 while 语句类似。 |
嵌套循环 | 您可以在 while、for 或 do..while 循环内使用一个或多个循环。 |
while 循环
只要给定的条件为真,C 语言中的 while 循环语句会重复执行一个目标语句。
while(condition)
{
statement(s);
}
statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。
condition 可以是任意的表达式,当为任意非零值时都为 true。当条件为 true 时执行循环。 当条件为 false 时,退出循环,程序流将继续执行紧接着循环的下一条语句。
for 循环
for ( init; condition; increment )
{
statement(s);
}
- init 会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句,只要有一个分号出现即可。
- 接下来,会判断 condition。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。
- 在执行完 for 循环主体后,控制流会跳回上面的 increment 语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。
- 条件再次被判断。如果为真,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为假时,for 循环终止。
do…while 循环
不像 for 和 while 循环,它们是在循环头部测试循环条件。在 C 语言中,do…while 循环是在循环的尾部检查它的条件。
do…while 循环与 while 循环类似,但是 do…while 循环会确保至少执行一次循环。
do
{
statement(s);
}while( condition );
条件表达式出现在循环的尾部,所以循环中的 statement(s) 会在条件被测试之前至少执行一次。
如果条件为真,控制流会跳转回上面的 do,然后重新执行循环中的 statement(s)。这个过程会不断重复,直到给定条件变为假为止。
嵌套循环
C 语言中 嵌套 for 循环 语句的语法:
for (initialization; condition; increment/decrement)
{
statement(s);
for (initialization; condition; increment/decrement)
{
statement(s);
... ... ...
}
... ... ...
}
C 语言中 嵌套 while 循环 语句的语法:
while (condition1)
{
statement(s);
while (condition2)
{
statement(s);
... ... ...
}
... ... ...
}
C 语言中 嵌套 do…while 循环 语句的语法:
do
{
statement(s);
do
{
statement(s);
... ... ...
}while (condition2);
... ... ...
}while (condition1);
循环控制语句
控制语句 | 描述 |
---|---|
break 语句 | 终止循环或 switch 语句,程序流将继续执行紧接着循环或 switch 的下一条语句。 |
continue 语句 | 告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。 |
goto 语句 | 将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。 |
break 语句
- 当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
- 它可用于终止 switch 语句中的一个 case。
如果使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。
continue 语句
C 语言中的 continue 语句有点像 break 语句。但它不是强制终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。
对于 for 循环,continue 语句执行后自增语句仍然会执行。对于 while 和 do…while 循环,continue 语句重新执行条件判断语句。
goto 语句
C 语言中的 goto 语句允许把控制无条件转移到同一函数内的被标记的语句。
注意:在任何编程语言中,都不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用 goto 语句的程序可以改写成不需要使用 goto 语句的写法。
goto label;
..
.
label: statement;
在这里,label 可以是任何除 C 关键字以外的纯文本,它可以设置在 C 程序中 goto 语句的前面或者后面。
无限循环
如果条件永远不为假,则循环将变成无限循环。for 循环在传统意义上可用于实现无限循环。由于构成循环的三个表达式中任何一个都不是必需的,您可以将某些条件表达式留空来构成一个无限循环。
C 指针
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。
指针变量声明的一般形式为:
type *var-name;
int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */
NULL 指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
NULL 指针是一个定义在标准库中的值为零的常量。
C 指针详解
概念 | 描述 |
---|---|
指针的算术运算 | 可以对指针进行四种算术运算:++、–、+、- |
指针数组 | 可以定义用来存储指针的数组。 |
指向指针的指针 | C 允许指向指针的指针。 |
传递指针给函数 | 通过引用或地址传递参数,使传递的参数在调用函数中被改变。 |
从函数返回指针 | C 允许函数返回指针到局部变量、静态变量和动态内存分配。 |
C 数组
C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。
数组的声明并不是声明一个个单独的变量,比如 number0、number1、…、number99,而是声明一个数组变量,比如 numbers,然后使用 numbers[0]、numbers[1]、…、numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。
所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
声明数组
在 C 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:
type arrayName [ arraySize ];
这叫做一维数组。arraySize 必须是一个大于零的整数常量,type 可以是任意有效的 C 数据类型。例如,要声明一个类型为 double 的包含 10 个元素的数组 balance,声明语句如下:
double balance[10];
现在 balance 是一个可用的数组,可以容纳 10 个类型为 double 的数字。
初始化数组
在 C 中,您可以逐个初始化数组,也可以使用一个初始化语句,如下所示:
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。
如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数。因此,如果:
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
您将创建一个数组,它与前一个实例中所创建的数组是完全相同的。下面是一个为数组中某个元素赋值的实例:
balance[4] = 50.0;
上述的语句把数组中第五个元素的值赋为 50.0。所有的数组都是以 0 作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去 1。
访问数组元素
数组元素可以通过数组名称加索引进行访问。元素的索引是放在方括号内,跟在数组名称的后边。例如:
double salary = balance[9];
上面的语句将把数组中第 10 个元素的值赋给 salary 变量。下面的实例使用了上述的三个概念,即,声明数组、数组赋值、访问数组
数组详解
在 C 中,数组是非常重要的,我们需要了解更多有关数组的细节。下面列出了 C 程序员必须清楚的一些与数组相关的重要概念:
概念 | 描述 |
---|---|
多维数组 | C 支持多维数组。多维数组最简单的形式是二维数组。 |
传递数组给函数 | 您可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。 |
从函数返回数组 | C 允许从函数返回数组。 |
指向数组的指针 | 您可以通过指定不带索引的数组名称来生成一个指向数组中第一个元素的指针。 |