目录
- 基本了解C语言的基础知识,对C语言有一个大概的认识。
- 每个知识点就是简单认识,不做详细讲解。
1.什么是C语言
- C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易 的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
- 尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的 C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。
- 二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制 定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。 [1] 目前2011年12月8 日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉 字编程。
- C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。
- 其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。
2.第一个C语言程序
//在屏幕上打印hello,world
#include<stdio.h>
int main()
{
printf("hello,world");
return 0;
}
- #include<stdio.h>(引入头文件):st(标准)d(输入)i(输出) ,stdio.h(标准输入输出头文件)
- int(整型):main函数运行结束后,返回一个整型的值,与后面的return呼应
- main(主函数):程序的入口,一个程序有且仅有一个main函数,使用前一定要包含头文件 stdio.h
- printf(打印):输出函数,引号中为输出的内容,是一个库函数
- return 0:0就是一个整型,在main运行结束后被返回
3.数据类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
//打印各数据类型的大小
#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));
return 0;
}
- %d:打印10进制的整型
- \n:表示换行
- sizeof():运算符(操作符),运算括号内数据类型的大小,单位为type(字节)
注意:存在这么多的类型,其实是为了更加丰富的表达生活中的各种值。
数据类型的使用
char ch = 'w'; char:定义一个常量为一个字符,字符可以是字母、数字或符号,字符在‘’内
int weight = 120;
int salary = 20000;
4.变量、常量
- 生活中的有些值是不变的(比如:圆周率,性别,身份证号码,血型等等)
- 有些值是可变的(比如:年龄,体重,薪资)
- C语言中把这种可变的值叫做变量,不可变的值叫做常量
4.1定义变量的方法
int age = 150;
float weight = 45.5f; 编译器认为一位小数就是double,所以加f
char ch = 'w';
4.2变量的命名
- 只能由字母(包括大写和小写)、数字和下划线( _ )组成。
- 不能以数字开头。 长度不能超过63个字符。
- 变量名中区分大小写的。
- 变量名不能使用关键字。
4.3变量的分类
- 局部变量(大括号里的)
- 全局变量(大括号外的)
#include <stdio.h>
int global = 2019;//全局变量
int main()
{
int local = 2018;//局部变量
//下面定义的global会不会有问题?
int global = 2020;//局部变量
printf("global = %d\n", global);
return 0;
}
总结:
- 上面的局部变量global变量的定义其实没有什么问题的!
- 当局部变量和全局变量同名的时候,局部变量优先使用。
变量的使用
计算两个数的和
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
int sum = 0;
scanf("%d %d", &a, &b);
sum = a + b;
printf("sum=%d", sum);
return 0;
}
- 输入(scanf):定义三个整型,&为取地址符号
- 计算:定义计算,定义计算不能在输入前,因为输入前如果计算,sum值已经得出,输入内容就无效了
- 输出:“sum=%d”这样写的原因是结果显示为sum=...
4.4变量的作用域和生命周期
作用域
-
程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效可用的,而限制这个名字的可用性的代码范围就是这个名字的作用域。
- 局部变量的作用域是局部变量所在的局部范围;
- 全局变量的作用域是整个工程。
生命周期
- 变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。
- 局部变量的生命周期:进入局部变量所在的范围(作用域)生命周期开始,出作用于生命周期结束;
- 全局变量的生命周期:整个程序的生命周期,也就是main函数的生命周期。
4.5常量
C语言中的常量和变量的定义形式有所差异。
C语言中的常量分为以下4种:
- 字面常量
- const修饰的常变量(具有常量属性的变量)
- #define定义的标识符常量
- 枚举常量
字面常量
- 如100(字面常量) 3.14(字面常量) "abc"(字符串常量) 'w'(字符常量)
const修饰的常变量
- 当一个变量的值不想被修改,用const“保护”起来就行了,此时的变量变成了常变量,但是其实质仍然是变量,常量的某些性质仍然不具备。
const int a = 1;
a = 2;
因为已经定义a为常变量,所以这里再次定义a,系统会报错
#define定义的标识符常量
如#define MAX 100 ,此后在程序中出现MAX就代表了100,如果需要将程序中100数值全部改变,一个一个改太不方便,而用了#define MAX 100 ,只需要将MAX后面的100改成你想要的数字,后面程序中都会改变,这样就方便多了。
#define MAX 100
printf("%d", MAX);
效果
枚举常量
语法:enum Sex{Male,Female,Securt};
enum Sex a = Female
enum Sex {
Male,Female,Secret
};
printf("%d\n", Male);
printf("%d\n", Female);
printf("%d\n", Secret);
第一个Male默认是1
效果
enum Sex {
Male=1,Female,Secret
};
printf("%d\n", Male);
printf("%d\n", Female);
printf("%d\n", Secret);
将Male设置为1
效果
5.字符串+转义字符
5.1字符串
"hello world.\n"
- 这种由双引号引起来的一串字符称为字符串字面值,或者简称字符串。
- 注意:字符串的结束标志是一个\0的转义字符,在计算字符串长度的时候\0是结束标志,不算作字符串内容,但是算作数量
- "bit"和'b''i''t'的区别是前者中有\0而后者没有
5.2转义字符
转义字符顾名思义就是转变意思。 下面看一些转义字符。
转义字符 | 释义 |
\? | 在书写连续多个问号时使用,防止他们被解析成三字母词 |
\' | 用于表示字符常量' |
\" | 用于表示一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符。 |
\a | 警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符(Tab) |
\v | 垂直制表符 |
\ddd | ddd表示1~3个八进制的数字。 如: \130 X |
\xdd | dd表示2个十六进制数字。 如: \x30 0 |
进制转换
下面我们简单介绍一下,'\ddd' 和 '\xdd'这两个转义字符:
例如八进制数130能转换成十进制数88,而依据下表88表示X所以\130表示X,\xdd同理
strlen():strlen()是一个库函数,使用前要包含<string.h>,在求字符串长度的时候,只算'\0'之前的部分
#include<stdio.h>
#include<string.h>
int main()
{
printf("%d\n", strlen("abcdef"));
printf("%d\n", strlen("c:\test\628\test.c"));
return 0;
}
效果
6.注释
- 代码复杂时最好加上注释,利己利他;
- 代码暂时不要的时候也可以注释掉。
- C语言风格的注释:/* ... */
- C++风格的注释: //...
- 注意C语言风格的注释缺陷是不能嵌套注释,C++风格的注释好处是可以注释一行,也可以注释多行,所以在这里就不用说了,比这当然建议铁汁们用C++风格的注释。
7.选择语句
语法:if(){};else if(){};else(){};
int coding = 0;
printf("你会去敲代码吗?(选择1or0);>");
scanf("%d", &coding);
if (coding == 1)
{
printf("坚持,你会有好offer!\n");
}
else
{
printf("没了没了,回家卖红薯...\n");
}
输入1,效果
输入0,效果
8.循环语句
- while语句-简单讲解
- for语句(后面详细介绍)
- do...while语句(后面详细介绍)
printf("好好敲代码\n");
int line = 0;
while (line <= 10)
{
line++;
printf("我要继续努力敲代码\n");
}
if (line > 10)
{
printf("好offer\n");
}
效果
9.函数
上面讲了main函数,也就是主函数。一个工程中,主函数有且只有一个。
函数,什么是函数呢?
数学中有函数,如f(x) = 2*x + 1功能是求2x + 1的值
f(x,y) = x + y功能是求x + y的值
C语言把一些独立的功能封装成一个个函数,供使用者调用。
#include<stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("请输入两个整数:\n");
scanf("%d %d", &num1, &num2);
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
上述代码,写成函数如下:
#include<stdio.h>
//函数定义
int Add(int x, int y)//int是返回类型,Add是函数名,x和y是函数的形式参数
{
//大括号里面的内容是函数体
int z = x + y;
return z;
}
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("请输入两个整数:\n");
scanf("%d %d", &num1, &num2);
sum = Add(num1, num2);//函数调用
printf("sum = %d\n", sum);
return 0;
}
函数的特点就是简化代码,方便代码复用,即如果需要,直接调用即可 。
10.数组
10.1数组定义
数组的定义:一组相同类型元素的集合
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
char ch1[] = { 'a','b' };
char ch2[] = "ab" ;
定义一个容量为10的数组,如果后面填的不够十个,则为默认值0
10.2数组的下标
C 语言规定:数组的每个元素都有一个下标, 下标是从0开始的 。
数组可以通过下标来访问的
比如:
int array[10] = {1,2,3,4,5,6,7,8,9,10};
//该数组是10个元素,下标的范围是0-9
10.3数组的使用
例子:
int i = 0;
int arr[10] = { 0 };
while (i < 10)
{
scanf("%d", &arr[i]);
i++;
}
i = 0;
while (i < 10)
{
printf("%d", arr[i]);
i++;
}
输入:
1 3 5 7 9 2 4 6 8 10
输出:
1 3 5 7 9 2 4 6 8 10
11.操作符
C语言中包含了非常丰富的操作符,所以有人说,C语言是非常灵活的。
算数操作符
+ - * / %
这里先简单介绍一下特别容易出错的/ 和 %
- / : double ret = 7 / 2; 结果是3.000000(暂时先不用管为什么小数点后面那么多0),实际上我们想要的结果是3.5, 那该怎么办呢?改成double ret = 7.0 / 2; 或者改成double ret = 7 / 2.0;
- %:取模,也叫求余,一定要注意的是取模操作符只能应用于整数哦,浮点数是不可以的,这点一定要注意。比如:7 % 2 = 1;(商3,余1)
赋值操作符
= += -= *= /= &= ^= |= >>= <<=
这里介绍前五个
= :是用来初始化如int a = 0;或者赋值 a =0;
+= :a+=3等同于a=a+3
后面的同理
单目操作符
! 逻辑反操作
- 负值
+ 正值
& 取地址(不介绍)
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反(不介绍)
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)(不介绍)
(类型) 强制类型转换
- 单目操作符:操作数只有一个,比如a=+a只有一个操作数,所以这里+叫单目操作符:
- 双目操作符:2 + 3 ,和3就是操作数,由于‘+’有两个操作数,所以叫双目运算符。
!:在C语言中0为假,非0为证真。if(a)的括号中如果a为真,则操作,为假不操作
而如果a=0为假,则!a则为真,同理如果a=1为真,则!a为假
- :如果a=1,则-a等于-1
+ :与-同理,没啥用
sizeof:求大小,单位为字节,sizeof(int)为4,则int arr[3];,sizeof(arr)为4*3=12
--:分为前置和后置,前置表示先操作后显示,如int a = 10;b=--a;则打印b,a的结果为9,9
后置表示先显示后操作,如int a = 10;b=a++;则打印b,a的结果为10,11
++:和--同理
(类型) 强制类型转换:int a = 1.1编译器会报错,但可int a =(float)1.1则不会报错
关系操作符
>
>=
<
<=
!= 相当于“不等于”
== 相当于“等于”
逻辑操作符
&& 逻辑与:并且 age>=18&&<=30
|| 逻辑或:或者 age<=18||>=30
条件操作符(三目操作符)
条件?a:b:如果条件以为真则输出a,假输出b,例
m=(a>b?a:b)表示输出a、b中的较大者
逗号表达式
m=(a+=3,b=a-5,c=a+b)表示的是里面的式子依次计算,输出的是最后一个式子的值
下标引用操作符和函数调用操作符
12.常见关键字
12.1关键字 typedef
12.2关键字static
在C语言中, static是用来修饰变量和函数的
- 修饰局部变量-称为静态局部变量
- 修饰全局变量-称为静态全局变量
- 修饰函数-称为静态函数
12.2.1修饰局部变量
普通局部变量是再熟悉不过的变量了,在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。
普通局部变量存储于栈区,使用完毕会立即释放。
一个普通的局部变量是放在栈区的,而被static的修饰的局部变量,是放在内存的静态区的存储位置发生了变化,使得局部变量出了作用域不会销毁,影响了变量的生命周期作用域不受影响
静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。
变量在全局数据区分配内存空间;编译器自动对其初始化
其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束
void test()
{
static int a = 1;//静态变量
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}
效果
2 3 4 5 6 7 8 9 10 11
12.2.2 修饰全局变量
一个全局变量在整个工程中都可以使用
全局变量是具有外部链接属性的,在其他源文件内部只要适当地声明就可以使用
static修饰全局变量这时全局变量的外部链接属性就变成了内部链接属性,只能在自己所在的.c文件内部使用,其他.c文件无法使用
static修饰全局变量影响了变量的作用域
//代码1
//add.c
int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0;
}
//代码2
//add.c
static int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0;
}
代码1正常,代码2在编译的时候会出现连接性错误。
结论:
一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使 用。
12.2.3 修饰函数
修饰函数和修饰全局变量类似
函数是具有外部链接属性的,static 修饰函数 后,函数的外部链接属性就变成了内部链接属性,被static修饰的函数只能在自己所在的.c文件内使用,其他.c文件无法使用
static修饰函数最终相当于影响了作用域
//声明外部符号 - 函数
extern int Add(int, int);
int main()
{
int a = 10;
int b = 20;
int sum = Add(a, b);
printf("%d\n", sum);
return 0;
}
12.3关键字register
register表示寄存器,寄存器是计算机读取最快的存储设备
register int a = 100;是建议编译器将a等于100放在寄存器中存储,但编译器会根据a的使用频率等情况自行决定是否存储在寄存器中
13.define 定义常量和宏
#define M 100
#define STR "hello bit"
#define MAX(x, y) ((x)>(y)?(x):(y))
int main()
{
printf("%d\n", M);
printf("%s\n", STR);
int a = 10;
int b = 20;
int m = MAX(a+3, b);
//int m = (a > b ? a : b);
printf("%d\n", m);
return 0;
}
前面define
- 定义了常数M为100,后面的printf("%d\n", M)就相当于printf("%d\n", 100)
- 定义了STR,后面的printf("%s\n", STR)就相当于printf("%s\n", hello bit)
- 定义了宏MAX(x, y) ((x)>(y)?(x):(y)),后面的int m =MAX(a+3, b)就相当于int m = (a > b ? a : b)
14.指针
14.1内存
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的。
所以为了有效的使用内存,就把内存划分为一个个小的内存单元,每个内存单元的大小是1个字节。
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
14.2 指针变量的大小
32位的计算机有32根地址线(电线),每根电线能发出数字信号(0或1),即输出一个32位的二进制数,所以地址占4个字节的空间,而十六进制的一位数可以表示二进制数的四位数,所以32位计算机的地址为8位十六进制数。
同理64位的计算机地址占8个字节,地址位16位的十六进制数
#include<stdio.h>
int main()
{
int num = 10;//num要在内存空间
#// 取出num的地址,地址也称为指针,注意这里num是一个整型变量,4个字节,每个字节都有地址
//但是取出的是第一个字节的地址(较小的地址)
printf("%p\n", &num);//%p是以第一个内存空间的地址的形式进行打印
int* p = #
*p = 20;//p是用来存放地址的,p是一个指针变量
return 0;
}
15.结构体
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型
人:复杂对象(名字 + 年龄 + 性别 + ...);
书:复杂对象(书名 + 作者 + 出版社 + ...)
#include<stdio.h>
int main()
{
struct Stu//结构体类型
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
};
//结构体初始化
struct Stu s = { "小高", 20, "未知" };
//'.'为结构体成员访问操作符 用法:结构体变量 . 结构体成员
printf("name = %s age = %d sex = %s\n", s.name, s.age, s.sex);
//'->'操作符
struct Stu* ps = &s;
printf("name = %s age = %d sex = %s\n", (*ps).name, (*ps).age, (*ps).sex);
printf("name = %s age = %d sex = %s\n", ps->name, ps->age, ps->sex);
//注意'.'和'->'都是结构体成员访问操作符
return 0;
}
创建 Stu 后 {} 外有一个 ;