C_Note

C_Note

Slience_Displace Lv1

C _Base Grammars

基础语法

C_Language ? Cat_Language!!!

标准代码架构
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <stdio.h>  // 标准输入输出头文件,用于使用 printf 和 scanf 函数

// 定义一个常量宏
#define PI 3.14159

// 声明一个结构体
struct Person {
char name[50]; // 字符数组,用于存储名字
int age; // 整数类型,用于存储年龄
};

// 函数声明
void greet(struct Person p);
int add(int a, int b); // 两个整数相加的函数
void modifyValue(int *ptr); // 使用指针修改变量值的函数

// 主函数,程序的入口
int main() {
// 变量声明与初始化
int x = 10; // 声明一个整型变量并赋值
float radius = 5.5; // 声明一个浮点型变量并赋值
double area; // 声明一个双精度浮点型变量

// 条件判断语句 if-else
if (x > 5) {
printf("x is greater than 5.\n");
} else {
printf("x is less than or equal to 5.\n");
}

// 数组的声明与初始化
int numbers[5] = {1, 2, 3, 4, 5}; // 声明一个整型数组
char message[] = "Hello, World!"; // 声明并初始化字符数组(字符串)

// 使用循环遍历数组
printf("Array elements: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");

// 计算圆的面积
area = PI * radius * radius;
printf("The area of the circle with radius %.2f is %.2f\n", radius, area);

// 调用函数
int sum = add(5, 7); // 调用加法函数
printf("The sum of 5 and 7 is %d\n", sum);

// 指针的使用
int value = 20;
printf("Original value: %d\n", value);
modifyValue(&value); // 使用指针修改变量的值
printf("Modified value: %d\n", value);

// 使用结构体
struct Person person1; // 声明一个结构体变量
person1.age = 30; // 赋值
strcpy(person1.name, "Alice"); // 使用 strcpy 函数复制字符串
greet(person1); // 调用 greet 函数,传递结构体变量

// 指针与数组
int *ptr = numbers; // 指向数组的指针
printf("First element using pointer: %d\n", *ptr); // 通过指针访问数组第一个元素

return 0; // 主函数返回 0 表示程序正常结束
}

// 函数定义:用于打印欢迎信息
void greet(struct Person p) {
printf("Hello, %s! You are %d years old.\n", p.name, p.age);
}

// 函数定义:两个整数相加并返回结果
int add(int a, int b) {
return a + b;
}

// 函数定义:使用指针修改值
void modifyValue(int *ptr) {
*ptr = 50; // 通过指针修改传入的变量值
}


常量

常量在设置后是不能更改的

C语言中的常量可以根据其类型分为以下几类:

常量类型 描述 示例
整型常量 表示整数的常量,可以是十进制、八进制、十六进制表示。 100, 0123(八进制), 0x1A(十六进制)
浮点常量 表示小数的常量,包括科学计数法。 3.14, 1.0e-2
字符常量 表示单个字符的常量,必须用单引号包围。 'A', '9', '\n'
字符串常量 表示一串字符的常量,必须用双引号包围。 "Hello", "C语言"
符号常量 #defineconst关键字定义的具有固定值的标识符常量。 #define PI 3.14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//全局常量

//字符型常量
#define str_a = 'A'
#define str_a = '\n' //'\n'为转义字符,用于字符串换行 ; '\b',退格 ; '\\'反斜杠即'/'

//常量
#define Π 3.141 //#define 常量名 常量值

//符号常量
#define PI (3+2) //#define 常量名 含有符号的数字组合
int main() //函数需定义为int类型,才能在函数中定义并初始化int变量
{
int a = PI*2; //这里实际的运算状况是 3+2*7 相当于直接将PI移过来了
printf("i = %d\n",a); //输出7,

return 0;
}

变量

变量类型 描述 范围(根据实现) 示例
int 整型变量,用于存储整数。 -32,768 到 32,767 (16位系统),较常见是32位系统 int x = 5;
float 单精度浮点数,用于存储小数。 约为 ±3.4e–38 到 ±3.4e+38 float y = 3.14;
double 双精度浮点数,表示更大范围和更精确的小数。 ±1.7e–308 到 ±1.7e+308 double z = 2.71828;
char 字符变量,存储单个字符(ASCII码)。 -128 到 127 char c = 'A';
long 长整型,存储更大的整数。 -2^31 到 2^31-1 (32位系统) long n = 1000000;
short 短整型,存储较小的整数。 -32,768 到 32,767 short s = 32767;
unsigned 无符号整型,用于存储非负数。 0 到 65535 (16位系统) unsigned int u = 5;
1
2
3
4
5
6
7
8
9
10
11
12
//变量
int x = 5; //数据类型 变量名 = 值

