基础

C主框架

1
2
3
4
5
6
int main()
{
/*****************
*****************/
return 0;
}

main函数,又称主函数,是程序执行的起点。在执行程序时,由系统调用主函数,最后返回,结束程序。主要代码要写在主函数里。

主函数的类型一般是int,最后由return返回0来结束运行。

头文件

C语言标准库

stdio.h是C语言标准库,提供了C语言最基本的语法以及一些函数。

1
2
3
4
5
6
7
#include<stdio.h>

int main()
{

return 0;
}

数学函数库

math.h里有大量关于数学操作的函数,可以用来更方便的解决问题。常用的有:

  • abs() 对整形数据取绝对值

  • fabs() 对浮点型数据取绝对值

  • sqrt() 对数据取平方根(double型)

  • pow(x, y) 求x的y次幂(double型)

string库

  • string.h中的函数主要用于对字符串进行操作,常用的函数有:

  • strlen() 返回字符串的长度。

  • strcmp(x, y) 比较字符串xy。当x < y,返回值小于0;当x = y,返回值等于0;当x > y,返回值大于0

  • strcpy(x, y) 将y指向的字符复制到x

  • strcat(x, y) 将字符串y连接到x的尾部

注释

  • // 单行注释

  • /**/ 整段注释

#define 定义标识符

C语言中可以使用#define来定义一个标识符来表示一个常量,或定义一些宏,定义的标识符,并不占用程序内存,在预编译阶段对程序代码进行文本替换。定义标识符的操作在主函数外面。

最常见的用法就是#define来定义一些常量:

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
#define PI = 3.1415926

int main()
{
printf("圆周率 = %d", PI);

return 0;
}

typedef 关键字定义

C语言允许用户使用 typedef 关键字来定义自己习惯的数据类型名称,typedef 的真正含义是给一个已经存在的类型名称起一个别名,注意是已经存在的数据类型,而非变量,例如:

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
typedef long long LL;

int main()
{
LL a = 12345678;

return 0;
}


数据

定义和赋值

定义:数据类型 数据名 ;

定义时赋初值:数据类型 数据名 赋值符号(=) 初值 ;

同时定义多个:数据类型 数据名 , 数据名 ;

注意! 定义时没有赋初值的话这个数据的值就是随机的,有需要时千万别忘了赋初值,没有需要时也赋初值也是一个很好的习惯。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>

int main()
{
int a = 0;
int b = 5;
double c = 3.14, d = 2.2;

printf("%d %d %lf %lf", a, b, c, d);

return 0;
}

输出如下:
0 5 3.14 2.2

变量和常量

在程序运行的过程中,可以改变值的变量称为变量。

程序运行过程中,不可以发生改变的量叫做常量。

一般定义的数据默认为变量,可以用define定义常量,也可以在定义时的数据类型前加上const使之成为常量。

1
2
3
const int a = 2;
const double pi = 3,1415926;

数据类型

整形

类型 存储大小 值范围
char 字符型 1字节 -128 到 127
short 短整型 2字节 -32,768 到 32,767
int 整型 4字节 -2,147,483,648 到 2,147,483,647
long 长整型 4字节 -2,147,483,648 到 2,147,483,647
long long 长长整形 8字节

浮点型

类型 存储大小 值范围 精度
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位有效位

unsigned

整型变量的值的范围包括负数到正数。

但是在实际应用中,有的数据的范围常常只有正值(如学号、年龄等),为了充分利用变量的值的范围,可以将变量定义为“无符号”类型。可以在类型符号前面加上修饰符 unsigned ,表示指定该变量是“无符号整数”类型。如果加上修饰符 signed或什么都不加,则是“有符号”类型。

布尔型

布尔类型是一种包含两种值的数据类型,即01。基本上,bool类型的值表示两种行为,即truefalse。在这里,’0'表示false值,而’1‘表示true值。

在C中,'0' 以0的形式存储,而其他整数以1的形式存储,即“非零即true”

C语言标准库不自带bool类型,需要引用stdbool.h头文件:
#include<stdbool.h>

有符号整型数据存储单元中最高位代表数值的符号,如果指定为无符号型,不能存放负数,如 -123 等。由于无符号整型变量不用符号位,所以可表示数值的范围是一般整型变量中的两倍。

内存分配

内存分配-CSDN

类型转换

在进行运算时,不同类型的数据要转换成同一类型。

自动类型转换(隐式类型转换)

  • float型数据自动转换成double型;

  • charshort型数据自动转换成int型;

  • int型与double型数据运算,直接将int型转换成double

  • int型与unsigned型数据、直接将int型转换成unsigned型;

  • int型与long型数据,直接将int型转换成long型。

