前言
以下内容使用Visual Stdio 2022集成开发环境,内容仅针对初学者。
目录
一、第一个C语言程序
二、数据类型
三、变量、常量
Ⅰ、变量
Ⅱ、常量
①、 字面常量
②、const修饰的常变量
③、define定义的标识符常量
④、枚举常量
#include
int main()
{
printf("Hello world!");
return 0;
}
程序输出:
具体理解:
① 包含头文件
在项目中外部依赖项能找到stdio.h头文件,这些头文件都是vs自带的头文件(有很多没列出来),现在的我们只需要知道里面含有许多函数,这些函数能用来实现我们需要操作,比如scanf函数(格式化输入)和printf函数(格式化输出)在stdio.h中定义,再比如Windows.h头文件中的Sleep函数,我们需要用Sleep函数(后续会介绍)时只需要引入Windows.h头文件。引入方式为#include <头文件全名>
scanf入口——> <scan函数>
printf入口——>
②main函数
main函数可以写成以下几种形式(都不会报错)
int main()
{
return 0 ;
}
void main()
{
}
main()
{
}
以上三种方式写main函数均不会报错,但是最规范的是第一种。
③格式化输出
目前只需要知道printf函数是一个用来控制操作台输出的函数即可。
printf函数入口——>
④main函数返回值
每个函数都有特定的返回值,void意思为空表示没有返回值,返回类型取决于定义的返回类型。
char //字符类型 占 = 1 = 个字节
short //短整形 占 = 2 = 个字节
int //整形 占 = 4 = 个字节
long //长整型 占 = 4 = 个字节
long long //长长整形 占 = 8 = 个字节
float //单精度浮点型 占 = 4 = 个字节
double //双精度浮点型 占 = 8 = 个字节
我们可以用sizeof操作符来验证类型占多少个字节
#include
int main()
{
printf("char 类型占%d个字节\n", sizeof(char));
printf("short 类型占%d个字节\n", sizeof(short));
printf("int 类型占%d个字节\n", sizeof(int));
printf("long 类型占%d个字节\n", sizeof(long));
printf("long long类型占%d个字节\n", sizeof(long long));
printf("float 类型占%d个字节\n", sizeof(float));
printf("double 类型占%d个字节\n", sizeof(double));
return 0;
}
注:①long long类型在c99以后才有这个类型(编程语言以前是有A语言到C语言的,因为有些语法不一样,导致代码没有通用性,所以有人想定制人们公认的语法,最后才定制了c89标准(可以理解为公认语法),c99也是由c89更新过来的新标准)
②sizeof(int)的结果是4,而printf中这种表现形式是格式化输出的基本形式,%d(格式字符)表示以十进制整数输出。
格式字符入口——><格式字符>
③\n是转义字符,意思是操作台打印到\n这时,光标移动到下一行。之后的打印从下一行开始。
转义字符入口——><转义字符>
变量分为局部变量 与 全局变量
定义在大括号内的变量叫做局部变量,该变量的作用域只存在于大括号内部,只能在大括号内部使用。
定义在大括号外的变量叫做全局变量,该变量的作用域存在于所有范围,在整个文件中都能使用。
定义变量的方式通常为
类型 变量名 = 对应的数值(加对应的数值是为了初始化变量,当然不加也是可以的,如果不初始化变量,那么在后面的代码中你没给这个变量赋值还用了它,程序就会报错。在后面数组那一章会介绍不初始化变量会产生什么样的后果)
知识点:
当我们定义三个重复的变量名给它赋值不同的数据,那么编译器是会用哪个数据呢?
如下
#include
int a = 1;
int main()
{
int a = 11;
{
int a = 111;
printf("%d\n", a);
}
printf("%d", a);
return 0;
}
结果为
可以看到编译器选用最近的变量当作a的数据,这就是变量选择的就近原则(局部优先)
注释:变量a虽然名字一样,但是每个变量存放数据的容器(地址)不一样。
地址详解——><创作中>
由以下求证
#include
int a = 1;
int main()
{
int a = 11;
{
int a = 111;
printf("%p\n", &a);
printf("%d\n", a);
}
printf("%p\n", &a);
printf("%d\n", a);
return 0;
}
结果为
可以看到两个区段a所代表的容器(地址)不一样,由此所见:重新定义局部变量a并不会修改全局变量的数据,程序使用a变量时,采用局部优先原则,此时在main函数不能通过普通变量使用外面定义的a,因为a已经在main函数内定义。(可以通过指针变量使用main函数外面定义的a)。
#include
int main()
{
char a = 'a';//字符'a'为字符常量
short b = 12;//12为整形常量
int c = 4; //一般右边为整数的数字
//编译器默认将这个数字当作整形(int)
float d = 3.14f;//3.14为双精度浮点型,加一个f表示3.14为单精度浮点型
double e = 3.5;//3.5为双精度浮点型,与左侧类型相匹配
return 0;
}
在赋值语句中,一般右边的类型要与左边的类型相匹配,否则就会产生类型的转换。
具体转换后面会讲到(目前学习不用考虑这个,只需要知道等号两边类型相匹配不会出错就行了)
注:字符常量在内存是如何存储的=>在C语言中有一个ASCII表,每个字符对应一个数字,内存存放字符的形式就是将这个数字代替字符存储。比如字符 'a' 它的ASCLL码为97,内存存放的便是97.
ASCLL码——>
类型转换——><创作中>
如上图:使用const修饰了一个整形(int),那么我们就不能通过这个变量a修改它的值。
被const修饰的变量叫做常变量,只是说这个变量具有了常属性(不能通过常变量修改它的值)
但是可以通过指针来找到常变量指向的内存,通过地址来修改它的值,具体实现如下
#include
int main()
{
const int a = 21;
// a = 11;
printf("%d\n", a);
int* aq = &a;
*aq = 11;
printf("%d\n", a);
return 0;
}
结果如下:
int* 是整形指针,现在只需要知道它是定义指针的方式,指针简而言之就是地址,指针的出现也是为了能用代码将地址聚现化。&为取地址操作符,&a的意思就是将a的地址取出来代替&a。*为解引用操作符,首先aq是一个指针变量,内容是a的地址,*aq就是将aq指向的那一块数据代替*aq(或许你有疑问:指向的一块数据有多少字节呢 ?这是根据指针变量定义的类型来决定的,比如你用int* 定义一个变量,那么这个指针解引用只会获得指定位置的4个字节的数据。同理使用double* 定义一个指针变量,那么解引用只能访问内存条中指定位置的8个字节的数据。)
操作符详解——><操作符>
#include
#define CRT 100
int main()
{
int a = CRT;
int arr[CRT] = { 0 };
printf("%d\n", a);
printf("%d\n", CRT);
return 0;
}
标识符常量定义方式如上图:#define 常量名 数值
define定义的标识符常量可以用作赋值,给数组规定大小(以上arr数组的大小为100)。
#include
enum sex
{
MALE, //值为 = 0 =
FEMALE, //值为 = 1 =
DOUBLE, //值为 = 2 =
ONE = 99,//值为99
TWO //值为100
};
int main()
{
enum sex man = MALE;
printf("%d\n", MALE);
printf("%d\n", FEMALE);
printf("%d\n", DOUBLE);
printf("%d\n", ONE);
printf("%d\n", TWO);
return 0;
}
结果为
枚举就是一一列举,枚举是C语言提供的一种自定义的方法。(目前只需要知道枚举类型的定义和枚举常量的值就行了)
枚举常量的值是逐渐递增的,当没有赋值时从0开始递增,赋值后从赋值的地方递增。
知识点:
①数组大小的定义中括号内的常量只能用字面常量、标识符常量、枚举常量这三种。
②在C99标准新加入了加长数组,这种数组可以使用变量做为定义数组大小的常量。
(所以你会发现在一些编译器中使用变量定义数组大小不会报错,原因是你用的编译器使用的是C99以后的标准)