//混合运算中的变量强制转换
int main(){
int i = 5;
float f = i/2; //输出结果为2.000
//因为左右操作数均为整形变量,i/2的整形运算结果会省去小数变为2

float f = (float)i/2; //(数据类型)变量名
//此时结果为2.5,由此也可推断混合运算的运算方法以左操作数为准
}

注意,在C语言中当变量被定义后它的类型就无法改变了,上文的(float)i应被视为一种将i转换为float形式的新的临时变量的表达式

C语言中的混合运算以float f = i/2;为例,他的结果数据类型和运算数据类型是分开的,流程上来讲是先判断操作数的数据类型,当左右操作数均为整形时执行整形计算,其他情况执行浮点运算,此时得出的结果为int类型数据,随后将结果返回变量f时被转换为float类型

下面是 C 语言中常用的变量类型的表格展示,包括每种类型的描述、占用的内存大小以及表示的范围

数据类型 描述 大小(通常) 范围
int 整数类型,表示带符号的整型数据 4 字节(考试可能会问) -2,147,483,648 到 2,147,483,647
unsigned int 无符号整数类型 4 字节 0 到 4,294,967,295
short 短整型,带符号 2 字节 -32,768 到 32,767
unsigned short 无符号短整型 2 字节 0 到 65,535
long 长整型,带符号 8 字节 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long 无符号长整型 8 字节 0 到 18,446,744,073,709,551,615
float 单精度浮点型,用于表示小数 4 字节 3.4E-38 到 3.4E+38(6 位有效数字)
double 双精度浮点型,用于表示高精度小数 8 字节 1.7E-308 到 1.7E+308(15 位有效数字)
char 字符类型,用于表示单个字符 1 字节 -128 到 127(或 0 到 255,取决于系统)
unsigned char 无符号字符类型 1 字节 0 到 255
long double 扩展精度浮点型 16 字节 3.4E-4932 到 1.1E+4932(18-19 位有效数字)
_Bool 布尔类型(C99 引入),表示真或假 1 字节 0(假)或 1(真)
void 无类型,通常用于函数返回类型和指针类型 无法表示数据

标准输出指令

prtinf( )

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

int main() {
int a = 1234;
char c = 'A';
float e = 1.3;

printf("Integer: %d\n Character: %c\n", a, c); //printf("字符串%格式化类型" ,数据)
//注意 当改行代码有多个变量需要被打印时C语言是按照从左向右的顺序来识别参数的,故参数顺序需一一对应

//修饰符混合使用
printf("Integer: %7d\nFloat: %-7.3f\n", a, e);
// %-7.3f 意思为 左对齐;字符最小宽度为7;浮点精度为小数点后3位;浮点数据类型


}

puts( )

输出一个字符串到标准输出(通常是显示器)。puts() 会自动在输出的字符串末尾加上一个换行符

int puts(const char *str);

  • 参数 str 是要输出的字符串。
  • 返回值为非负整数,表示写入的字符数量。如果发生错误,返回 EOF(即 -1)。
1
2
3
4
5
6
#include <stdio.h>
int main() {
char str[] = "Hello, World!";
puts(str); // 输出字符串并自动换行
return 0;
}

常用格式说明符

格式说明符 描述 示例
%d 十进制形式输出带符号整数 printf("%d", 123); => 123
%i 十进制形式输出带符号整数(与 %d 相同) printf("%i", 123); => 123
%u 十进制形式输出无符号整数 printf("%u", 123); => 123
%f 浮点数形式输出 printf("%f", 3.14); => 3.140000
%e 科学计数法形式输出浮点数 printf("%e", 123.45); => 1.234500e+02
%g 自动选择使用 %e%f 格式 printf("%g", 123.45); => 123.45
%c 输出单个字符 printf("%c", 'A'); => A
%s 输出字符串 printf("%s", "Hello"); => Hello
%x 小写十六进制形式输出无符号整数 printf("%x", 255); => ff
%X 大写十六进制形式输出无符号整数 printf("%X", 255); => FF
%o 八进制形式输出无符号整数 printf("%o", 255); => 377
%p 输出指针的值(地址) printf("%p", &a); => 0x7ff...
%% 输出百分号 % 本身 printf("%%"); => %