如此等等,总之是由低级向高级型转换。另外不要错误地理解为先将char型或short型转换成int型,再转换成unsigned型,再转换成long型,直至double型。

强制类型转换

强制类型转换的一般形式为:(类型名) (表达式)

1
2
3
4
5
int a = 7, b = 2;
float y1, y2;
float y1 = a / b; // y1的值a/b为3.0
y2 = (float) (a / b); // y2的值为3.5, float将a强制转换为实型,b也随之自动转换为实型

ASCII码

每个字符都对应着一个ASCII码:ASCII码表
常用:

0 -> 48

9 -> 57

A -> 65

Z -> 90

a -> 97

z -> 122

进制转换

十进制: 默认数制

二进制:0B0b前缀表示,如0b0101

八进制:0前缀表示,如0123

十六进制:0X0x前缀表示,如0x1A

vc6.0中整形后加lL表示是long型,加u表示是unsigned


顺序结构

在C语言中,程序的执行分为三种结构:顺序结构、选择结构(分支结构)和循环结构。

顺序结构:代码从上到下顺序执行,中间没有任何判断和跳转。

变量输入输出

在C语言中,输入和输出是通过库函数stdio.h中的scanf()printf()函数来实现的。在输入与输出时,printf()函数与scanf()函数的格式字符串用于指定输入输出的格式。格式字符串中的格式说明符(如%d表示整数,%f表示浮点数)必须与后面参数的类型和数量相匹配。如果格式字符串与参数不匹配,可能会导致未定义的行为或输出错误。

表达式

C语言中的表达式主要由运算符和操作数构成。

运算符

  • 算术运算符+ - * / %
  • 赋值运算符:C语言中的赋值运算符=用于将一个表达式的值赋给变量。此外,C语言还支持复合赋值运算符,如+=-=*=/=%= 等,这些运算符可以简化赋值和算术运算的组合。
  • 自增自减运算符:C语言中的自增++和自减 -- 运算符用于将变量的值增加或减少1。这些运算符只能用于变量,不能用于常量或表达式。
  • 位运算符
位运算符 名称 规则
<< 左移 将 a 的二进制位向左移动 n 位,右侧补 0
>> 右移 向右移动 n 位,左侧补符号位(正数补 0,负数补 1
^ 异或 对应位不同时,结果为 1;相同则为 0
& 对应位不同时,结果为 1;相同则为 0
| 对应位至少有一个为 1 时,结果为 1;否则为 0

优先级

在C语言中,运算符的优先级决定了表达式中各个运算对象之间的计算顺序,即哪个部分先计算,哪个部分后计算。下面是C语言中常用的运算符优先级列表,从高到低排列:

  1. 括号 ()
  2. 一元运算符:++ - - !
  3. 算术运算符:* / %
  4. 算术运算符:+ -
  5. 关系运算符:< > <= >=
  6. 等价运算符:== !=
  7. 位运算符:<< >>
  8. 位运算符:&
  9. 位运算符:^
  10. 位运算符:|
  11. 条件运算符 ?:
  12. 赋值运算符:= += -=
  13. 逗号运算符: ,

需要注意的是,同一优先级的运算符按照结合性进行计算,大部分运算符遵循从左至右的结合性,只有单目运算符条件运算符赋值运算符遵循从右至左的结合性。

语句

C语言中的语句可以分为以下几类:

  • 表达式语句:由表达式加上分号;组成,用于计算表达式的值并执行副作用。
  • 函数调用语句:由函数名、实际参数加上分号;组成,用于调用函数。
  • 控制语句:用于控制程序的执行流程,包括条件判断、循环执行、转向等。
  • 复合语句:用花括号{}括起来的一条或多条语句,也称为块。
  • 空语句:只有分号;组成的语句,不执行任何操作的语句。

选择结构

if-else 判断结构

1
2
3
4
5
6
7
if(表达式1){
    语句1
    语句2
    ……
 
}

或者:

1
2
3
if(a > b)
a += b + 10;

关系运算符

< >= < <=

​ != 用于测试“不相等”

​ == 用于测试“相等”

逻辑运算符

||&&!

switch-case选择结构

switch-case语句一般搭配breakdefault使用。

中断语句break是C语言中的关键字,用于跳出循环或switch语句的执行。break语句通常用于在满足某个条件时提前终止循环,或在switch语句中匹配到某个case后跳出。

当 switch 表达式的值并不匹配所有 case 标签的值时,这个 default 子句后面的语句就会执行,switch 语句可以有一个可选的 default case,出现在 switch 的结尾。default case 可用于在上面所有 case 都不为真时执行一个任务。default case 中的 break 语句不是必需的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d", &day);

switch (day)
{
case 1:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
case 6:
printf("星期六\n");
break;
case 7:
printf("星期天\n");
break;
default:
printf("输入错误");
}
return 0;
}

