C语言知识点

空格

打空格!!!

逗号后面要打空格

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

int main (void) {
int a, b, c, d;
scanf ("%d%d", &a, &b);
printf ("%d %d", a, b);
return 0;
}

运算符前后要打空格

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

int main (void) {
int a = 1, b = 2;
if (a < b) {
printf ("%d", a);
} else {
printf ("%d", b);
}
return 0;
}

for循环里的分号后面要打空格

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

int main (void) {
int i;
int a[5] = {3, 5, 4, 1, 2};
for (i = 0; i < 5; ++i) {
printf ("%d ", a[i]);
}
return 0;
}

小括号和花括号之间要打空格

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

int main (void) {
int i;
for (i = 0; i < 5; ++i) {

}
return 0;
}

双斜杠注释后面打空格

1
// 双斜杠和这句话中间有空格

其他还有什么地方要打空格自己意会

基础

C主框架

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

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

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

1
2
3
4
5
void main()
{
/*****************
*****************/
}

主函数也可由其他类型定义,如voidsigned等,但一般不常见且在一些情况下可能报错。以上为以void做主函数头(无需返回值)。

头文件

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型)

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

int main()
{
int a = 9;
int b = -3;

double c = 12.5;
float d = -5.123;

printf("%d %d %lf %f\n", abs(a), abs(b), fabs(c), fabs(d));

int aa = sqrt(a);
int bb = pow(b, 3); // -3的3次方

printf("%d %d", aa, bb);

return 0;
}

输出如下:

1
2
9 3 12.5 5.123
3 -27

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的尾部

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

int main()
{
char a[6] = "Hello";
char b[6] = "World";
char c[6] = "55555";

printf("%d\n", strlen(a));

int res = strcmp(a, b);
if (res < 0)
printf("小于\n");
else if (res == 0)
printf("等于\n");
else
printf("大于\n");

strcpy(c, b);

strcat(a, c);

printf("%s", a);

return 0;
}

输出如下:

1
2
3
5
小于
HelloWorld

输出

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

int main()
{
printf("Hello World");
printf("%d", 6);

return 0;
}

注释

  • // 单行注释

  • /**/ 整段注释

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

int main()
{
//printf("Hello World");
//printf("Hello World");
//printf("Hello World");
//printf("Hello World");

/*
printf("Hello World");
printf("Hello World");
printf("Hello World");
printf("Hello World");
printf("Hello World");
printf("Hello World");
printf("Hello World");
printf("Hello World");
printf("Hello World");
printf("Hello World");
*/

return 0;
}

#define定义标识符

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

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

1
2
3
4
5
6
7
8
9
#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
#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
#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;
}

输出如下:

1
0 5 3.14 2.2

变量和常量

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

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

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

1
2
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+386 位有效位
double双精度浮点数8字节2.3E-308 到 1.7E+30815 位有效位
long double长双精度浮点数16字节3.4E-4932 到 1.1E+493219位有效位

unsigned

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

有符号整型数据存储单元中最高位代表数值的符号,如果指定为无符号型,不能存放负数,如 -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
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表示浮点数)必须与后面参数的类型和数量相匹配。如果格式字符串与参数不匹配,可能会导致未定义的行为或输出错误。

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

int main()
{
char a;
int b;
float c;
double d;
long long e;
char f[10];

/*
%d 十进制有符号整数
%lld long long整数
%u 十进制无符号整数
%f 浮点数
%lf 双精度浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x,%X 无符号以十六进制表示的整数
%0 无符号以八进制表示的整数
%g 自动选择合适的表示法
*/

scanf("%c %d %f %lf %lld %s", &a, &b, &c, &d, &e, f); // 输入时变量要加取地址符(&),字符串不用,详见指针

/*
%nd 表示输出n位整型数,不够n位右对齐
%.nf 表示小数点后保留n位
%n.mf 表示输出场宽为n+m的浮点数,其中小数位为m,整数位为n,小数点占一位不够n+m位右对齐
%0nd 表示在输出一个小于n位的数值时,将在前面补0使其总宽度为n位
*/

printf("%8d%8d%8d\n", b, b*10, b*100);
printf("%8.2f%8.2f%8.2f\n", c, c*10, c*100);
printf("%08lld%08lld%08lld", e, e*10, e/10);

return 0;
}

输入:

1
a 25 3.456 12.3456 111 hello

输出如下

1
2
3
      25     250    2500
3.46 34.56 345.60
000001110000111000000011

表达式

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

运算符

  • 算术运算符+ - * / %
  • 赋值运算符:C语言中的赋值运算符=用于将一个表达式的值赋给变量。此外,C语言还支持复合赋值运算符,如+=-=*=/=%= 等,这些运算符可以简化赋值和算术运算的组合。
  • 自增自减运算符:C语言中的自增++和自减 -- 运算符用于将变量的值增加或减少1。这些运算符只能用于变量,不能用于常量或表达式。
  • 位运算符<<>>^&|

优先级

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

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

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

语句

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

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

选择结构

if-else if- else判断结构

大括号

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

这是一个if语句,如果表示条件的逻辑表达式的结果不是0,那么就执行后面跟着的这对大括号内的语句;否则就跳过不执行,继续下面的其他语句。

但是if语句还有一种形式可以不用{}。

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

if语句这一行结束的时候并没有表示语句结束的”;”,而后面的赋值语句写在if的下一行,而且缩进了,在这一行结束的时候有一个分号。

表明这条赋值语句是if语句的一部分,if语句拥有和控制这条赋值语句,决定其是否被执行。

简单地说就是if(逻辑表达式)后要么跟上”{“,要么跟上语句,不能直接写分号。

**总结:**有大括号的时候 条件满足的情况执行所有括号内语句,无大括号的时候 条件满足执行最近邻语句。

关系运算符

< >= < <=

!= 用于测试“不相等”

== 用于测试“相等”

逻辑运算符

&&

​ 逻辑与 理解为: 即 怎么 又 怎么 一假全假,全真为真

||

​ 逻辑或 理解为: 要么 怎么 要么 怎么 一真为真, 全假为假

​ 逻辑非 真取假 假取真

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>
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
{
printf("少年\n");
}
else if (age >= 18 && age < 30)
{
printf("青年\n");
}
else if (age >= 30 && age < 50)
{
printf("中年\n");
}
else if (age >= 50 && age < 80)
{
printf("老年\n");
}
else
{
printf("老寿星\n");
}
return 0;
}

switch-case选择结构

switch语句也是一种分支语句。 常常用于多分支的情况。else if 语句也能实现多分支情况,但在某些情况下使用else if来实现,会使代码过于复杂。

1
2
3
4
5
6
switch(整型表达式)
{
//在一个 switch 中可以有任意数量的 case 语句。
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
#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。相当于if-else中的:

1
2
3
4
5
6
7
8
if (a)
{
b;
}
else
{
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
int cmp (int a, int b)
{
return a > b ? a * 2 : b + a + b / 2;
}

布尔变量

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

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

C语言标准库不自带bool类型,需要引用stdbool.h头文件或用typedef手动定义:

1
#include<stdbool.h> 

1
typedef enum {false, true} bool;

应用示例:

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

int main()
{
bool x = false; // 变量初始化

if(x == true) // 条件语句
{
printf("x的值为真");
}
else
printf("x的值为假");

return 0;
}
1
x的值为假

循环结构

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

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)
{
语句;
}

表达式1 ⽤于循环变量的初始化 ,表达式2 ⽤于循环结束条件的判断 ,表达式3 ⽤于循环变量的调整,三种表达式都可以省略,但分号不能省略。

for循环和while循环可以相互转换。二者没有性能上的差别。实际开发中,根据具体结构的情况,选择哪个格式更合适、美观。

break、continue

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

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 对应的头文件。

自定义函数

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

​ 例:写一个函数可以找出两个整数中的最大值。

1
2
3
4
int cmp(int x, int y)
{
return (x > y) ? (x) : (y);//三目运算符:x大于y返回x,x小于y返回y
}

定义和使用

一个在两个数中返回最大值的函数:

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

int cmp(int x, int y)
{
return (x > y) ? (x) : (y);//三目运算符:x大于y返回x,x小于y返回y
}

int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);

int max = cmp(num1, num2);

printf("max = %d\n", max);

return 0
}

输入:

1
10 20

输出如下:

1
max = 20

函数可以先声明后定义

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

int cmp(int x, int y);

int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);

int max = cmp(num1, num2);

printf("max = %d\n", max);

return 0
}

int cmp(int x, int y)
{
return (x > y) ? (x) : (y);//三目运算符:x大于y返回x,x小于y返回y
}

在以上的代码中,int cmp(int x, int y);先将函数声明,这样的语句叫做函数原型。

声明即告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。

创建 C 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。

调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。

返回类型、函数名、形参、实参、返回

C 语言中的函数定义的一般形式如下:

1
2
3
4
return_type function_name( parameter list )
{
body of the function
}
  • **返回类型:**一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void
  • **函数名称:**这是函数的实际名称。函数名和参数列表一起构成了函数签名。
  • 参数:当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
  • **函数主体:**函数主体包含一组定义函数执行任务的语句。

局部变量与全局变量

任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。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
#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
type arrayName [ arraySize ];

这叫做一维数组。arraySize 必须是一个大于零的整数常量,type 可以是任意有效的 C 数据类型。

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
#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
#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;
}

输出如下:

1
数组长度为: 5

多维数组

C 语言支持多维数组。多维数组声明的一般形式如下:

1
type name[size1][size2]...[sizeN];

多维数组最简单的形式是二维数组。一个二维数组,在本质上,是一个一维数组的列表。下面是一个二维数组,包含 3 行和 4 列:

1
int x[3][4];

初始化二维数组

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

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

这样也是一样的:

1
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

二维数组可以用嵌套的两个循环来遍历:

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

int main ()
{
/* 一个带有 5 行 2 列的数组 */
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}};
int i, j;

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

输出如下:

1
2
3
4
5
6
7
8
9
10
a[0][0] = 0
a[0][1] = 0
a[1][0] = 1
a[1][1] = 2
a[2][0] = 2
a[2][1] = 4
a[3][0] = 3
a[3][1] = 6
a[4][0] = 4
a[4][1] = 8

字符串(字符数组)

字符串实际上是使用空字符 \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
#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()

读取一个字符,包括任何字符。

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

int main()
{
char a = getchar();

printf("%c\n", getchar());
printf("%c\n", a);

reutnr 0;
}

输入:

1
abcdefg

输出如下:

1
2
3
b
a

  • gets()

读取整行输入,直至遇到换行符,然后把换行符,储存其余字符,并在这些字符的末尾添加一个空字符使其成为一个 C 字符串。

1.gets()函数不安全。
2.C11标准委员会已经将其废除,建议能不用尽量不用。

1
2
3
4
5
6
7
8
#include <stdio.h>
int main() {
char str[100];

gets(str); // 从标准输入流中读取一行字符
printf("%s\n", str);
return 0;
}

输入:

1
Hello World!

输出如下:

1
Hello World!
  • %[^\n]

%[^\n]是一种输入方法,用到了正则表达式相关用法。它代表输入至换行符时停止。同样的,%[^1]表示输入到1停止,以此类推。

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main() {
char str[100];

scanf("%[^1]", str);

printf("%s\n", str);
return 0;
}

输入:

1
xxxxxxxxxxxxxxxxxxx1

输出如下:

1
xxxxxxxxxxxxxxxxxxx

指针

(能理解多少就理解多少,知道地址与变量的关系就行)

指针-菜鸟驿站

指针-CSDN

取地址符

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

下面一个例子输出变量的地址:

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

int main ()
{
int a = 10;
int *p; // 定义指针变量
p = &var_runoob;

printf("a 变量的地址: %p\n", p);
return 0;
}

输出如下:

1
a 变量的地址: 0x7ffeeaae08d8

指针与地址

取内容符

指针变量定义格式:存储类型 数据类型 指针变量名;

int *p: 定义了一个指针变量p,指向的数据是int类型的:

1
2
3
4
5
6
7
8
int a = 5;
int *p = &a;
char c='v';
char *q=&c;
printf("%p %p\n", p, &a);
printf("%p %p\n",q,&c);
printf("%d %d\n",a,*p);
printf("%c %c\n",c,*q);

访问指针所指向空间的内容用取内容运算符*

那么p变量存放的就是a的地址,q变量存放的是c的地址。

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

指针与数组

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

1
int myArray[5] = {10, 20, 30, 40, 50};

在这里,myArray 是数组名,它表示整数类型的数组,包含 5 个元素。myArray 也代表着数组的地址,即第一个元素的地址。

数组名本身是一个常量指针,意味着它的值是不能被改变的,一旦确定,就不能再指向其他地方。

我们可以使用&运算符来获取数组的地址:

1
2
int myArray[5] = {10, 20, 30, 40, 50};
int *ptr = &myArray[0]; // 或者直接写作 int *ptr = myArray;

在上面的例子中,ptr 指针变量被初始化为 myArray 的地址,即数组的第一个元素的地址。

需要注意的是,虽然数组名表示数组的地址,但在大多数情况下,数组名会自动转换为指向数组首元素的指针。这意味着我们可以直接将数组名用于指针运算,例如在函数传递参数或遍历数组时:

1
2
3
4
5
6
7
8
9
10
11
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]); // 数组名arr被当作指针使用
}
}

int main() {
int myArray[5] = {10, 20, 30, 40, 50};
printArray(myArray, 5); // 将数组名传递给函数
return 0;
}

在上述代码中,printArray 函数接受一个整数数组和数组大小作为参数,我们将 myArray 数组名传递给函数,函数内部可以像使用指针一样使用 arr 数组名。

指针与函数

传递指针给函数

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

下面的实例中,我们传递一个无符号的 long 型指针给函数,并在函数内改变这个值:

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

void getSeconds(unsigned long *par);
int main ()
{
unsigned long sec;
getSeconds( &sec );
/* 输出实际值 */
printf("Number of seconds: %ld\n", sec );
return 0;
}
void getSeconds(unsigned long *par)
{
/* 获取当前的秒数 */
*par = time( NULL );
return;
}

输出如下:

1
Number of seconds :1294450468

结构体

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

声明

定义和声明结构体的同时创建变量:

1
2
3
4
5
struct Student {
char name[20];
int age;
float score;
} stu; // 创建了一个名为stu的结构体变量

先定义结构体,然后声明变量:

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

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

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

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

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

在结构体内部不初始化成员,而是在创建结构体变量后初始化:

1
2
3
4
5
struct Student {
char name[20];
int age;
float score;
} stu = {"Tom", 18, 90.5f}; // 在定义变量的同时进行初始化

访问

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

1
2
3
4
5
6
7
8
9
10
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); // 另一种访问结构体成员的方式

在结构体数组中存储数据:

1
2
3
4
5
struct Student {
char name[20];
int age;
float score;
} stu[3]; // 创建了一个结构体数组,可以存储3个学生的信息

使用结构体指针访问结构体数组:

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

p = stu;
printf("%s\n", (p+1)->name); // 访问第二个学生的名字

在结构体中使用结构体类型成员:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Date {
int year;
int month;
int day;
};

struct Student {
char name[20];
struct Date birthday;
float score;
};

struct Student stu = {"Tom", {1999, 12, 31}, 90.5f};
printf("%d\n", stu.birthday.year); // 访问学生的出生年份

链表-结构体指针

结构体链表

—end—