其他格式化修饰符

修饰符 描述 示例
- 左对齐(默认右对齐) printf("%-10d", 123); => 123
+ 强制输出数值符号(正数显示 + 号) printf("%+d", 123); => +123
正数前输出空格,负数前输出 - printf("% d", 123); => 123
0 用零填充(通常用于数字) printf("%04d", 5); => 0005
# 对于 %o%x%X,显示进制前缀 printf("%#x", 255); => 0xff
数字 最小字段宽度 printf("%5d", 12); => 12
.数字 精度控制,用于浮点数 printf("%.2f", 3.14159); => 3.14

标准读取函数

1.scanf( )

scanf 是 C 语言中用于从标准输入(通常是键盘)读取数据的函数。它可以根据指定的格式字符串,将输入的内容转换为对应的变量值,但他在Visual Studio 2022已被弃用,改用更安全的scanf_s

scanf_sscanf 的安全版本,要求为字符串输入提供额外的参数,指定缓冲区的大小,以防止缓冲区溢出。在传入数组时缓冲区大小需要和数组长度相等,否者会出现致命bug, (unsigned)sizeof(a) 是常用的自主获取组长度的方法,传入单个数字时则不需要额外参数

scanf_s 向参数传入数据时实际是向该数据的内存地址传值,因此需写为&变量名

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 num;
printf("enter a number:");
scanf_s("%d",&num); //传入数据时实际是向该数据的内存地址传值,因此需写为&变量名
printf("you enter number is %d\n", num);

//传入字符串
char a[10];
printf("enter a string(max length is 9):");
//scanf_s("%s",a,10);
scanf_s("%s", a, (unsigned)sizeof(a)); // 传入数组a以及它的大小
printf("you enter string is %s\n",a);

//混合传入
char c[10];
float f[10];
printf("enter a string and float (max length is 9):\n");
//scanf_s("%s",a,10);
scanf_s("%s",c, (unsigned)sizeof(c));
scanf_s("%f",&f[0]); //数组只以单个索引的形式传入值
printf("you enter string is %s\nyou enter float is%f\n",c,f[0]);


return 0;
}

//scanf已被启用,采用更安全感的scanf_s

关于混合传值

scanf通常读数读到空格就会中断,因此一次向多个变量传值使用空格来中断第一个传值过程,再次输入则向下一个变量传值

2.gets( )

用于获取一行的输入,遇到\n时中断,但gets() 函数不安全,因为它没有检查缓冲区的大小。输入的字符串如果超过数组大小,可能会导致缓冲区溢出,带来严重的安全漏洞。因此,gets() 已经在 C11 标准中被废弃,不推荐使用。

由于 gets() 存在安全性问题,通常建议使用更安全的替代函数 fgets()

fgets(str, sizeof(str), stdin)str 是字符数组,sizeof(str) 表示最多读取的字符数,stdin 是标准输入流。fgets() 会在读取到换行符或者到达指定字符数时停止

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

int main()
{
char f[10];
printf("enter a string and float (max length is 9):\n");
//gets(f);
fgets(&f,sizeof(f), stdin); //fgets(字符数组变量名,数组长度,sthdin)
printf("you enter int is %s\n", f);

return 0;
}

sp : get( )在获取字符串并传给数组时会自动在末尾加上\0

格式说明符

scanf 函数根据 格式说明符 将输入的字符转换为相应的数据类型。以下是常用的格式说明符:

数据类型 格式说明符 示例代码 示例输入 说明
int %d scanf_s("%d", &num); 123 读取一个十进制整数。
float %f scanf_s("%f", &flt); 3.14 读取一个浮点数。
double %lf 3.1415 读取一个双精度浮点数。
char %c scanf_s(" %c", &ch); A 读取一个字符(包括空白字符)。
字符串 %s scanf_s("%s", str,(unsigned)sizeof(str)); hello 读取字符串,遇到空白符停止。
无符号整数 %u 123 读取一个无符号整数。
八进制整数 %o 017 读取一个八进制整数。
十六进制整数 %x 0x1F 读取一个十六进制整数。
长整数 %ld 123456 读取一个长整型变量。
长长整数 %lld 12345678 读取一个长长整型变量。
指针 %p 0x7ffee 读取一个指针类型的地址。

