背景介绍
- 简单介绍一个计算机的结构
计算机主要由应用软件,操作系统,驱动层和硬件来组成
其中的应用软件主要包括一些日常使用的软件,例如:QQ音乐,QQ等一些软件
操作系统包括windows,macos,linux等一些计算机操作系统
驱动车则是帮助操作系统和硬件之间进行一个交互,帮助计算机更好的工作
硬件就是电脑本身的一些设备和配置
- 计算机语言的发展
计算机首先从2进制,例如001010101,在此基础上有些提出了助记符这样的定义,助记符就是指将二进制转换成更容易记住的名字,例如1001—ADD,0010—MOV等,这时的二进制便发展成了汇编语言。从此之后,计算机语言便有了新一轮的发展,从汇编语言到了B语言又到如今的C语言
第一个C语言的程序
- 这里需要说明的是,本文中使用的编译器为VS2019
#define _CRT_SECURE_NO_WARNINGS //这里是因为VS中scanf不安全,所以定义一个常量给它,在VS中要使用scanf_s才行,但是其他编译器不通用
#include<stdio.h>//引用头文件,使其可以使用printf库函数
int main()//主函数,第一个C语言程序只可以有一个main函数
{
printf("hehe\n");//在屏幕上输出一个hehe
return 0;//返回值,返回int类型的值,这里为0
- 上面是一个简单的C语言程序,一个最简单的C语言的程序要包含头文件和主函数(main),不然这个程序是不完整的。
数据类型
- C语言中有一些常见的数据类型
数据类型 | 大小(字节) |
---|---|
char | 1 |
short | 2 |
int | 4 |
long | 4 |
long long | 8 |
float | 4 |
double | 8 |
- 这些数据类型的大小是怎么计算而来的呢,这里我们可以使用C语言的一个函数size of 来实现
int main()
{
printf("%d\n", sizeof(char));//%d表示返回一个整形,sizeof是计算类型占据的空间,以字节来返回的
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;
}
- 这里我们要提出的是在一个C语言进行的过程中,总是从main函数的第一行进行下去的,这里是十分重要的!
- 这里给读者补充一个内容,就是计算机内存单位的计算
单位 | 单位换算 |
---|---|
1bit | 1 |
1byte | 8 bit |
1KB | 8 byte |
1MB | 1024 KB |
1GB | 1024 MB |
1TB | 1024 GB |
1PB | 1024 TB |
- 注意:bit是计算机内存大小的最小单位
- 一个汉字是两个字节,要用字符串去存储
变量和常量
- 定义变量的方法采用 类型+变量=值 的方法来实现
int main()
{
int a = 2; //定义一个变量整形a,给它赋值2
char b = 'w';//定义一个变量字符,给它赋值’w'
}
int main()
{
float a = 34.3;//定义一个单精度的浮点变量a,值为34.3
return 0;
}
- 这里要注意虽然给的类型是float,但是在编译器中默认一个小数是double
- 若要为float变量则在值后面加一个f
- 局部变量和全局变量
- 局部变量是指在main函数内部定义的变量
- 全局变量是指在main函数外部定义的变量
- 这里给大家看一下容易出错的例子
int num = 10;//10
int main()
{
int num = 20;
printf("%d\n", num);//20
return 0;
}
- 这里的输出结果应该是多少呢?
- 答案是20,因为局部变量优先级在main函数中
- 变量的定义
- 只能由字母(小写大写都可以),数字和下划线(
_
)组成 - 不能以数字开头
- 长度不可以超过63个字符
- 变量名中区分大小写的
- 变量名不可以用关键字
- 变量名最好有意义
int main()
{
int Apple;
int apple;//这两个变量不一样
int apple1_1;
int 1apple;//不可以用数字开头
int char;//不可以使用关键字
int banananum;//变量名最好有意义,这里的变量表示香蕉的数量
}
变量的作用域和生命周期
- 局部变量的作用域:是局部变量所在的局部范围
- 全局变量的作用域:全局变量的作用域是整个工程
- 如果另一个变量在其他的源文件中,是否可以使用?
- 答案是可以的
- 生命周期
- 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束
- 全局变量的生命周期:整个程序的生命周期
常量
-
字面常量
-
const
修饰的常变量 -
#define定义的标识符常量
-
枚举常量
-
枚举变量的注意事项
-
-
注意常量是不可以去修改的
-
这里再给大家补充一个C99的概念——变长数组
-
什么是变长数组呢?
-
首先我们先看一个错误
-
如果我们给变量a常量化会怎么样呢?(
const
修饰)
-
我们发现虽然给a常量化,但是还是行不通,这是因为在VS的编译环境下,
const
只是给这个变量一个常属性,不能改变它本身是变量的性质 -
但是如果在Linux系统的gcc编译数组中,这样的形式就可以成立,这样的数组就叫做变长数组,但是这样的数组不可以初始化
字符串+转义字符+注释
- C语言中的字符是使用单引号来引起来的
' '
char a =' w '
,char b = 'b'
等一些字符
- 但是在C语言中字符串和字符的定义是不一样的
- 字符串要用
" "
双引号来引出,而且要用一个字符数组来包括它 char arr[ ]="apple"
#include<stdio.h>
int main()
{
char arr[] = "apple";//定义一个字符数组来包含apple这个字符串
}
- 注意:字符串的结束标志是一个
\0
的转义字符。在计算字符串长度的时候\0
是结束的标志,不算作字符串的内容
int main()
{
char arr1[] = "bit";//默认有'\0'
char arr2[] = { 'b','i','t' };
char arr3[] = { 'b','i','t','\0'};//有'\0'的字符串
printf("%s\n", arr1);//%s表示打印字符串,识别'\0'作为结束标志
printf("%s\n", arr2);
printf("%s\n", arr3);
}
arr2[ ]
找不到结束的标志,所以它只能在它之后存储的空间中找到'\0'
才能停止,所以会产生乱码- 当然这里也可以使用另个方法来验证
#include<string.h>
int main()
{
char arr1[] = "abc";
char arr2[] = {'a', 'b', 'c'};
int len = strlen(arr1);
printf("%d\n", len);
len = strlen(arr2);
printf("%d\n", len);
//strlen 是一个库函数,专门用来求字符串长度的,它也是找到\0结束
int len1 = strlen("abcdef");
printf("%d\n", len1);
return 0;
}
- 转义字符
- 转义字符是编程语言中很常见的存在,我们来看一看一些例子
转义字符 | 释义 |
---|---|
\? | 在书写多个问号的时候,防止他们被解析成三字母词 |
\` | 用于表示一个字符单引号 |
\" | 用于表示一个字符串内部的双引号 |
\ \ | 用于表示一个反斜杆 |
\a | 用于表示警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符(换一页) |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd表示1~3个八进制数字。如 :\130 X。(不一定要写满) |
\xdd | dd表示1~2个十六进制的数字。如:\30 0。(不一定要写满) |
- 这里的数字会转化成十进制对应的ASCII码值
- 注释
- C语言中的注释有两种形式可以呈现
1. 使用/* */
这样的形式来呈现(不可以嵌套实现)
2. 使用//
这样的形式来呈现(可以一行也可以多行)
选择语句
- 在C语言中选择语句是十分重要的,它运用在许许多多的方面——
if else
这样的形式来呈现
int main()
{ //c语言中0为假,非0为真
int a = 1;
if (a) //当()里面的值为真时,执行下面的语句
printf("好好学习");
else //当()里面的值为假时,执行下面的语句
printf("去卖红薯");
return 0;
}
- 其余的选择语句后面会有详细讲解
循坏
- C语言中的循环有很多种,
for,while,switch
这类都是一种循环体。 - 这里我们粗略讲解,后面会细讲
int main()
{
int a;
scanf("%d", &a);
while (a < 10)//当a小于10时,执行这个循环
{
printf("好好学编程\n");
a++;//每执行一次循环a的值就自加1
}
return 0;
}
- 当我输入的值为8的时候,8小于10,故输出一次。这时8要自加一次,变成9,9也小于10,故又执行一次输出。当下次时,a的值变成了10,不满足条件变不执行循环了
函数
- 函数在语言的运用过程中十分广泛,在一些大型的编译程序中,函数的运用会显得十分重要
- 下面是一个使用函数的c语言程序示例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int add(int x, int y)
{
int z = x + y;//定义一个函数来完成两个整形数的加法
return z;
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);//主函数执行上面的add函数
int c = add(a, b);
printf("两个数总和=%d", c);
return 0;
}
- 从上面的例子可以看出对于函数来说,要有返回类型,形式参数,函数体三大类型
- 注意:定义函数要在一个源文件之间去定义,如果没有在同一个头文件中,要使用
extern
关键字进行外部声明
数组
- 数组是一组相同类型元素的集合
int arr[10]={1,2,3,4,5,6,7,8,9,10};//定义一个整形的数组,最多放10个元素
- 注意:如果数组的元素没有满10个,则自动补0
- 数组的每一个元素都有下标,数组的下标默认从0开始
- 数组可以通过下面来访问
int arr[10]={0};
//下标的范围是0~9
int main()
{
//不完全初始化,数组有4个元素,只给3个字符初始化,剩余一个没有给值,默认被初始化为'\0'
char arr[] = { 'b', 'i', 't'};
//[b i t \0]
//[ ][ b i t ][ ]
printf("%d\n", strlen(arr));//strlen函数返回\0之前的字符个数
return 0;
}
操作符
- 算术操作符
+ - * / %
除法操作符/
和上下类型有关,取余操作符%
只能对整形使用 - 移位操作符
<< >>
移动二进制位 - 位操作符
& ^ |
二进制的运算 - 赋值操作符
= += -= *= /= &= ^= |= >>= <<=
对c语言的变量进行赋值 - 单目操作符
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
- 关系操作符
>
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”
- 逻辑操作符
&& 逻辑与
|| 逻辑或
- 条件操作符
exp1 ? exp2 : exp3//如果exp1是真的话,执行exp2,假的话执行exp3
- 逗号表达式
exp1, exp2, exp3, …expN//从左到右最后一个表达式为最终结果
- 下标引用、函数调用和结构成员
[] () . ->
常见关键字
auto break case char const continue default do double else enum
extern float for goto if int long register return short signed
sizeof static struct switch typedef union unsigned void volatile while
- 我们重点说几个,之后会详细的讲解的
register
寄存器关键字,频繁又大量使用的关键词建议放入寄存器中auto
每个局部变量都是auto都修饰的typedef
对类型名重命名
//将unsigned int 重命名为uint_32, 所以uint_32也是一个类型名
typedef unsigned int uint_32;
int main()
{
//观察num1和num2,这两个变量的类型是一样的
unsigned int num1 = 0;
uint_32 num2 = 0;
return 0;
}
static
静态修饰变量和函数
- 修饰局部变量-称为静态局部变量
- 修饰全局变量-称为静态全局变量
- 修饰函数-称为静态函数
- 修饰局部变量
//代码1
#include <stdio.h>
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
//代码2
#include <stdio.h>
void test()
{
//static修饰局部变量
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
- 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;
}
- 一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。
- 修饰函数
//代码1
//add.c
int Add(int x, int y)
{
return c+y;
}
//test.c
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
//代码2
//add.c
static int Add(int x, int y)
{
return c+y;
}
//test.c
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
- 一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。
#define 定义常量和宏
//define定义标识符常量
#define MAX 1000
//define定义宏
#define ADD(x, y) ((x)+(y))//这里一定要加括号
#include <stdio.h>
int main()
{
int sum = ADD(2, 3);
printf("sum = %d\n", sum);
sum = 10*ADD(2, 3);
printf("sum = %d\n", sum);
return 0;
}
指针
- 内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。 - 为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
![在这里插入图片描述](https://img-blog.csdnimg.cn/35f963dccaba4e4286f953efc0d9570d.png - 变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。
#include <stdio.h>
int main()
{
int num = 10;
#//取出num的地址
//注:这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址)
int *p=#//解引用p作为指针变量来存储num
printf("%p\n", &num);//打印地址,%p是以地址的形式打印
return 0;
}
- 指针变量的大小
#include <stdio.h>
//指针变量的大小取决于地址的大小
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
int main()
{
printf("%d\n", sizeof(char *));
printf("%d\n", sizeof(short *));
printf("%d\n", sizeof(int *));
printf("%d\n", sizeof(double *));
return 0;
}
- 因为一个指针变量存放一个变量第一个地址,所以32bit为4个字节(依机器而定)
- 指针大小在32位平台是4个字节,64位平台是8个字节。
结构体
- 结构体是C语言中特别重要的知识点,结构体使得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);
- 当然
(*p).name
这样也是可以解引用成员的,结构体用.
,指针用->
。
完结
- 精讲部分将持续推送