跳到主要内容

C语言基础

一段简单的代码分析

输出单词 Hello World
# include <stdio.h>
int main() { // 程序里面有且仅有一个主函数
printf("Hello,World!\n");
return 0;
}

程序的第一行 #include <stdio.h> 是预处理器指令,告诉 C 编译器在实际编译之前要包含 stdio.h 文件。

第二行 int main() 是主函数,程序在这里执行,C语言程序都是从 main 函数开始执行

第三行 printf(...) 是 C 中另一个可用的函数,会在屏幕上显示消息 “Hello World”。

最后一行 return 0; 终止 main() 函数,并返回值 0 。

基础语法

  • 英文分号 ; ,在 C 程序中,分号是语句结束符。也就是说,每个语句必须以分号结束

  • C 语言中的注释有两种: 以 // 开始的单行注释,这种注释可以单独占一行 ; /* */ 这种个数的注释可以单行或者多行;不能在注释内嵌套注释,注释也不能出现在字符串或字符值中。

  • C 标识符是用来标识变量、函数,或任何其它用户自定义项目的名称。
    • 一个标识符以字母 A-Z 或 a-z 或 下划线_ 开始,不能以数字开始,后面跟零个或多个字母、下划线和数字(0-9)。
    • C 标识符内不允许出现标点符号,比如 @、$ 和 %。
    • C 是区分大小写的编程语言。
  • C 语言自己保留的关键字,编写程序时不能与之重复,如变量 定义 int/char/double 等保留字。

  • C 中的空格

    • 只包含空格的行,被称为空白行,可能带有注释,C 编译器会完全忽略它。
    • 在 C 中,空格用于描述空白符、制表符和注释。空格分割语句的各个部分,让编译器能识别语句中的某个元素(比如 int),在哪里结束,下一个元素从哪里开始
    • int age ,int 和 age 之间必须至少有一个空格字符(通常是一个空白符),这样编译器才能够区分它们。
    • fruit = apples + oranges; // 获取水果的总数 fruit 和 =,或者 = 和 apples 之间的空格字符不是必需的,但是为了增强可读性,可以根据需要适当增加一些空格。
  • sizeof 获取存储字节: 为了得到某个类型或某个变量在特定平台的准确大小,可以使用 sizeof 运算符。表示式 sizeof(type) 得到对象或类型的存储字节大小。,比如: sizeof(int)、sizeof(12)

  • void 类型用于 指定没有可用的值。它通常用于以下三种情况:

1
函数返回值为空
C 中有各种函数都不返回值,不返回值的返回类型为空
例如: void exit(int status);
2
函数参数为空
C 中有各种函数不接受任何参数。不带参数可以接受一个 void,可以直接不写。
例如 int rand(void);
3
指针指向 void
类型为 void* 的指针代表对象的地址,而不是类型。
例如,内存分配函数 void * malloc(size_tsize);返回指向 void 的指针,可以转换为任意类型

变量

变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有特定的类型,类型决定了变量的大小和布局,该范围内的值可以存储在内存中,运算符可应用于变量上。

变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为 C 是大小写敏感的。

变量定义:指定一个数据类型,并包含该类型的一个或多个变量的列表,如下所示:

type variable_list;

在这里 type 必须是一个有效的 c 数据类型,可以是 char、w_char、int、float、double 或任何用户自定义的对象, variable_list 可以由一个或多个标识符名称组成,多个标识符之间用逗号分割。下面列出几个有效的声明:

int i,j,k;

变量可以在声明的时候被初始化(指定一个初始值)。初始化器由一个等号,后跟一个常量表达式组成,如下所示:

type variable_name = value;

下面是几个实例:

int d = 3, f =5; // 定义并初始化整型变量 d 和 f
char x = 'x'; //字符型变量 x 的值为 x'

定义一维数组

定义一维数组

type arrayName[arraySize]

定义枚举类型

枚举第一个元素默认为 0, 可以赋其它值

枚举元素的值 默认在前一个元素基础上加1

定义枚举变量
enum DAY {
MON = 1,TUE,WED,THU,FRI,SAT,SUN
};

表达式

C 中有两种类型的表达式:

左值(lvalue): 指向内存位置的表达式被称为左值(lvalue)表达式。左值表达式可以出现在赋值号的左边或右边

右值(rvalue):术语右值(rvalue) 指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。

常量

整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0表示八进制,不带前缀则默认表示十进制。

浮点常量由 整数部分、小数点、小数部分和指数部分组成。可以使用小数形式或者指数形式来表示浮点常量,如:

3.14159
314159E-5

字符常量是括在单引号中,可以是一个普通的字符(例如 'x')、一个转义序列(例如 '\t')。 在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符 (\n) 或制表符 (\t)

字符串的字面值或常量是括在双引号 "" 中的。一个字符串包含类似于字符常量的字符: 普通字符、转义序列和通用的字符。

宏定义

#define 用来定义一个可以代替值的宏,语法格式如下:

# define 宏名称 值

例如

# define LENGTH 10 // 后续使用可用 LENGTH 代替 10 这个常量。

关键字

const 关键字

const 关键字定义一个 只读的变量,本质是修改了变量的存储方式为只读。