运算符

1. 算术运算符

算术运算符用于执行基本的数学运算,如加法、减法、乘法、除法等。

运算符 描述 示例 结果
+ 加法 a + b ab 相加
- 减法 a - b a 减去 b
* 乘法 a * b a 乘以 b
/ 除法 a / b a 除以 b
% 取模(余数) a % b a 除以 b 的余数
++ 自增 ++aa++ a 递增 1
-- 自减 --aa-- a 递减 1
  • ++aa++:前者是前置自增(先加再用),后者是后置自增(先用再加)。
  • --aa--:类似地,分别为前置和后置自减。

2. 关系运算符

1
2
3
4
5
6
7
8
#include <stdio.h>
int main()
{
int a = 123;
error if (3 < a < 10)} //比较运算符无法进行中间值判断
//由于比较运算符返回的是0和1值,因此 3 < a < 10 实际执行的是result=3<a和result<10,因为result必定为0或1,故此判断式无效
if (3 < a && a < 10) //正确写法

关系运算符用于比较两个操作数,结果返回布尔值 1(真)或 0(假)。

运算符 描述 示例 结果
== 等于 a == b 如果 a 等于 b,返回 1;否则返回 0
!= 不等于 a != b 如果 a 不等于 b,返回 1;否则返回 0
> 大于 a > b 如果 a 大于 b,返回 1;否则返回 0
< 小于 a < b 如果 a 小于 b,返回 1;否则返回 0
>= 大于等于 a >= b 如果 a 大于等于 b,返回 1;否则返回 0
<= 小于等于 a <= b 如果 a 小于等于 b,返回 1;否则返回 0

3. 逻辑运算符

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
#include <stdio.h>

int main()
{
int i = 1;
i && printf("y ct see me \n"); //此时i被当作一个判断值使用
//逻辑与短路运算,当i为0时不执行,i为1时执行逻辑语后的表达式
//等价于下列if语句
if (i)
{
printf("y ct see me \n");
}



int a = 1;
a || printf("y ct see me \n"); //此时i被当作一个判断值使用
//逻辑或短路运算,当a为1时不执行,i为0时执行逻辑语后的表达式
//等价于下列if语句
if (!a)
{
printf("y ct see me \n");
}

return 0;
}

逻辑运算符用于布尔运算,常用于条件语句中的复杂判断。

运算符 描述 示例 结果
&& 逻辑与 a && b 如果 ab 都为真,返回 1;否则返回 0
|| 逻辑或 a || b 如果 ab 任一个为真,返回 1;否则返回 0
! 逻辑非 !a 如果 a 为假,返回 1;否则返回 0

4. 位运算符

位运算符用于位级操作,操作数被视为位模式而非数值。

运算符 描述 示例 结果
& 按位与 a & b ab 按位与
| 按位或 a | b ab 按位或
^ 按位异或 a ^ b ab 按位异或
~ 按位取反 ~a a 的按位取反
<< 左移 a << 2 a 左移 2 位
>> 右移 a >> 2 a 右移 2 位

5. 赋值运算符

赋值运算符用于为变量赋值,通常可以结合算术运算符进行简化操作。

运算符 描述 示例 结果
= 赋值 a = b b 的值赋给 a
+= 加后赋值 a += b a = a + b
-= 减后赋值 a -= b a = a - b
*= 乘后赋值 a *= b a = a * b
/= 除后赋值 a /= b a = a / b
%= 取模后赋值 a %= b a = a % b
<<= 左移后赋值 a <<= 2 a = a << 2
>>= 右移后赋值 a >>= 2 a = a >> 2
&= 按位与后赋值 a &= b a = a & b
^= 按位异或后赋值 a ^= b a = a ^ b
|= 按位或后赋值 a |= b a = a | b

6. 条件运算符(三元运算符)

条件运算符用于根据条件的真假执行不同的表达式。

运算符 描述 示例 结果
? : 条件表达式(类似 if-else) a ? b : c 如果 a 为真,执行 b,否则执行 c

7. 其他运算符

1
2
3
4
5
6
7
8
#include <stdio.h>
int main()
{
int a = 0;
int c = sizeof(a); //计算数据的字节大小
printf("num size is %d\n", c);
return 0;
}