:C语言中的switch语句具有“穿透”性,这意味着如果在switch case中没有使用break语句,那么匹配的case之后的所有case都将被执行。

三目运算符

格式:

1
a ? b : c;

意为若a成立,则执行b,否则执行c。

三目运算符有很多用法,如判断赋值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int a = 1, b = 2;
int x;

x = a > b ? a : b; // x = 2

/* 用三目运算符求出了a与b的最大值并赋给x,相较于
if (a > b)
{
x = a;
}
else
{
x = b;
}
要简单。
*/

如直接返回:

1
2
3
4
5
int cmp (int a, int b)
{
return a > b ? a * 2 : b + a + b / 2;
}


循环结构

循环语句具有在某些条件满足的情况下,反复执行特定代码的功能。

while

1
2
3
4
while (表达式)
{
语句;
}

do-while

1
2
3
4
do
{
语句;
} while(表达式);

do while 循环是先直接进⼊循环体,执⾏循环语句,然后再执⾏ while 后的判断表达式,表达式为真,就会进⾏下⼀次,表达式为假,则不再继续循环。

for

1
2
3
4
for (表达式1; 表达式2; 表达式3)
{
语句;
}

break、continue

在循环执行的过程中,如果某些状况发⽣的时候,需要提前终止循环,这是非常常见的现象。C语言中提供了 break 和 continue 两个关键字,就是应⽤到循环中的。

break 的作用是用于永久的终止循环,只要 break 被执行,直接就会跳出循环,继续往后执行。

continue 的作用是跳过本次循环 continue 后边的代码,在 for循环和 while 循环中有所差异的。

嵌套

分支结构和循环结构在使用中都可以嵌套,像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void Func(void)
{
int Flag = 0;

if (Flag) {
int Flag = 1;
while (Flag) {
static int Flag = 0;

Flag++;
if (Flag >= 100) {
for(int Flag = 0; Flag <= 100; ++Flag) {
}
break;
}
}
} else {
for(int Flag = 0; Flag <= 100; ++Flag) {
while (1) {
static int Flag = -100;

Flag++;
if (Flag >= 0) {
int Flag = 0;

if (Flag) {
printf("Test 1\r\n");
} else {
printf("Test 0\r\n");
}

break;
}
}
}
}
}

函数

函数是指将一组能完成一个功能或多个功能的语句放在一起的代码结构。在C语言程序中,至少会包含一个函数,即主函数main()

分类

库函数

​ 库函数就是存放在函数库中的函数,具有明确的功能、入口调用参数和返回值。

​ 库函数必须知道的一个秘密就是:使用库函数,必须包含 #include 对应的头文件。

自定义函数

​ 自定义函数和库函数一样,有函数名,返回值类型和函数参数。

局部变量与全局变量

任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量:

  • 在函数或块内部的局部变量

  • 在所有函数外部的全局变量

  • 形式参数的函数参数定义中

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>