const int LENGTH = 10;// 定义变量 LENGTH = 10 ,且只读,即无法修改 LENGTH 的值。

static 关键字

使用 static 修饰局部变量可以在函数调用之间保持局部变量的值,这种方式不推荐。

static 修饰符 也可以应用于全局变量或函数。当 static 修饰全局变量或函数时,会使变量或函数的作用域限制在声明它的文件内。

避免被其它文件误用。

extern 关键字

extern 关键字用于 提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。

可以这么理解,extern 是 用来在另一个文件中声明一个全局变量或函数。extern 修饰符通常用于当有 两个或多个文件共享相同的全局变量或函数的时候

typedef 关键字

typedef 关键字为 类型取一个新的名字。下面的实例为单字节数字定义了一个术语 BYTE: typedef unsigned char BYTE

在这个类型定义之后,标识符 BYTE 可以作为类型 unsigned char 的缩写,例如: BYTE b1,b2;

提示

#define 为值取一个名字,typedef 为类型取一个名字。

运算符

算数运算符

下表显示了 C 语言支持的所有算数运算符。假设变量 A 的值为 10,变量 B 的值 为 20 ,则:

运算符描述实例
+把两个操作数相加A+B = 30
-把两个操作数相减A-B = -10
*把两个操作数相乘A*B = 200
÷分子除以分母B / A = 2
%取模运算符,整除后的余数B % A = 0
++自增运算符,整数值增加 1A++ 将得到 11
--自减运算符,整数值减少 1A-- 将得到 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)为真

杂项运算符

下表列出了 C 语言支持的其它一些重要的运算符,包括 sizeof 和 ?:

运算符描述实例
sizeof()返回变量的大小,字节大小sizeof(a) 将返回 4,其中 a 是整数。
&返回变量的地址,取地址符号&a; 将给出变量的实际地址
*指向一个变量*a; 将指向一个变量
?条件表达式如果条件为真 ? 则值为 X : 否则值为 Y

判断语句

判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。C 语言把 任何非零或非空的值假定为 true,把 零 或 null 假定为 false

1. if语句
if(boolean_expression){
//如果布尔表达式为真将执行的语句
}
2. if else 语句(扩展 if else if else)
if(boolean_expression){
//如果布尔表达式为真将执行的语句
}
3. switch case 语句
switch(boolean_expression){
case constant_expression:
statement(s);
break;
case constant_expression:
statement(s);
break;
// 可以有任意数量的 case 语句
default// 可选的
statement(s);
}

循环语句

循环语句允许我们多次执行一个语句或语句组,C 语言提供了以下几种循环类型:

1. while 语句
while(condition){
statement(s);
}
2. for 语句
for(init; condition; increment) {
statement(s);
}
3. do while 语句 (至少保证执行一次循环体)
do {
statement(s);
} while (condition);

break 语句

C 语言中的 break 语句有以下两种用法:

  1. 当 break 语句出现在 一个循环内时,循环会立即终止,且程序流将 继续执行紧接着循环的下一条语句

  2. 可用于终止 switch 语句中的一个 case

如果使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。

continue 语句

C 语言中的 continue 语句会跳过当前循环中的代码,强迫开始下一次循环

对于 for 循环,continue 语句执行后自增语句仍然会执行。对于 while 和 do...while 循环,continue 语句重新执行语句判断条件。

goto 语句

C 语言中的 goto 语句允许把控制无条件转移到同一函数内的被标记的语句

C 作用域

局部变量: 在某个函数或块内部声明的变量称为局部变量。它们只能被函数或该代码块内部的语句使用。局部变量在函数外部是不可知的。

全局变量是定义在函数外部,通常是在程序的顶部。全局变量在整个程序生命周期内都是有效的,在任意的函数内部能访问全局变量。全局变量可以被任何函数访问。也就是说,全局变量在声明后整个程序中都是可用的。

在程序中,局部变量和全局变量的名称可以相同,但是 在函数内,如果两个名字相同,会使用局部变量 ,全局变量不会被使用。

C 内存管理

定义一个指针,必须 使其指向某个存在的内存空间的地址,才能使用 ,否则使用野指针会造成段错误,内存分配与释放函数如下:

void free(void *addr); 该函数释放 addr 所指向的内存块,释放的是动态分配的内存空间。

void *malloc(int size); 在堆区分配一块指定大小为 size 的内存空间,用来存放数据,不会被初始化。

常用函数

下面是头文件 string.h 中定义函数,掌握以下常用的函数:

  • void *memcpy(void *dest,const void *src,size_t n): 从 src 复制 n 个字符到 dest
  • void *memset(void *str,int c,size_t n) 复制字符 c (一个无符号字符)到参数 str 所指向的字符串的前 n 个字符
  • char *strcat(char *dest,const char *src): 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
  • char *strncat(char *dest,const char *src,size_t n): 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。
  • char *strchr(const char *str,int c):在参数 str 所指向的字符串中搜索第一次出现字符 c (一个无符号字符)的位置。
  • int strcmp(const char *str1,const char *str2): 把 str1 所指向的字符串 和 str2 所指向的字符串进行比较。
  • char strcpy(char *dest,const char *str): 把 src 所指向的字符串复制到 dest
  • size_t strlen(const char *str): 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符