除了上述常用的运算符,还有一些其他的运算符,包括取地址、取值、大小、逗号等。

运算符 描述 示例 结果
& 取地址 &a 返回变量 a 的地址
* 指针解引用 *p 返回指针 p 指向的值
sizeof 计算数据类型大小 sizeof(a) 返回 a 的字节大小
, 逗号表达式 a = (x++, y++) 先执行 x++,再执行 y++
-> 结构体指针成员访问 p->member 访问指针 p 指向的结构体的成员
. 结构体成员访问 s.member 访问结构体 s 的成员

7.运算符优先级

算数 > 关系 > 逻辑 :表格如下

C语言运算符优先级表

优先级最高符号名称或含义使用形式结合方向说明
1()括号表达式左结合
[]数组下标表达式左结合
->取结构体成员(指针)表达式左结合
.取结构体成员(非指针)表达式左结合
sizeof返回数据类型大小表达式左结合
2!逻辑非表达式右结合
~位取反表达式右结合
++自增表达式右结合
--自减表达式右结合
-负号表达式右结合
*指针表达式右结合
&取地址表达式右结合
3*表达式左结合
/表达式左结合
%取余表达式左结合
4+表达式左结合
-表达式左结合
5<<左移表达式左结合
>>右移表达式左结合
6<小于表达式左结合
<=小于等于表达式左结合
>大于表达式左结合
>=大于等于表达式左结合
7==等于表达式左结合
!=不等表达式左结合
8&按位与表达式左结合
9^按位异或表达式左结合
10|按位或表达式左结合
11&&逻辑与表达式左结合
12||逻辑或表达式左结合
13? :条件运算符表达式右结合
14=赋值表达式右结合
+=加赋值表达式右结合
-=减赋值表达式右结合
*=乘赋值表达式右结合
/=除赋值表达式右结合
%=取余赋值表达式右结合
<<=左移赋值表达式右结合
>>=右移赋值表达式右结合
&=按位与赋值表达式右结合
^=按位异或赋值表达式右结合
|=按位或赋值表达式右结合
15,逗号表达式左结合

考研复试可能会用

逻辑语句

逻辑语句概述

注意 逻辑语句后一般不加分号(;)

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
38
39
40
41
42
43
44
45
46
47
48
#include <stdio.h>

int main() {
int a = 5, b = 10;

// if...else 语句
if (a > b) {
printf("a is greater than b\n");
}
else if(a = b){
printf("a is equcal than b\n");
}
else {
printf("a is not greater than b\n");
}

// 逻辑与、逻辑或
if (a < b && b > 0) {
printf("Both conditions are true\n");
}

// 三元运算符
int max = (a > b) ? a : b;
printf("The maximum is %d\n", max);

// switch 语句
switch (a) {
case 5:
printf("a is 5\n");
break;
case 10:
printf("a is 10\n");
break;
default:
printf("a is not 5 or 10\n");
}

//for语句
int length = 10;
for (size_t t = 2; t < length; t++) //for(初始化变量;判断条件;变量变化表达式)
//for语句第一次循环 用初始量去判断条件,执行语句,执行变量变量变化表达式
//二次后的循环则是 判断条件,执行语句,执行变量变量变化表达式
{
printf("cool %d\n",t);
}

return 0;
}

C 语言中的逻辑语句主要包括逻辑运算符条件语句。逻辑语句用于控制程序的执行流程,常用的逻辑语句有 ifelse ifelseswitchwhilefordo...while 等。

1. 逻辑运算符

逻辑运算符用于连接条件表达式或进行条件判断。C 语言中的逻辑运算符如下表所示:

运算符 名称 用法 结果
&& 逻辑与(AND) expr1 && expr2 expr1expr2 均为真,结果为真,否则为假
| 逻辑或(OR) expr1 逻辑或 expr2 expr1expr2 任一真,结果为真
! 逻辑非(NOT) !expr expr 为真,结果为假,反之亦然

2. 条件语句

C 语言中的条件语句用于根据不同的条件执行不同的代码块。以下是常见的条件语句:

语句 用法 解释
if if (condition) { /* code */ } condition 为真时,执行 { /* code */ }
if...else if (condition) { /* code1 */ } else { /* code2 */ } 如果 condition 为真,执行 code1,否则执行 code2
else if if (condition1) { /* code1 */ } else if (condition2) { /* code2 */ } else { /* code3 */ } 多条件判断,第一个为真的条件执行相应的代码块
switch switch (expression) { case val1: /* code */ break; case val2: /* code */ break; default: /* code */ } 根据 expression 的值选择执行相应的 case 代码块

3. 循环语句

C 语言中的循环语句用于重复执行某一代码块,直到满足指定的条件。

语句 用法 解释
while while (condition) { /* code */ } condition 为真时,重复执行 { /* code */ }
do...while do { /* code */ } while (condition); 先执行一次代码块,再根据 condition 判断是否继续
for for (init; condition; increment) { /* code */ } 常用循环,按照初始化、条件判断、增量控制的顺序执行

4. 三元运算符

三元运算符是简化 if...else 语句的方式,语法如下:

运算符 用法 解释
?: condition ? expr1 : expr2 condition 为真时,返回 expr1,否则返回 expr2

5.continue和break

语句 用法 解释
continue continue; 当循环语句中出现 continue 时,跳过本次循环,执行下一次循环
break break; 当循环语句中出现 break 时,打断循环,执行后续语句

数组

数组类型 用法示例 访问方式 特点
一维数组 int arr[5]; arr[i] 固定大小,元素在内存中连续存储。
二维数组 int arr[3][4]; arr[i][j] 类似矩阵,元素按行优先存储。
多维数组 int arr[2][3][4]; arr[i][j][k] 用于复杂的多维数据存储。
字符数组 char str[] = "Hello"; str[i] '\0' 结尾,表示字符串。
动态数组 int *arr = (int *)malloc(5 * sizeof(int)); arr[i] 动态分配内存,大小可变。
参数传递 void func(int arr[], int size) arr[i] 传递指针,需要传递数组大小。

一维数组

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
#include <stdio.h>
int main()
{
// 声明并初始化
int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; //数组类型 数组名[数组大小] = { }
int b[] = {1,2,3,4,6,8,90,34,3,312} //无数组大小的初始化方式,编辑器会自动匹配数组大小
int length_b = sizeof(a) / sizeof(int); //获取数组长度,方便后续操作

int arr[5]; // 声明一个长度为5的整型空数组 此时数组里的值均为0


//访问数组
// 给数组的第3个元素赋值
arr[2] = 10; //数组名[索引号] = 值

// 获取第1个元素的值
int x = arr[0]; // 变量名 = 数组名[索引号]

//遍历数组
for(int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}

return 0;
}

主要 数组索引从0开始,因此大小为10的数组实际索引为0到9

关于数组初始化 :

通常可在数组后添加一个新的变量来动态的记录数组长度,常用的以为数组长度算法为int length_a = sizeof(a) / sizeof(int);

关于数组越界的问题 :

在访问数组时,如果使用的索引超出了数组的有效范围,可能会导致不可预知的行为或程序崩溃。从内存层面上,溢出的数组值会和该数组相邻的变量产生冲突,使得该变量获得错误的值,Visual Studio 2022会自动检测数组下标溢出问题,并阻止编译,但其他编译器仍可能出现问题

多维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
int matrix[3][4]; // 3行4列的二维数组

int matrix[2][3] = { //初始化
{1, 2, 3},
{4, 5, 6}
};

matrix[1][2] = 10; // 设置第2行第3列的值为10

return 0;
}

多维数组的内存结构

二维数组在内存中是按行连续存储的。例如,matrix[2][3] 在内存中的存储顺序为:matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0], matrix[1][1], matrix[1][2]

数组传递

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
#include <stdio.h>

// 函数原型声明,确保在 main 函数之前声明 print_a 函数
void print_a(int a[], int length);

int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
int length_a = sizeof(a) / sizeof(int);

print_a(a, length_a); // 调用 print_a 函数
printf("length_a = %d\n", length_a); // 输出数组长度,输出为10

return 0;
}

void print_a(int a[], int length) //数组a传递进print_a时传递的不是数组本身,而是指针
{
int length_a_p = sizeof(a) / sizeof(int); //此时sizeof(a)的值为它指针的大小,即8byte,故length_a_p此时的值并不能反映数组a的大小
printf("length_a_p = %d\n", length_a_p); //输出为2

int i;
for (i = 0; i < length; i++)
{
printf("%d\n", a[i]);
}
}