int main ()
{
/* 局部变量声明 */
int a, b;
int c;
int sum = 0;

/* 实际初始化 */
a = 10;
b = 20;
c = a + b;

// a,b,c,sum都是main函数的局部变量

for (int i = 0; i < a; i ++ )
{
int d;
d = i * 2;

sum += d;
}

// i,d是for语句中的局部变量

printf ("value of a = %d, b = %d and c = %d\n", a, b, c);
printf ("sum = %d", sum);

return 0;

全局变量是定义在主函数外部,通常是在程序的顶部。全局变量在整个程序生命周期内都是有效的,在任意的函数内部能访问全局变量

全局变量可以被任何函数或语句访问。也就是说,全局变量在声明后整个程序中都是可用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

/* 全局变量声明 */
int g;

int main ()
{
/* 局部变量声明 */
int a, b;

/* 实际初始化 */
a = 10;
b = 20;
g = a + b;

printf ("value of a = %d, b = %d and g = %d\n", a, b, g);

return 0;
}

全局变量在定义时默认初值为0

递归

递归-菜鸟教程


数组

数组是一种数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组中的元素可以通过索引访问,索引通常从0开始

声明与初始化

1
2
3
int arr[5]; // 声明一个整型数组,其中包含5个元素,未初始化
int arr[] = {1, 2, 3, 4, 5}; // 声明一个整型数组,并初始化
int arr[5] = {1, 2, 3, 4, 5}; // 声明并初始化一个整型数组

访问

1
int a = arr[3]; // a = 4

遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

int main ()
{
int n[10]; /* n 是一个包含 10 个整数的数组 */
int i,j;

/* 初始化数组元素 */
for (i = 0; i < 10; i++ )
{
n[i] = i + 100; /* 设置元素 i 为 i + 100 */
}

/* 输出数组中每个元素的值 */
for (j = 0; j < 10; j++ )
{
printf("n[%d] = %d\n", j, n[j] );
}

return 0;
}

输出如下:

1
2
3
4
5
6
7
8
9
10
n[0] = 100
n[1] = 101
n[2] = 102
n[3] = 103
n[4] = 104
n[5] = 105
n[6] = 106
n[7] = 107
n[8] = 108
n[9] = 109

获取数组长度

数组长度可以使用 sizeof 运算符来获取数组的长度,例如:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main() {
int array[] = {1, 2, 3, 4, 5};
int length = sizeof(array) / sizeof(array[0]); // 获取数组长度

printf("数组长度为: %d\n", length);

return 0;
}

输出如下:
数组长度为: 5

多维数组

C 语言支持多维数组。多维数组声明的一般形式如下:
type name[size1][size2]...[sizeN];
多维数组最简单的形式是二维数组。一个二维数组,在本质上,是一个一维数组的列表。

初始化二维数组

多维数组可以通过在括号内为每行指定值来进行初始化:

1
2
3
4
5
6
int a[3][4] = {  
{0, 1, 2, 3} , /* 初始化索引号为 0 的行 */
{4, 5, 6, 7} , /* 初始化索引号为 1 的行 */
{8, 9, 10, 11} /* 初始化索引号为 2 的行 */
};

这样也是一样的:
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

遍历

嵌套的两个循环


字符串(字符数组)

字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,字符串的实际长度总要多一位,\0 是用于标记字符串的结束。在定义一个字符串时不需要把 \0字符放在字符串常量的末尾。C 编译器会在初始化数组时,自动把 \0 放在字符串的末尾。

转义字符

在C语言中,转义字符是以反斜杠\开头,后跟一个字符。它用来表示非打印字符,比如换行\n以及其他一些特殊的字符。

以下是C语言中常用的转义字符的完整列表:

\\:反斜杠
\':单引号
\":双引号
\?:问号
\a:警报(响铃)
\b:退格
\f:换页
\n:换行
\r:回车
\t:制表符(水平制表)
\v:垂直制表
\0:空字符
\ooo:八进制表示的字符(其中 ooo 是一个八进制数,范围为 0-377)
\xhh:十六进制表示的字符(其中 hh 是一个十六进制数,范围为 00-FF)

定义与赋值

1
2
char site[7] = {'R', 'U', 'N', 'O', 'O', 'B'};
char site[] = "RUNOOB";

实际上,字符串就是char类型的数组,各种操作都与数组大同小异。

输入输出

字符串用%s输入输出,且输入时不用加取地址符&

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main(){
char ch[11] = {'j', 'a', 'v', 'a', 't', 'p', 'o', 'i', 'n', 't', '\0'};
char ch2[11] = "javatpoint";

printf("Char Array Value is: %s\n", ch);
printf("String Literal Value is: %s\n", ch2);

return 0;
}

输出如下:

1
2
Char Array Value is: javatpoint
String Literal Value is: javatpoint

  • getchar()
    读取一个字符,包括任何字符。
  • gets()
    读取整行输入,直至遇到换行符,然后把换行符,储存其余字符,并在这些字符的末尾添加一个空字符使其成为一个 C 字符串。
  1. gets()函数不安全。
  2. C11标准委员会已经将其废除,建议能不用尽量不用。

指针

指针-菜鸟教程
指针-CSDN

取地址符

每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。

取内容符

符号*可以访问地址里面的内容。

指针与数组

在 C 语言中,数组名表示数组的地址,即数组首元素的地址。当我们在声明和定义一个数组时,该数组名就代表着该数组的地址。

指针与函数

传递指针给函数

C 语言允许传递指针给函数,只需要简单地 声明函数参数为指针类型 即可。


结构体

结构体(struct)是一种构造类型,它可以将不同的数据类型组合在一起形成一个新的数据类型,这种新的数据类型就是结构体。

声明

使用typedef定义别名,然后创建变量:

1
2
3
4
5
6
7
8
typedef struct Student {
char name[20];
int age;
float score;
} Student;

Student stu; // 创建了一个名为stu的结构体变量

访问

使用指针访问结构体成员:

1
2
3
4
5
6
7
8
9
10
11
struct Student {
char name[20];
int age;
float score;
};

struct Student stu = {"Tom", 18, 90.5f};
struct Student *p = &stu;
printf("%s\n", (*p).name); // 使用指针访问结构体成员
printf("%s\n", p->name); // 另一种访问结构体成员的方式

链表-结构体指针

结构体链表

—end—