摘要:本系列主要是基于C语言的程序设计、数据结构和算法等计算机专业内功知识,以达到锻炼自身,分享他人的目标。
一、前言
1、C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码及不需要任何运行环境支持便能运行的编程语言。人们通常认为应用层以下均为底层,具体如下图所示,但有特例,如早期WPS是由C语言实现的。
2、C语言是一种具有国际标准的语言。如C89,C90,C99,C11,其中前两者是适用度最广的标准。
3、C语言编译器有Clang、GCC、WIN-TC、SUBLIME、MSVC和Turboc等。
二、写代码的正确步骤
** 注:基于Visual Studio 2022 集成开发环境(IDE)**
1、创建工程。点击Visual C++中空项目
2、创建源文件。xxx.c - 为源文件,xxx.h - 为头文件
3、写代码。
#include <stdio.h>
//首先创建主函数
//因为C语言是从主函数的第一行开始执行的
//其中,int 是函数返回类型,main 是函数名,{} 是函数体,printf - 库函数,作用是在屏幕上打印信息
//printf 的使用,需要打声招呼,即引用头文件(stdio.h)
int main()
{
printf("内容");
return 0;
}
4、编译代码
开始执行: 编译+链接+运行代码
开始调试:检查语法错误
三、数据类型
1、计算机语言应该有能力描述生活中的问题,故选择多种数据类型适应生活不同情况。
代码 | 含义 | 字节大小 |
---|---|---|
char | 字符型 | 1 |
short | 短整型 | 2 |
int | 整型 | 4 |
long | 长整型 | 4/8 |
long long | 更长整型 | 8 |
float | 单精度浮点型 | 4 |
double | 双精度浮点型 | 8 |
注:long字节长度满足大于等于int字节长度,在不同编辑器环境下,可能出现4字节或者8字节。
程序:计算数据类型字节大小。
//本文以char为例,表示计算类型所占空间的大小
#include <stdio.h>
int main()
{
printf("%d\n", sizeof(char));//sizeof() - 计算类型或变量所占空间的大小
return 0;
}
2、计算机中的进制与单位
二进制:0-1
八进制:0-1-2-3-4-5-6-7
十进制:0-1-2-3-4-5-6-7-8-9
英文 | 汉义 | 等价代换 |
---|---|---|
byte | 字节 | 8bit |
KB | - | 1024B |
MB | - | 1024KB |
GB | - | 1024MB |
… | - | 1024… |
在二进制前提下,设有n位比特,可以表示十进制的数字范围是(0,
2
n
2^n
2n-1),
** 注:计算机中最小单位是比特byte**
3、printf下的格式符号
#include <stdio.h>
int main()
{
printf("内容");//打印内容
printf("%d\n",100);//打印一个整数 - %d
/*
% d 十进制有符号整数
% u 十进制无符号整数
% f 浮点数
% s 字符串
% c 单个字符
% p 指针的值
% e 指数形式的浮点数
% x, % X 无符号以十六进制表示的整数
% 0 无符号以八进制表示的整数
% g 自动选择合适的表示
*/
return 0;
}
4、常量与变量
1)定义
常量:不能改变的量
变量:可以改变的量。
#include <stdio.h>
int main()
{
//创建一个变量
//类型 变量的名字 = 0;推荐
//类型 变量的名字;不推荐
int age = 20;
float weight = 70.3;
printf("2022年,我的年龄%d,我的体重%f\n",age,weight);
//对于float - %f,对于double - %lf;,对于int - %d;
return 0;
}
2)变量分为全局变量和局部变量
全局变量:代码块{ }外部定义的
局部变量:代码块{ }内部定义的
3)变量的作用域和生命周期(空间和时间角度)
局部变量作用域 - 代码块{ }内部
全局变量作用域 - 整个工程
局部变量的生命周期 - 进入局部范围开始,出去局部范围结束
全局变量的生命周期 - 程序的生命周期
extern int a;//其他文件使用时,需要声明时使用该关键字
4)常量的表达方法
//1.字面常量 如3.14,10,'a',"adhakj"
//2.const 修饰的常变量
const int num = 10;//num 再次不可修改,类比于动名词
//3.#define 定义的标识符常量
#define Num 50
//4.枚举常量
enum Sex
{
//这种枚举类型的变量的未来可能取值
man = 3,//赋初值
woman,
sercrt
};
enum Sex R = man;
注:当局部变量和全局变量名字起冲突的时候,局部优先
5、scanf函数在vs中的解决方案
1)scanf替换为为scanf_s
2)源文件的第一行加上
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
int sum = 0;
scanf("%d%d", &a, &b);//%d%d应该连续挨着且中间无其他符号
sum = a + b;
printf("sum = %d",sum);
return 0;
}
这两种基本能解决99%的scanf警告问题。
四、字符串
1、定义
有双引号引起来的一串字符称为字符串字面值。
** 注:字符串的结束标志是一个\0的转义字符(" "自带\0),但在计算机计算字符串长度时\0不计入。**
#include <stdio.h>
#include <string.h>
int main()
{
//字符数组 - 是一组形同类型的元素
//字符串在结尾隐藏了\0的字符,\0是字符串结束的标志
char arr1[] = "abc";//以\0结束标志
char arr2[] = { 'a','b','c' };//结尾之后有乱码
printf("打印字符串%s\n",arr1);
printf("打印字符串%s\n",arr2);
int len = strlen("abc");//求字符串的长度,不算\0
printf("%d\n",len);
printf("%d\n", strlen(arr1));//长度是3
printf("%d\n", strlen(arr2));//字符长度是随机数值
return 0;
}
2、转义字符
符号 | 含义 |
---|---|
\? | 在书写多个问号时,防止解析成其他符号 |
\’ | 用于表示字符常量’ |
\" | 用于表示字符常量“ |
\\ | 用于表示一个反斜杠 |
\a | 警告字符 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\t | 水平制表符,相当于TAB |
\r | 回车 |
\v | 垂直制表符 |
\ddd | ddd表示1~3个八进制的数字 |
\xdd | dd表示2个十六进制数字 |
\ddd:解释d8
2
^2
2+d8
1
^1
1+d8
0
^0
0 = 十进制下的数字;\xdd:x是标识符,d16KaTeX parse error: Expected group after '^' at position 1: ^̲+d16
0
^0
0 = 十进制下的数字。
基于%d的输出格式下是十进制有符号整数;基于%c输出格式下是显示ASCII码值*
注:转义字符在计算字符串长度时算一个字符。
3、注释(十分重要)
1)快捷方式:选中代码,长按Ctrl+K+C进行注释,长按Ctrl+K+U取消注释
2)作用:解释复杂代码
3)注释风格:①单行//注释(C++风格,推荐),②多行/**/(C语言风格,不推荐,不支持嵌套)
五、选择与循环
1、选择语句
#include <stdio.h>
int main()
{
int input = 0;
printf("你要好好学习吗?");
scanf_s("%d",&input);
if (input == 1)
printf("好的,奋斗百天上清华!");
else
printf("不,我要在清华旁边卖红薯!");
return 0;
}
2、循环语句(while)
#include <stdio.h>
int main()
{
int line = 0;
while (line < 30000) {
printf("写代码的第%d行\n",line);
line++;
}
printf("迎娶白富美!");
return 0;
}
六、函数
#include <stdio.h>
int add(int x,int y)//add函数
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int num1 = 0;
int num2 = 0;
scanf_s("%d%d",&num1,&num2);
int sum = add(num1, num2);//函数方式解决
printf("sum = %d",sum);
return 0;
}
七、数组
#include <stdio.h>
int main()
{
//数组 - 一种相同类型的元素的集合
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//完全初始化
char ch[5] = {'a','b','c'};//不完全初始化,剩余的默认为0
//数组使用下标来进行访问.arr[0] == 1,arr[1] == 2,以此类推。。。
int i = 0;
while (i<10)
{
printf("%d\n",arr[i]);
i++;
}
return 0;
}
八、操作符(重要)
1、算数操作符:
符号 | 含义 |
---|---|
+ | 将左右参数进行相加 |
- | 将左右参数进行相减 |
/ | 取除法的整数部分作为输出 |
% | 取除法的余数部分作为输出 |
2、移位操作符:
符号 | 含义 |
---|---|
>> | 在二进制条件下,将1向右移一位 |
<< | 在二进制条件下,将1向左移一位 |
3、位操作符:
符号 | 含义 |
---|---|
& | 按位与(AND)例:左右一位为0便是0 |
丨 | 按位或(OR)例:左右一位为1便是1 |
^ | 按位异或 (XOR)例:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。 |
~ | 按位取反 (NOT) |
4、赋值操作符:
符号 | 含义 |
---|---|
= | 赋值 |
+= | a= a+b |
-= | a=a -b |
/= | a=a / b |
&= | a=a &b |
^= | a=a^b |
>>= | a=a >>b |
<<= | a=a <<b |
注:赋值运算符 = 的优先级低于其他符号,故先算其他运算符之后再算=,=右边是以一个整体与=左边进行计算的。
5、单目操作符:
符号 | 含义 |
---|---|
! | 逻辑反操作 |
- | 负值 |
+ | 正值 |
& | 取地址 |
sizeof | 操作数的类型长度(以字节为单位) |
~ | 对一个数的二进制按位取反 |
- - | 前置、后置- - |
++ | 前置、后置+ + |
* | 间接访问操作符 |
(类型) | 强制类型转换 |
#include <stdio.h>
int main()
{
int a = 0;
printf("%d\n", ~a);//~按位取反,把所有二进制位中,把0变成1,把1变成0,int 0的二进制是32位0,
//整数在内存中储存的是补码,一个整数的二进制表示有3种:①原码②反码③补码
//最高位1表示负数,0表示正数。
//其中,-1(负数)的原码是
//10000000000000000000000000000001(原码)
//11111111111111111111111111111110 (反码)
//11111111111111111111111111111111(补码 = 反码 + 1)
//正整数:原码 = 反码 = 补码
return 0;
}
#include <stdio.h>
int main()
{
int a = 10;
int b = ++a;//前置++ - 先++赋值a,后使用赋值b。
printf("%d%d", a, b);
return 0;
}
#include <stdio.h>
int main()
{
int a = 10;
int b = a++;//后置++ - 先使用a赋值b,后++赋值a,
printf("%d\n%d", a, b);
return 0;
}
#include <stdio.h>
int main()
{
int a = (int)3.24;
printf("%d\n",a);
return 0;
}
6、关系操作符
符号 | 含义 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
!= | 不等于 |
== | 相等 |
7、逻辑操作符
符号 | 含义 |
---|---|
&& | 逻辑与 |
丨丨 | 逻辑或 |
8、条件操作符(三目操作符)
exp1? exp 2 : exp3
exp1成立,exp2计算,整个表达式的结构是:exp2的结果;
exp1不成立,exp3计算,整个表达式的结构是:exp3的结果
#include <stdio.h>
int main()
{
int a = 0;
int b = 3;
int max = 0;
max = a > b ? a : b;
//if(a > b)
// max = a;
//else
// max = b;
printf("%d\n", max);
return 0;
}
9、逗号表达式
#include <stdio.h>
int main()
{
int a = 0;
int b = 3;
int c = 5;
int d = (a = b + 2, c = a - 4, b = c + 2);//逗号表达式,是从左至右以此计算,
//整个表达式的结果是最后一个表达式结果
printf("%d\n", d);
return 0;
}
10、下标引用、函数调用和结构成员
[ ]、( )、 . ->
#include <stdio.h>
int main()
{
//下标引用操作符
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n",arr[2]);
//函数调用的时候,函数名后面的()就是函数调用操作符
printf("haha\n");
printf("%d",100);
return 0;
}
九、常见关键字
1、C语言提供的,不能自己创造关键字
2、变量名不能是关键字
3、
符号 | 含义 |
---|---|
auto | 自动的 - 每个局部变量都是auto修饰的,自动创建,自动销毁 |
break | |
case | |
char | |
const | |
continue | |
default | |
do | |
double | |
else | |
enum | |
extern | 用来声明外部符号 |
float | |
for | |
goto | |
if | |
int | |
long | |
register | 寄存器关键字 |
return | |
short | |
signed | 有符号的,如正负号 |
unsigned | 无符号的 |
sizeof | |
static | 静态的 |
struct | |
switch | |
typeedf | 类型定义 |
union | 联合体(共用体) |
void | 无- 空 |
volatile | |
while |
** 注:define和include 是预处理指令**
#include <stdio.h>
//类型重定义,起小名
typedef unsigned int u_int;
int main()
{
u_int num = 200;
printf("%u",num);
return 0;
}
#include <stdio.h>
//static - 静态的作用1.修饰局部变量;2.修饰全局变量 3.修饰函数
//改变了局部变量的生命周期,本质上改变了变量的存储类型
//栈区:局部变量,函数的参数;堆区:动态内存分配的;静态区:全局变量,static修饰的局部变量
void test()
{
static int a = 1;//保留a值不销毁
a++;
printf("%d\n", a);
}
extern int Add(int x, int y);
//extern int g_val;//声明全局变量,当static修饰全局变量只能在自己所在的源文件内部使用。
//全局变量,在其他源文件内部可以被使用,是因为全局变量具有外部链接属性,
//但是被static修饰之后,就变为内部链接属性,其他源文件就不能连接到静态全局变量了
int main()
{
/*int i = 0;
while (i<10)
{
test();
i++;
}
printf("%d\n",g_val);*/
int a = 20;
int b = 10;
int sum = Add(a, b);
printf("%d\n",sum);
return 0;
}
** define定义常量和宏**
//#define 是一个预处理指令。1.define定义符号2.定义宏
#include <stdio.h>
#define MAX 1000
#define ADD(X,Y) ((X)+(Y))
int main()
{
int Z = 4 * ADD(2, 3);
printf("%d\n",Z);
return 0;
}
十、指针
1、内存如同一栋居民楼,
内存是怎么编号的?一个内存空间是多大的?
32位 - 32根地址线 - 物理线 - 通电 -1/0 - 2
3
2
^32
32个内存单元 = 4,294,967,296byte / 8 = 524,288KB/1024 = 512MB/1024 = 0.5GB+
一个内存单位是一个字节
电信号转换成数字信号:1和0组成的二进制序列
#include <stdio.h>
int main()
{
int a = 10;//a在内存中要分配空间的 - 4个字节
printf("%p\n",&a);
int* pa = &a;//pa是用来存放地址的,在C语言中pa叫指针变量,*说明pa是指针变量,int说明pa指向对象的类型是int型
//指针就是地址。指针变量也是数据类型,也有自己的地址。
char ch = 'w';
char* pc = &ch;
printf("%p\n", pc);
*pa = 20;//*解引用操作,*pa是通过pa里面的地址找到a
//指针大小都是相同的,原因:指针是用来取地址的,指针需要多大空间,取决于地址的存储需要多大空间
//32位 - 32bit/8位 = 4byte; 64位 - 64bit/8位 = 8byte ;内存单元 = 1字节
return 0;
}
十一、结构体
#include <stdio.h>
struct Stu //创建学生
{
char name[20];
int age;
double score;
};
struct Book //创建书
{
char name[20];
float price;
char id[30];
};
//结构体可以让C语言创建新的类型出来
int main()
{
//结构体直接法
struct Stu s = {"张三",20,86.5};//结构体创建与初始化
printf("第一种:%s %d %lf\n",s.name,s.age,s.score);//结构体变量.成员变量
//解引用指针法
struct Stu *ps = &s;
printf("第二种:%s %d %lf\n",(*ps).name,(*ps).age,(*ps).score);//结构体解引用.成员变量
//指针箭头法->
printf("第三种:%s %d %lf\n",ps->name,ps->age,ps->score);//结构体指针->成员变量
return 0;
}