目录
从零开始学习C语言。
一、什么是C语言
C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
二、第一个C语言程序
(1)创建项目
打开VS,创建一个新项目
找到空项目
编辑信息
注意:.c为后缀代表以C语言语法来编译代码,.cpp代表以C++的语法来进行编译
(2)接下来我们就可以进行代码的编写了,下面是一个简单的代码编写及运行结果:
对以上代码的解释:
#include<stdio.h> //编译预处理指令
int main( ) //定义主函数
{ //函数开始
printf(“Hello World!\n”); //实现了对信息“Hello World”的打印。
return 0; //返回一个值,终止 main() 函数,并返回值 0
}
需要注意的地方:
main()后面的括号()不能省
printf和return语句最后都要写上分号;
除引号“ ”内的内容,都要在英文状态下编写(包括换行符 \n)
三、数据类型
字符型:
char //字符数据类型
整型:
short //短整型
int //整形
long //长整型
long long //更长的整形
浮点型:
float //单精度浮点数
double //双精度浮点数
每种类型的大小:
sizeof是计算变量在内存的占空间的大小,单位是字节
这里顺便给出字节(Byte)与位(bit)等的关系,方便大家理解:
1字节(Byte)=8位(bit)
1 KB = 1024 B = 2^10 B
1 MB = 1024 KB = 2^20 B
1 GB = 1024 MB = 2^30 B
1 TB = 1024 GB = 2^40 B
四、变量,常量
不变的值,C语言中用常量的概念来表示,变化的值C语言中用变量来表示。
示例:
变量
1)变量的命名
*只能由字母、数字、下划线组成
*数字不能作为开头
*不能使用关键字
*区分大小写
*长度不能超过63个字符
2)变量的分类
变量分为全局变量和局部变量
怎么判断全局变量和局部变量:
在函数外部定义的是全局变量(这里的函数包括main函数)
在头文件中定义的是全局变量
在函数或语句块内部定义的是局部变量
函数的参数是该函数的局部变量
比如上方的整型变量a,它在{ }的外部,所以是全局变量;
整型变量b,它在{ }的内部,所以是局部变量。
注意:
在同一个范围内,同一个变量不能重复定义多次
变量遵循局部优先,即当全局变量和局部变量名字相同的情况下,局部优先。因此,尽量不要用相同的名字
3)变量的使用
注意:
这里引用了scanf函数,作用是等待从键盘上输入,将从键盘输入的字符转化为“输入控制符”所规定格式的数据,然后存入以输入参数的值为地址的变量中。
&为地址符,可以引用相应变量的地址,地址即为存放数据的位置。
“%d %d”输入的两个字符用空格隔开,也可用Tab或Enter隔开;若为( ,)则用逗号隔开。
4)变量的作用域及“生命周期”
作用域:
限定这个名字的可用性的代码范围就是这个名字的作用域。即哪里能用,作用域就是哪里。
下面举个例子:
如上图所示,两个名字相同的变量,但是作用域并不同。
红色矩形内的变量a的作用域在红色椭圆所示的{ }范围内;而蓝色矩形内的变量a的作用域在蓝色椭圆所示的{ }范围内。并且遵循局部优先
此外,还可以利用extern引用外部变量,引用的变量来自其他的文件。
综上:
1.局部变量的作用域是变量所在的局部范围。
2.全局变量的作用域是整个工程。
生命周期:
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
局部变量的生命周期:进入作用域 生命周期开始,出作用域 生命周期结束。
全局变量的生命周期:整个程序。
常量
常量的分类
1.字面常量
直观的可以看出的量,比如:
20,3.14,‘c’,“abc”
2.const 修饰的常变量
当我们不希望某一个变量被更改时,可以在变量语句的前面加上const
此时整型变量a就无法从100改为10了。而const修饰的a,本质是变量,但是不能直接被修改,有常量的属性。
特别注意:此时const修饰的a任然是变量,不能用在数组的[ ]中,即不能写成arr[a]。
3.#define 定义的标识符常量
此时的MAX就是一个由#define定义的标识符常量,含有一个固定值100
4.枚举常量
可以一一列举出来的
比如三原色红绿蓝
枚举常量的默认值是从0,1,2以此递增的,因此这里打印出来的值为0,1,2
五、字符串,转义字符,注释
字符串
我们用单引号’ ‘存下一个字符,若我们要存入一串字符,则需要用双引号" "来完成
注:
字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
在利用strlen()计算字符串长度时,遇到’\0’结束,但’\0’不计入长度。
转义字符
即转变字符的意思
下面是一些转义字符:
转义字符 | 释义 |
---|---|
\0 | 结束标志 |
\? | 在书写连续多个问号时使用,防止他们被解析成三字母词 |
\’ | 用于表示字符常量 ’ |
\" | 用于表示一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符。 |
\a | 警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd 表示 1~3 个八进制的数字。 如: \130 |
\xdd | dd 表示 2 个十六进制数字。 如: \x30 |
注释
- 代码中有不需要的代码可以直接删除,也可以注释掉
- 代码中有些代码比较难懂,可以加一下注释文字,作为解释
注释有两种风格:
1.C语言风格的注释
/*xxxxxx*/
缺陷:不能嵌套注释
2.C++风格的注释//xxxxxxxx
可以注释一行也可以注释多行
个人推荐第二种风格
写注释可以梳理自己的代码,让自己的思路清晰,也可以让别人更好读懂我们的代码。
六、选择语句
选择语句有if else语句,也包括switch语句,这里只简单举一个例子
这里使用了if else的选择语句。
七、循环语句
循环语句包括:
while语句
for语句
do…while语句
这里是一个for循环语句的简单例子
八、函数
维基百科中对函数的定义:子程序
比如被大量使用的库函数,还有许许多多自定义的子函数。
函数的特点就是简化代码,代码复用。这里就自定义了一个Add函数,用来计算两数是和,这样一来就方便了编写,当需要求两数和时就不需要反复写了,只需调用此子函数。
九、数组
C语言中给数组的定义:一组相同类型元素的集合
像这样,定义了一个名为arr的数组,该数组含有5个整型数据。
注意,数组的下标要从0开始,比如上面的arr数组,从arr[0]开始,并且arr[0]存放的数组为1,依次存放后面的数据。如下图:
此外,我们可以运用上面的循环语句来访问该数组中的元素:
十、操作符
C语言提供了非常丰富的操作符,使用起来比较灵活。
这里列举出部分常见操作符:
算术操作符 | + * / % |
---|---|
移位操作符 | << 左移操作符 >> 右移操作符 |
位操作符 | &按位与 ^ 按位异或 |按位或 |
赋值操作符 | = += -= *= /= &= |= ^= |
单目操作符 | ! 逻辑反操作 - 负值 + 正值 & 取地址 sizeof 操作数的类型长度(以字节为单位) ~ 对一数的二进制按位取反 – 前置、后置-- ++前置 后置++ (类型) |
关系操作符 | > < <= >= == != |
逻辑操作符 | &&逻辑与 ||逻辑或 |
条件操作符 | exp1 ? exp2 : exp3 |
逗号表达式 | exp1, exp2, exp3, …expN |
下标引用 | [ ] 下标引用操作符 |
函数调用 | ( ) |
结构成员 | . 结构体.成员名 -> 结构体指针->成员名 |
一些注意事项:
- 除号两端都是整数时,执行整数除法;若两端只要有一个浮点型数就执行浮点数除法。
- 取模操作符两端只能是整数。
- 单目操作符即只有一个操作数的操作符。
- C语言中,0表示假,非0(!0)为真。
- sizeof是一个操作符。因此sizeof(a)的括号可省,但sizeof(int)括号不可省。
- 后置++(–)先使用后自增(自减);前置则相反。
- (类型)意思是强制类型转换,比如(int)3.14就是将3.14强制转化成整型3。
- 条件操作符也是三目操作符,比如 a>b?c:d ,如果a>b为真,则执行表达式c,否则执行表达式d。
- 逗号表达式的特点是从左向右依次计算,整个表达式的结果是最后一个表达式的结果.
- 下标引用操作符[ ],比如arr[5]=10,此时[ ]才是一个操作符,arr和5就是[ ]的操作数。若像int arr[5]={ }这样,此时的[ ]不是一个操作符,仅为定义数组的语法形式。
- 函数调用操作符( ),比如Add(2,3),此时Add,2,3都是( )的操作数
十一、常见关键字
C语言提供了许多的关键字
这里对部分关键字做简单释义:
auto自动变量,可省略。
break跳出循环,常再switch语句中与case搭配使用。
数据类型也是关键字。
const常属性。
continue用于循环。
enum枚举。
struct结构体。
union联合体(共用体)。
extern声明外部符号。
register寄存器。
signed有符号—unsigned无符号。
static静态的。
typedef类型重命名。
void无(函数的返回类型,函数参数),不需要任何返回。
注意:变量名不能是关键字。
这里我们再简单讲一下两个关键字:typedef和static
关键字typedef
有时,我们在定义一个数据类型时会觉得类型名太长太麻烦,
比如 unsigned int 类型的变量,我们可以利用关键字typedef给这个类型重新定义一个比较简单的名字 uint 。
关键字static
static有三种用法:
1. 修饰局部变量-称为静态局部变量
先写一段代码,运行结果为十个1,因为此时没有static修饰局部变量a,当局部变量a出了在test函数的作用域时,就被销毁,下一个for循环引用test的时候,a又被重新赋值为0。
而当我们在变量语句前面加上关键字static时:
运行结果变成了1~10,这是因为当局部变量a被static修饰后,改变了存储位置,生命周期变成了整个程序,所以不会被销毁(但作用域不变)。这里画一个示意图供大家参考:
局部变量存放在栈区,进这个作用域创建,出作用域销毁。
被static修饰后存放在静态区,生命周期变成整个程序,程序结束才销毁。
2. 修饰全局变量-称为静态全局变量
我们创建两个源文件(text.c和add.c),在text文件中我们定义了一个全局变量g_val,在add文件中我们通过extern声明外部变量也可以正常编译
但若我们在变量前加上static,编译却没法进行了
这是因为static修饰了全局变量,使其变成了静态全局变量,作用域变成了只在该变量所在的源文件使用。
全局变量具有外部链接属性,当static修饰全局变量时,这个全局变量的外部链接属性就变成了内部链接属性,其他源文件(.c)就不能再使用这个全局变量了。
3. 修饰函数-称为静态函数
static修饰函数与修饰全局变量类似,当不用static修饰时,可以正常运行
而当用static修饰函数时,出现了熟悉的报错
这是因为static修饰函数时,也使得函数的作用域缩小,只能在当前源文件使用。
十二、#define定义常量和宏
1)#define定义标识符常量,比如:
#define MAX 1000
此时MAX就成为了一个常量,数据为1000.
2)#define定义宏,比如:
#define ADD(x, y) ((x)+(y))
#include <stdio.h>
int main()
{
int sum = ADD(2, 3);
printf("sum = %d\n", sum);
return 0;
}
这里ADD(x,y)就是定义的宏,((x)+(y))就是这个宏的作用(将参数x和y相加),不难看出,宏是有参数的,所以细化一下,ADD就是宏名,x和y就是参数(参数无类型),((x)+(y))就是宏体。
在这个代码里,通过int sum = ADD(2, 3);
调用宏,将实参2和3分别传给形参x和y,再执行宏体((x)+(y))。
十三、指针
要想知道什么是指针,我们需要先了解内存:
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。
如何取地址,如下:
#include <stdio.h>
int main()
{
int num = 10;
#//取出num的地址
printf("%p\n", &num);//打印地址,%p是以地址的形式打印
return 0;
}
注:
1.这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(即首地址)。
2.这里有一个很重要的符号,就是取地址操作符&。
3.打印的结果是用十六进制表示的。
如何存地址呢,我们就需要用到指针,如下:
#include <stdio.h>
int main()
{
int num = 10;
int *p = #
*p = 20;
return 0;
}
这时,p中就存放了num的首地址。p就叫做指针变量。因此,存放地址(指针)的变量就称为指针变量。
注:
p是指针变量,int*是指针变量的类型,int说明p指向的对象是int类型,*说明p是一个指针变量。其他的类型类似。
若我们要找到p指向的对象,我们可以在p前面加上一个*,如下:
*p
此时,* 是一个解引用操作符,意思是通过p存放的地址,找到p所指向的对象,而*p就是p所指向的对象。
指针变量的大小:
指针变量的大小取决于地址的大小
int main()
{
printf("%d\n", sizeof(char *));
printf("%d\n", sizeof(short *));
printf("%d\n", sizeof(int *));
printf("%d\n", sizeof(double *));
return 0;
}
运行结果:
所以,指针大小在32位平台是4个字节,64位平台是8个字节。
十四、结构体
C语言为了描述更复杂的类型,给出了自定义类型的能力——结构体。
比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。
这里只能使用结构体来描述了。
例如:
struct Stu
{
char name[20];//名字
int age; //年龄
char sex[5]; //性别
char id[15]; //学号
};
结构体是把一些单一类型组合在一起的做法。
接下来我们可以简单举一个例子:
先写下一个学生的信息
struct Stu s = {"张三", 20, "男", "20180101"};
然后打印这个学生的信息:
printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);
这里需要注意:信息要一一对应。
这里用到了 .
操作符,用法是:结构体对象. 成员名。
另外,我们还可以这样来打印:
struct Stu *ps = &s;
printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps-
>id);
注:这里用到了->
操作符,用法是:结构体指针变量->成员名。
总结:当得到的是一个结构体变量是,可以用.
操作符,当得到的是一个指针可以用->
操作符。
因为是初识C语言,所以很多地方并不完善,也不够深入具体,但希望对刚开始学习C语言的小伙伴有所帮助。