本章目标
了解C语言的基础知识,对C语言有一个大概的认识。 每个知识点就是简单认识,不做过分详细讲解,后面会详细讲解。
什么是C语言
C语言是一门通用计算机编程语言,广泛应用于底层开发,应用层向下属于底层开发。
C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
计算机是硬件,操作系统(windows、linux、unix、mac os等)用来操作硬件,驱动层把操作系统和硬件关联起来,我们的应用程序是运行在操作系统之上的。
什么是计算机语言?
中国人交流用汉语,英国人交流用英语,人和计算机用什么交流?
我们直接对着电脑说print hello,它能理解并且打印hello吗?答案是不能。计算机只能识别机器码(0,1)所以我们和计算机怎么交流呢?—计算机语言,计算机能理解的语言,比如:C/C++/PYTHON/JAVA等。
计算机是硬件,电路组成,只有高低电平(0/1),对于0,1组成的一串内容,我们是看不懂的,怎么办?使用一些助记符,比如ADD等,由此出现了汇编语言,后来又出现了B语言,C,C++等高级语言。
机器语言(2进制序列)----->汇编语言(助记符,ADD、JMP等)----->高级语言
由于C语言使用方便,很快流行起来,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。常用的C语言标准C89、C90,C99没有完全流行起来,用的相对较少,不是所有的编译器都支持。C语言标准规定了C语言的语法规则。
C语言是一门面向过程的计算机编程语言,与C++,Java、Python等面向对象的编程语言有所不同。其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。
集成开发环境(IDE):VS2013、VS2019(VS系列使用的编译器是MSVC)。
第一个C语言程序
1. 创建工程/新建项目
文件–>新建–>项目,创建项目后,解决方案资源管理器 可能出现在页面的右边,我们可以自己更改资源管理器的停靠位置,鼠标左键点中解决方案资源管理器,拖动,屏幕上会出现如下画面,拖拽资源管理器时,你会看到这几个箭头,红圈内的图标就代表停靠在左边。想放在哪边就把鼠标箭头拖动到对应的位置
2.创建文件
.c 源文件
.h 头文件 head
3.写代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>//包含一个叫stdio.h的头文件
//std:standard 标准 i:input o:output
//int---整型
//main前面的int表示main函数调用返回一个整型
int main()
{
//main函数----主函数--程序的入口
//main函数必须要有 并且在一个项目中main函数有且只有一个
printf("hehe\n");
//printf:print function 打印函数
//printf:库函数 c语言本身提供给我们的函数
//别人的东西---要使用必须要跟人家打招呼 #include <stdio.h>
return 0;//返回0
}
4.运行代码
在VS2013下,如果运行代码控制台出现一闪而过的问题,解决办法:
项目属性----->配置属性----->链接器----->系统---->子系统------>选择控制台。
vs2019没有这个问题。
快捷键:运行代码不调试 ctrl+F5 / Fn+ctrl+F5
这里强调一下:main函数在C语言中是程序的入口,程序从main函数开始执行,main函数有且仅有一个(一个项目只能有一个main函数)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void test()
{
printf("this is test function\n");
}
//test();//报错 main函数是程序的入口
//main函数其他几种写法
//-明确告诉我们,main函数不需要参数
//int main(void)
//{
//}
//main函数其实是可以有参数的
//int main(int argc,char* argv[])
//{
//}
//这种写法已经过时了
//void main()
//{
//}
数据类型
整数 - 整型
小数 - 浮点型(小数点可以浮动)
C语言有哪些数据类型?
//char 字符类型
//short(int) 短整型
//int 整型
//long 长整型
//long long 更长的整型
//float 单精度浮点型
//double 双精度浮点型
//。。。。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
//char 字符类型
char ch = 'A';//在内存中开辟一块空间,存放字符A
printf("%c\n",ch);//%c---打印字符格式的数据
int age = 20;
printf("%d\n",age);//%d -- 打印整型十进制数据
//%d 以有符号十进制整型形式打印数据
//%c 打印字符
//%f 打印浮点数
//%p 以地址的形式打印
//%x 打印十六进制
//%o 打印八进制
//%lf 打印双精度浮点数
//%u 打印无符号十进制整型
float f = 3.0;
printf("%f\n",f);
printf("%.2f\n",f);//小数点后保留两位
double d = 3.14;
printf("%lf\n",d);
return 0;
}
为什么要有这么多类型?为什么要有这么多整型?
-
为了表达生活中各种类型的值
比如年龄使用整型比较合适,身高、体重使用浮点型比较合适,性别使用字符型比较合适 -
选择合适的数据类型,节约内存空间,提高内存利用率
比如年龄,没有人可以活到200岁,那么使用char类型(占用1个字节内存空间,范围是0-255)就可以满足条件了,没有必要使用占用内存更多的数据类型,这样就可以节省内存空间。
那么不同的数据类型占用多大的内存空间呢?
首先介绍计算机中的单位:
bit:比特位 ,计算机最小单位 ,存储一个二进制位
Byte:字节 ,计算机的最小存储单元 ,一个字节存放8个比特位
KB = 1024B
MB = 1024KB
GB = 1024MB
TB = 1024GB
PB = 1024TB
我们计算一个类型创建的变量所占空间的大小,使用操作符sizeof。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
printf("%d\n",sizeof(char));//1byte
printf("%d\n",sizeof(short));//2
printf("%d\n",sizeof(int));//4
printf("%d\n",sizeof(long));//4 or 8
printf("%d\n",sizeof(long long));//8
printf("%d\n",sizeof(float));//4
printf("%d\n",sizeof(double));//8
return 0;
}
sizeof----操作符 计算变量/类型的大小,单位是字节,C语言标准规定:sizeof(long) >= sizeof(int),所以在不同的编译器下sizeof(long)的值是不一样的,只要保证sizeof(long)>=sizeof(int)即可。
注意:C语言标准规定:sizeof(long) >= sizeof(int)。不同编译器下sizeof(long)的值不同。
int main()
{
char ch = 'e';//字符使用单引号引起来的
printf("%c\n",ch);//e
printf("%d\n",ch);//101
//abf!@#$ - 字符 怎么存储到计算机中呢?计算机只能识别二进制0,1
//给这些字符都编上号
//字符 - ASCII码值
//a - 97
//b - 98
//c - 99
//d - 100
//...
//ASCII码表 美国标准信息交换代码
//所以char类型在内存中存储的是ASCII码值 - char属于整型家族
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
short age = 20;//向内存申请2个字节(16bit),用来存放20
float weight = 48.5;
//编译时候可能会有警告 double到float进行截断,会有精度的丢失
//48.5默认是double类型
float weight = 48.5f;//表示48.5是float类型
return 0;
}
变量、常量
生活中有可能会变化的量,也有不会变化的量。
不会变化的量 - 常量
变化的量 - 变量
变量其实就是用来存放数值等内容的盒子。
定义变量的方法
//类型 变量名;
int age= 28;
age = 15;//可以修改
char sex = 'w';
float weight = 48.5;
局部变量、全局变量
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int num1 = 30;//全局变量 - 定义在代码块({})之外的变量
int main()
{
//int num2 = 10;//局部变量 - 定义在代码块({})之内的变量
int num1 = 10;
printf("%d\n",num1);//值是多少? 10
return 0;
}
总结:
局部变量和全局变量可以同时存在 ,当局部变量和全局变量的名字相同时,在函数内部优先使用局部变量(局部优先)
建议:局部变量和全局变量名字不要相同 - 容易产生误会,产生bug
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
//计算两个数字的和
int num1 = 0;//向内存申请4个字节的空间
int num2 = 0;
int sum = 0;
//输入数据 - 使用输入函数scanf
scanf("%d%d",&num1,&num2);
//&取地址符号,把两个数字分别放进两个地址中
//键盘输入数据时,两个数之间用空格隔开,区分两个数字
//对于scanf
//scanf("%d,%d",&num1,&num2);
//这种形式,键盘输入要写成:10,20
sum = num1 + num2;
printf("sum = %d\n",sum);
return 0;
}
//scanf函数
int main()
{
int n1, n2;
scanf("%d%d", &n1, &n2);
//键盘输入:10 20
//scanf("%d,%d",&n1,&n2);
//键盘输入:10,20
//scanf("%d %d", &n1, &n2);
//键盘输入:10 20
//scanf("%d %d\n", &n1, &n2); 不要这样写
printf("%d\n",n1+n2);
return 0;
}
典型错误:语法错误:缺少“;”(在“类型”的前面)
C语言语法规定:变量定义要在当前代码块的开头部分, 所以要把所有的变量声明放在最前面,貌似C99之后就没有这个问题了~
打断点,程序运行起来后,在窗口—内存–内存1,可以通过变量地址,查看变量的值
注意:局部变量未初始化,默认值是随机值;全局变量未初始化默认值为0。
变量的作用域和生命周期
作用域
通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
简单来说就是:局部变量的作用域是在它所在的{}内部,出了这个{},就找不到这个变量了
全局变量的作用域是整个工程的任意位置。
注意,我们说的作用域,是指通过变量名字访问内存,是变量名的可用性,比如static修饰的局部变量,作用域是指函数内部,生命周期是整个程序运行期间,在函数外面是不能通过变量名来访问局部变量的,但是可以通过指针来访问!
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int global = 100;//全局变量作用域:整个工程,任何地方都可以使用
void test()
{
printf("%d\n",global);//100;
}
int main()
{
int num = 30;//局部变量
//变量的作用域
{
int age = 10;//变量age的作用域就在这个{}中
printf("%d\n",num);//30
}
//printf("%d\n",age);//报错 找不到age这个变量
printf("%d\n",num);//30
printf("%d\n",global);//100
return 0;
}
全局变量的作用域是整个工程,如果在一个源文件中声明的全局变量,在其他源文件中可以使用,但是怎么使用呢?使用extern关键字。
//test.c
#define _CRT_SECURE_NO_WARNINGS 1
int g_val = 2021;
//main.c
#include <stdio.h>
//使用extern来声明外部符号
extern int g_val;//可以使用test.c中声明的变量g_val
int main()
{
//未声明的标志符
printf("%d\n",g_val);
return 0;
}
生命周期
1.局部变量的生命周期:进入作用域开始,出作用域结束;
2.全局变量的生命周期:整个程序的生命周期。
生命周期结束,内存空间还给操作系统,内存单元仍然存在,但是没有权限再使用。
关于scanf函数使用的问题
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
scanf("%d%d",&num1,&num2);
int sum = num1 + num2;
printf("%d\n",sum);
return 0;
}
这段代码会报如下错误:
scanf函数是C语言提供的,scanf_s不是标准C语言提供的,是VS编译器提供的,scanf_s尽量不要使用,当代码移植时,其他编译器是不认识scanf_s函数的,代码的可移植性差。
怎么解决?
在源文件开头,使用define定义常量 :
#define _CRT_SECURE_NO_WARNINGS 1
但是每次手动添加该常量较为麻烦,找到VS编译器安装路径下的newc++file.cpp文件,写入#define _CRT_SECURE_NO_WARNINGS 1
注:若文件无法修改,这里给出2种解决办法:
1.复制出来一份,以记事本方式打开,写入#define _CRT_SECURE_NO_WARNINGS 1,保存后,覆盖原来的newc++file.cpp文件,以后每次添加源文件,会自动添加。
2.或者以管理员身份打开vs,然后拷贝newc++file.cpp文件所在路径,使用vs打开该文件,在该文件中写入#define _CRT_SECURE_NO_WARNINGS 1。
常量
不会变的量称为常量,C语言中常量分为以下几种:
- 字面常量
- const修饰的常变量
- #define定义的标识符常量
- 枚举常量
#define MAX 100
//定义枚举类型 -- 一种数据类型
enum Gender
{
//枚举常量--枚举的可能取值
//枚举常量的值,默认从0开始
//MALE,//0
//FAMLE//1
//
//枚举常量可以赋初值
//MALE = 2,//2
//FAMLE//3
MALE = 2,//2
FAMLE = 5//5
};
int main()
{
//1.字面常量
3.14;//浮点型的字面常量
100;//整型字面常量
//2.const修饰的常变量
//const修饰的只读变量必须在定义的同时进行初始化
const int a = 100;
//a = 200;//错误
//一个变量不能被修改说明这个变量具有常属性 - 不能被修改的属性
//证明a是变量
int n = 100;
//int arr[n] = {0};//错误 数组长度要求是常量
//int arr1[a] = {0};//错误 - a具有常属性,但是本质是变量
//3.#define定义的常量 - 不能修改
int b = MAX;
//MAX = 100;//错误
int arr2[MAX] = {0};
printf("%d\n",b);
//#define定义的常量放在头文件中,其他源文件包含该头文件就可以使用
//4.枚举常量
//枚举: 一一列举
//性别: 男 女
//定义枚举变量g1
enum Gender g1 = MALE;
//MALE = 10;//枚举常量的值不能改
return 0;
}
注意:C99标准中引入:变长数组,编译器一定要支持C99标准,才可以使用可变长数组,同时变长数组是不能初始化的。
puts函数
顺序输出作为实参的字符串,并在结尾自动换行。
puts(“…”)和printf(“…\n”)的功能基本相同。
int main()
{
//输出函数puts
//以下两种方式等价
puts("hello world!");
printf("hello world!\n");
return 0;
}