数组传递是按指针传递的,你传递的是数组首元素的地址,而不是整个数组。数组名退化为指针

数组的长度信息不会自动传递,数组长度信息丢失,需要手动传递长度。上述代码提供了一个可行的长度传递逻辑

指针传递使得函数可以修改原数组的值,因为指针指向的是相同的内存地址。

字符数组

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

int main()
{
char str[6] = { 'H', 'e', 'l', 'l', 'o', '\0' }; // 定义并初始化一个字符串。
//此方法有诸多弊端,例如结尾符忘写会输出乱码
char str2[] = "Hello"; // 字符串的简化初始化形式。通常使用这种方法初始化


int i;
for (i = 0; i < 6; i++)
{
printf("str = %c\n", str2[i]); //由于数组字符初始化时最后以为必定为\0,故长度为6的字符数组实际有效值只有5个,有效索引为0到4
}

printf("str = %s\n", str); //字符数组可通过%s格式化来整体输出

return 0;
}

关于字符数组初始化

字符数组是用于存储字符的数组,通常用于存储和处理字符串。在C语言中,字符串是以空字符 '\0' 结尾的字符数组,在对字符数组进行操作是要尤为注意索引问题

字符串操作函数str系列

该系列操作函数需调用<string.h>

在 C 语言中,string.h 头文件中提供了一些常用的字符串操作函数,包括 strlenstrcpystrcatstrcmp。这些函数专门用于处理以 '\0' 结尾的字符串

其中strcpystrcat由于其安全性的不足而被弃用,现用更安全的strcpy_sstrcat_s ,他们要求提供dest_size: 目标字符串的大小(总字节数,必须包含足够的空间来容纳源字符串和终止符 \0)来防止字符串溢出组中

dest_size 必须包含现有字符串、源字符串以及终止符 \0

如果目标缓冲区不够大,函数将不会追加字符串并返回错误。

如果目标或源字符串指针为 NULL,函数也会返回错误。

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
#include <stdio.h>
#include <string.h>
int main() {
char str_x[] = "test";
char str_b[30] = "Hello,World!";
char str_a[6] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char str_c[20];


int lenth_a;
lenth_a = strlen(str_a); //字符串计数器不包含组结尾的\0,因此返回值比实际组长度小1
printf("lenth of str_a is %d\n", lenth_a);
printf("size of str_a is %d\n", 6);

//字符串复制到另一字符串
strcpy_s(str_c,sizeof(str_c), str_b); //strcpy_s(目标组,目标组大小,源组)
puts(str_c);


//字符串尾追加字符串
strcat_s(str_b,sizeof(str_b),str_x); //strcat_s(目标组,目标组大小,源组)
puts(str_b);


//ASK码比较字符串大小
int j = strcmp(str_x, str_b);
printf("str_x campare with str_b %d\n",j);
//strcmp依照阿斯克码表进行比较,比较的大小结果并非实际字符长度大小,实际用途不明

return 0;
}

函数 功能 返回值 用法示例 注意事项
strlen 计算字符串长度 返回字符串长度,不含 \0 size_t len = strlen(str); 只计算 \0 之前的字符,不包括 \0,且传入字符串必须以 \0 结尾
strcpy_s 安全地将源字符串复制到目标字符串 返回目标字符串指针 strcpy(dest,sizeof(dest), src); 目标缓冲区必须足够大以容纳源字符串和 \0,否则失败
strcat_s 安全地将源字符串追加到目标字符串后 返回目标字符串指针 strcat(dest,sizeof(dest), src); 目标缓冲区必须包含现有字符串、源字符串和 \0,否则失败
strcmp 比较两个字符串 0:相等,正数:大于,负数:小于 int cmp = strcmp(str1, str2); 按字典顺序比较,区分大小写,比较到第一个不同的字符即停止

指针

标准代码架构

1
2
ooo

标准代码架构

1
2
ooo

标准代码架构

1
2
ooo

函数

标准代码架构

1
2
ooo

标准代码架构

1
2
ooo

标准代码架构

1
2
ooo

C++引用

标准代码架构

1
2
ooo

  • Title: C_Note
  • Author: Slience_Displace
  • Created at: 2024-10-14 00:00:00
  • Updated at: 2024-10-21 21:25:53
  • Link: https://mikumikudaifans.github.io/Displace.github.io/2024/10/14/C_Note/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments