【C语言入门学习】[1]初识C语言 01

2024.1.9更新

2024.2.20更新

#前言

什么是C语言?

  • C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。
  • ANSI C,作为C语言最初的标准
  • C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。
  • 其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C
  • C语言介于机器语言和高级语言之间

一、基本概念

一、c语言的基本框架

  • main函数是程序的入口
  • return 0;函数正常运行结束时返回0

二、c语言的数据类型

  • char //字符数据类型
  • short //短整型
  • int //整形
  • long //长整型
  • long long //更长的整形
  • float //单精度浮点数
  • double //双精度浮点数
  • C语言有没有字符串类型?
    add[]="String"

每种字符类型对应的字节大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
printf("%d\n", sizeof(char));
printf("%d\n", sizeof(short));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(long));
printf("%d\n", sizeof(long long));
printf("%d\n", sizeof(float));
printf("%d\n", sizeof(double));
printf("%d\n", sizeof(long double));
return 0;
}

输出结果:
1
2
4
4
8
4
8
8 最大为8个字节 2的64次方(64位系统)
对于计算机内存的解释,见:

三、变量的作用域和生命周期

作用域

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用

而限定这个名字的可用性的代码范围就是这个名字的作用域。

  1. 局部变量的作用域是变量所在的局部范围。
  2. 全局变量的作用域是整个工程。

生命周期

变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段

  1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
  2. 全局变量的生命周期是:整个程序的生命周期。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//作用域
//局部变量的作用域:就是变量所在的局部范围
//全局变量的作用域:整个工程


int g_val = 2021;//全局变量

int main()
{
printf("1:%d\n", g_val);
printf("hehe\n");
{
printf("2:%d\n", g_val);

int a = 10;
printf("a = %d\n", a);
}
printf("3:%d\n", g_val);

return 0;
}

#extern(关键字):

1
2
3
4
5
6
7
8
9
//声明一下变量
extern int g_val;

int main()
{
printf("%d\n", g_val);

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//生命周期
//变量的生命周期:变量的创建和销毁之间的时间段

//局部变量的生命周期:进入局部范围生命开始,出局部范围生命结束
//全局变量的生命周期:程序的生命周期
int main()
{
{
int a = 10;//a创建
printf("%d\n", a);
}
//a销毁
return 0;
}

#define/const和enum

define 和const的区别

1.编译器处理阶段

define是预处理器预处理阶段完成,const是编译器开始编译程序阶段完成,因此#define先于const处理。
2.语法语义方面

define是宏定义,特点是简单原位做替换,其定义的常量值没有类型限定,也不做类型检查,在出现宏名称的地方直接展开。
const是关键字,本质上会定义一个只读变量,不可以更改,编译是检查常量值的类型是否匹配。

例如:

define PI 3.14159
int r = 25;
double s = rrPI;
r = 30;
s = rrPI;
预处理完成以后的代码是:
int r = 25;
double s = rr3.14159;
r = 30;
s = rr3.14159;
define明显是直接替换,PI出现几次,其数值3.14159出现几次。
// 必须指定正确的类型
const double PI = 3.14159 ;
int r = 25;
double s = rrPI;
r = 30;
s = rrPI;
const明显是声明和定义一个变量,分配内存空间保存3.14159的数值,以后使用时和普通变量一样取值,但是无法对其进行赋值修改。
3.#define宏只做替换,不做表达式计算,如果#define定义的不是单个数值,而是一个常量表达式,建议加上圆括号,避免出错。
例如:定义常量表示每个元素的大小是int+double型大小之和。
define N sizeof(int) + sizeof(double)
int m = 100;
// 根据输入的m变量值计算总的空间大小
int total = mN;
这是错误的,因为替换以后int total= m
sizeof(int) + sizeof(double);
正确写法是:
define N (sizeof(int) + sizeof(double))
展开以后:
int total = m*(sizeof(int) + sizeof(double));
使用const不存在以上问题,const会对表达式先计算。
const int N = sizeof(int) + sizeof(double);
int m = 100;
// 根据输入的m变量值计算总的空间大小
int total = m*N;

代码示例

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
#define MAX 10000

int main()
{
//1. 字面常量
//3.14;
//10;
//'a';
//"abcdef";

//2. const修饰的常变量
//const int num = 10;//num就是常变量 - 具有常属性(不能被改变的属性)
//num = 20;
//printf("num = %d\n", num);//20

//int arr[10] = {0};//10个元素
//
//const int n = 10;
//int arr2[n] = {0};//n是变量的,这里是不行

//3. #define 定义的标识符常量
//MAX = 20000;//err
/*int n = MAX;
printf("n = %d\n", n);*/


return 0;
}

性别
enum Sex
{
//这种枚举类型的变量的未来可能取值
//枚举常量
MALE = 3,//赋初值
FEMALE,
SECRET
};

int main()
{
//4. 枚举常量
//可以一一列举的常量

enum Sex s = MALE;
//MALE = 3;//err
printf("%d\n", MALE);
printf("%d\n", FEMALE);
printf("%d\n", SECRET);

return 0;
}

#字符串和转义字符

由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符
串。
注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容
注:使用strlen计算字符串长度时会将\0一并算入

转义字符 x #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>#include<math.h>​//写一个代码,打印100~200之间的素数//素数-质数//只能被1和他本身整除​//代码优化1://m=ab;//a和b中一定至少有一个数字是 <=开平方m的//16 = 28 = 4*4//所以,大于开平方m的就不需要判断是否为m的因子,减少循环执行次数​//sqrt用于计算开平方的函数 -需要用到库函数 math.h//减少了循环的执行次数​//代码优化2://偶数不可能是素数//修改for (i = 100; i <= 200; i )为for (i = 101; i <= 200; i += 2)​int main(){ int i, j = 0;​ //判断i是不是质数 for (i = 101; i <= 200; i += 2) { int flag = 1;//定义一个参数,检测i是否能被 除了1和它本身的数 整除​ for (j = 2; j <= sqrt(i); j) { if (i % j == 0) { flag = 0;//如果能被2到i-1之间的整除,记录flag=0; //break; } }​ if (flag == 1)//不能被2到i-1之间的数整除 { printf("%d是质数\n", i);//那么i就是质数 } } return 0;}c
? 在书写连续多个问号时使用,防止他们被解析成三字母词
用于表示字符常量’
\“ 用于表示一个字符串内部的双引号
\ 用于表示一个反斜杠,防止它被解释为一个转义序列符。
\a 警告字符,蜂鸣
\b 退格符
\f 进纸符
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ddd ddd表示1~3个八进制的数字。 如: \130 X
\xdd dd表示2个十六进制数字。 如: \x30 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
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
//字符串就是一串字符 - 用双引号括起来的一串字符

int main()
{
"abcdef";
"hello bit";

return 0;
}
#include <string.h>

int main()
{
//字符数组 - 数组是一组形同类型的元素
//字符串在结尾的位置隐藏了一个\0的字符
//\0是字符串的结束标志

//char arr[] = "hello";

char arr1[] = "abc";
char arr2[] = {'a', 'b', 'c'};

//求一下字符串的长度
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));

//int len = strlen("abc");//string length
//printf("%d\n", len);

//打印字符串
//printf("%s\n", arr1);
//printf("%s\n", arr2);

return 0;
}


int main()
{
//printf("c:\test\test.c");
printf("ab\ncd");//\+n
return 0;
}

int main()
{
//printf("(are you ok??)");//??) -- ] - 三字母词
//(are you ok]
//
//printf("%c\n", '\'');
printf("%s\n", "abc");
printf("%s\n", "a");
printf("%s\n", "\"");
printf("%s\n", "'");
printf("c:\\test\\test.c");
printf("\a");

//printf在打印数据的时候,可以指定打印的格式


return 0;
}
printf("%d", 100);
printf("%c", 'a');
printf("%s", "abc");

四、ASCII码

ASCII码一览表

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
//printf("%c\n", '\130');//8进制的130是十进制的多少呢?
//X -- ASCII码值是88
//printf("%c\n", '\101');//A - 65 - 8进制是:101
//printf("%c\n", '\x30');//48 - '0'
//printf("%d\n", strlen("abc"));//3

printf("%d\n", strlen("c:\test\328\test.c"));

return 0;
}

#C语言的注释

1
2
3
4
5
6
7
8
9
10
11
12
13
注释: 是用来解释复杂代码的


int main()
{
//int a = 10; //C++注释风格
/*
int b = 0;
*/
//C语言的注释风格 - 不支持嵌套注释

return 0;
}

#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
32
33
34
35
36
int main()
{
int input = 0;//输入的值
printf("加入比特:>\n");
printf("那要好好学习吗(1/0)?>:");
scanf("%d", &input);

if (input == 1)
{
printf("好offer\n");
}
else
{
printf("卖红薯\n");
}
return 0;
}

比特 - 30000代码 - 找一个不错的工作

int main()
{
int line = 0;
//循环
while(line<30000)
{
printf("写代码:%d\n", line);
line++;
}
if (line == 30000)
{
printf("好offer\n");
}

return 0;
}

#函数概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}

int main()
{
int num1 = 0;
int num2 = 0;
scanf("%d%d", &num1, &num2);

//int sum = num1 + num2;
//函数的方式解决
int sum = Add(num1, num2);

printf("%d\n", sum);

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
25
26
27
28
29
30
31
int main()
{
//int a = 1;
//int b = 2;
//int c = 3;
//int d = 4;

//....

//数组 - 一组相同类型的元素的集合
//10个整形1-10存起来
//数组是用下标来访问的
//*
// /
//int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//int i = 0;
//while (i < 10)
//{
// printf("%d ", arr[i]);
// i++;
//}
////char ch[5] = {'a', 'b', 'c'};//不完全初始化,剩余的默认为0

//int a = 9 / 2;
//float a = 9 / 2.0;
int a = 9 % 2;//% - 取模(余)

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

return 0;
}

#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
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
int main()
{
//关于操作符的补充
//+ - * / %
int a = 9 / 2;//整数除法
float b = 9 / 2;//整数除法
float c = 9 / 2.0;//输出为小数
printf("%d\n", a);
printf("%f\n", b);
printf("%f\n", c);//正确结果

//移位操作符
int a1 = 2;//0010,此处省略n个0...
int b1 = a1 << 1;//左移操作符,移动的是二进制位
printf("%d\n", b1);//0100
//位操作符:& 按位与 | 按位或 ^ 按位异或
//赋值操作符 += -= *= /= ...
//单目操作符:!(逻辑取反) - + &
// *:间接访问操作符(解引用操作符)
//PS: a+b 有两个操作数,此处+为双目操作符

//sizeof是一个操作符,不是函数
sizeof(a);//通常使用方法
sizeof a;

printf("%d\n", !a);//非0即真
a = -a;
printf("%d\n", a);

//mark:为什么a按位取反后,输出结果为-1;
//~
a = 0;//二进制位32个bit
printf("%d\n", ~a);//结果为-1,按位取反,位即二进制位,按位取反包括符号位(bit31),补码反码转换符号位不变
//数据在内存中存储的是补码

//int b = (++a) + (++a) + (++a);//不建议使用的表达

//强制类型转换
//int a = (int)3.14;

//&&逻辑与 ||逻辑或

//条件操作符(三目操作符)? :
int a2 = 1;
int b2 = 2;
int max = 0;

if (a2 > b2)
{
max = a2;
}
else
{
max = b2;
}
printf("%d\n", max);

max = a2 > b2 ? a2 : b2;
printf("%d\n", max);

//逗号表达式
//逗号表达式从左向右依次计算
int a3 = 0;
int b3 = 3;
int c3 = 5;
int d3 = (a3 = b3 + 3, b3 = c3 - a3, c3 = a3 + b3);
//整个表达式是结果是最后一个表达式的结果
printf("%d", d3);


//下标引用,函数调用和结构成员
//[] () , ->

//调用函数的时候,函数名后面的()
printf("hi\n");
printf("%d",100);

//-------------------------------------------------------------------------------------------------//

//C语言的关键字
//1.无法自己创建
//2.不能作变量名
//3.

{
auto int a0 = 10;//自动创建,自动销毁 -自动变量
//auto 通常省略
}
//extern用来申明外部符号
//register寄存器关键字

//频繁被使用的数据,可以存储在寄存器中,提升效率
//计算机中效率最快的是寄存器
//现代编译器会自动将数据处理到寄存器中,所以register一般不使用

register int Number = 849797;

//signed 有符号的 10 -10
//unsigned 无符号的

//static 静态的
//union 联合体(共用体)
//void 无 空

//volatile

//类型重命名
//define,include不是关键字,为预处理命令

unsigned int num11 = 100;
u_int num2 = 100;

return 0;

}

#内存本质

总结:

计算机原理补充:

变量的二进制本质上是32位bit的,最高位为符号位,用&按位取反时会改变所有位

整数在内存中存储的是补码

补码 ->原码转换不会变符号位

一个内存单元大小为一个字节,然后再分配地址

1byte = 8bit