(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程

大家好,我Aaron, 对于学习编程的 hxd
们都有一个困扰,女朋友想了解你在干嘛却完全不懂代码怎么办,本文整理了C语言入门到进阶全知识点的概述以及基本用法,从此让你和女朋友一起幸福快乐的敲代码,该专栏后期会出C语言知识点详解和进阶和各种经典例题喔~感兴趣的朋友们可以订阅下来慢慢学习!!

✪ ω ✪ ✪ ω ✪

 点赞 +  关注  +  ✔收藏✔    

正文开始(老爷点个收藏慢慢看~)

文章目录

  • 前言
  • 一、什么是C语言
  • 二、第一个C语言程序
  • 三、数据结构
  • 四、 变量,常量
    • 4.1 变量的定义方法
    • 4.2 变量的分类
    • 4.3 变量的使用
    • 4.4变量的作用域和生命周期
    • 4.5 常量
  • 五、 字符串 + 转义字符
    • 1.字符串
    • 2.转义字符
  • 六、注释
  • 七、选择(分支)语句
  • 八、 循环语句
  • 九、 函数
  • 十、 数组
    • 10.1 数组定义
    • 10.2 数组的下标
    • 10.3 数组的使用
  • 十一、 操作符
  • 十二、 常用关键字
    • 12.1 关键字typedef
    • 12.2 关键字 static
  • 十三、 #define 定义常量和宏
  • 十四、 指针
    • 14.1 内存
    • 4.2 指针变量的大小
  • 十五、结构体
  • 总结


前言


本文旨在完整介绍C语言所学内从,是C语言专栏中的第一版,有兴趣完整的,系统的学习C语言知识的读者可以订阅本专栏,博主将会努力整理,博主准备的C语言专栏总共有三版。本专栏会介绍到很多计算机底层知识,建议收藏,慢慢学习嗷!

本文目标:
基本了解C语言的基础知识,对C语言有一个大概的认识
每个知识点就是简单认识,不做详细讲解,专栏后期都会细讲

全文重点

  • 什么是C语言
  • 第一个C语言程序
  • 数据类型
  • 变量、常量
  • 字符串 + 转义字符 + 注释
  • 选择语句
  • 循环语句
  • 函数
  • 数组
  • 操作符
  • 常见关键字
  • define 定义常量和宏
  • 指针
  • 结构体

正文开始

一、什么是C语言

C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

尽管C语言提供了许多低级处理的功能,但任然保持着良好的跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台

二十世纪八十年代,为了比年各开发厂商用的C语言语法差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法名称为ANSI C,作为C语言最初的标准,目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言最新的标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程

C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同

其编译器主要有Clang、GCC、WIN - TC、MSVC、Turbo C等。

接下来介绍其中我们必须要了解和掌握的!

什么是C语言呢?

C语言就是一种计算机语言

我们如何理解计算机语言?
其实将计算机语言和我们日常的语言类比起来就很好理解了

  • 计算机语言 - 人和计算机交流的语言(C/C++/Java/Python…)
  • 语言 - 人和人交流的语言(汉语、英语、日语)

C语言广泛运用于底层开发

如图:

这里的应用软件的开发被称为顶层开发
操作系统、驱动、硬件的开发则被称为底层开发

(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第1张图片

任何一门没有国际标准的语言,都不能被称为一门好的语言,而C语言,恰好有!!

C标准:
C语言出现 --> C语言标准:
K & R
C89 --> C90 --> C98 --> C99 --> C11
二进制 --> 二进制代码 --> 助记符(汇编语言) --> B语言 --> C语言
二进制:用0/1表示
在早期,用一个二进制代码表示一种算法,如:
00001011 - 加法 - ADD


编程工具:编译器

  • VC6.0 - 98年的软件(过于古老,不建议使用)

推荐使用:

  • VS2013 / VS2019 - 企业中常用的编译器

IDE - 集成开发环境,调用的是底层的MSVC编译器

  • Linux - gcc

  • Linux - clang

  • DEV - C++ - 学校推荐的!!!不建议使用,已经十几年不再更新了

二、第一个C语言程序

写一个C语言代码步骤:

  1. 工具(编译器) - VS2019

如果有码友使用的是VS2013版本的编译器,可能会遇到程序运行结果一闪而过的情况

解决办法1:
设置项目属性 --> 链接器 --> 系统 --> 子系统 --> 控制台

解决办法2:
使用系统控制命令

system(“pause”);

# include 
# include 

int main()
{
     
    printf("hehe\n");
    //system是一个库函数
    //是用来执行系统命令的
    //pause - 暂定
    system("pause");
    
    return 0;
}

system是一个库函数,是用来执行系统命令的,需要调用

#include - - 头文件
pause - 暂停控制台的作用


  1. 写代码
    1. 创建项目
    2. 创建源程序
    3. test.c - 源文件
      test.h - header头文件

    4. 写出main函数
#include 
//stdio.h 是一个头文件的名称
//std - 标准,i - input,o - output
//标准输入输出头文件

int main()  //  int - 整型
{
     
    //实际运行的代码
    //打印hello world
    //打印函数 - printf - 库函数,库函数的使用得引用头文件的
    printf("hello world\n");
    return 0;
}

printf - 打印函数 - 库函数,库函数的使用得引用头文件

标准输入输出
stdio.h 是一个头文件的名称
std - 标准, i - input, o - output

  1. 运行代码
    1. 快捷键:

      ctrl +F5 / ctrl + Fn + F5

    2. 按键

这里补充一点关于键盘上 Fn 键的知识


补充
Fn - 辅助功能键
F1 - F12本来是在变成中被赋予了相应的功能
但为了迎合大众小白用户的使用体验,有些键盘中赋给了F1 - F12键新的功能,如果想要使用这些键原本的功能,则需要按住 Fn + F1 - F12即可使用他们原本的功能
但这知识针对某些机器或者键盘所具有的功能辅助键,并不是所有的都需要这样操作
而且有的键盘上的 Fn 键是可以关闭的,可根据自身硬件采取相应措施
据博主目前测试,大部分笔记本电脑是会有 Fn 键的,而台式机基本都是应键盘而异,有的有,有的没有,有的像博主这样的,可以关闭,很方便,美滋滋。



C程序写法
写C语言代码时,虽然 VS2019 对 C99 标准并不是很支持,但我们现在敲代码基本采用 C99 的新写法为主,接下来展示C99和C89两种主函数的写法

# include 
//按F10

//main 函数是C语言程序的入口
//代码是从main函数的第一行开始执行的
//main函数有且只有一个

//C99 中引入的写法
int main()
{
     
    printf("hello world\n");
    printf("hello world\n");
    printf("hello world\n");
    printf("hello world\n");
    printf("hello world\n");
    
    return 0;
}
// 早期的写法
void main()
{
     
    
}

main 函数是C语言程序的入口
代码是从main函数的第一行开始执行的
main 函数有且只有一个
并且 main 函数可以放在程序的任意位置


三、数据结构

C语言是计算机语言
使用计算机语言写代码 - 写程序
程序是用来干什么的? - 程序是用来解决我们日常生活中的问题的
解决我们生活中的问题,比如:

购物 - - 网上购物 - 网上商城 - 淘宝 - 京东
模拟生活中的购物,然后在网络上解决购物问题

写程序就是利用各种各样的算法来解决如同上述这样的问题,其实我们的网购就是利用了很多高级的算法和程序拼接在一起实现的

既然要解决日常问题,那我们在生活中的数据是各式各样的,如果C语言想要描述这些数据,就需要存在与之相匹配的数据类型

比如:
50 - 是整数 使用 int 整型类型
55.5 - 是小数 使用 float / double 浮点数类型

下面把C语言中的数据类型一一罗列:

char                //字符数据类型
short               //短整型
int                 //整型
long                //长整型
long long           //更长的整型
float               //单精度浮点型
double              //双精度浮点型

我们在此可以思考一下:C语言中有没有字符串类型呢?

以下为C语言中数据类型的分类整理

字符类型
char
整型
short [int]
int
long [int]
long long [int]
浮点型
float - 单精度浮点型
double - 双精度浮点型

小数为什么在C语言中被称为浮点数呢?

123.45
12.345 * 10
1.2345 * 100
如上所示
因为小数点可以浮动,所以叫做浮点型

那么每种数据类型的所占内存空间大小是多少呢?
我们可以通过写代码来验证和计算
这里就要用到我们的 sizeof 操作符,一个专门用来计算占内存空间大小的操作符

代码如下:

#include 
int main()
{
     
    //printf - %d - 打印有符号数
    //printf("%d\n", 100);
    printf("%d\n", sizeof(char));
    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;
}

这里注意, 如果 sizeof 的操作数是变量,括号是可以省去的,但如果 sizeof 的操作数是数据类型,这个括号不可以省略,否则会报出语法错误,无法通过编译的!!!

运行结果:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第2张图片
控制窗口打印了这些数字,那么他们的单位又是什么呢?

接下来就要介绍计算机中的单位了
计算机中的单位总共有如下这么几种:
bit byte kb mb gb tb pb
而我们的计算机能够识别的是二进制(0/1) --> 我们规定一个比特位只能存放一个二进制位,得出如下单位换算:
1byte = 8bit
1kb = 1024byte
1mb = 1024kb
1gb = 1024mb
1tb = 1024gb
1pb = 1024tb

sizeof 计算的单位是byte - 字节

C语言标准规定:
sizeof (long) >= sizeof (int)
sizeof (long long) >= sizeof (long)
在64位机器上:sizeof (long) = = 8
在32位机器上:sizeof (long) = = 4

所以 long 类型不一定比 int 类型大
而 long long 类型也不一定比 long 类型大
这都是要取决于代码处在多少位的机器上决定的。

那么为什么会出现这个多的类型呢?

其实很简单

举个例子:
钱的数目不同:可以有100元 10000元 10000000元 100亿
年龄大小可以不同:可以有 10 岁,20 岁,100岁
不同大小的值存放在不同的类型中,可以避免浪费内存
比如用一个 long long 类型的变量去存放一个数字 20 ,实在是有些铺张浪费了
又或者如果用 char 存放 100 亿,那也存不下呀,所以我们需要有灵活的数据类型存放不同的数据

代码展示:

#include 
int main()
{
     
    int age += 20;//age 在内存中分配4个字节的空间
    char ch = 'w';//ch 在内存中分配1个字节的空间
    short = age;
    //类型 变量名   值
    int salary = 10000;
}

注意:存在这么多的类型,其实是为了更加丰富的表达生活中的各种值

四、 变量,常量

生活中有些值是不变的(比如:圆周率,性别(?),身份证号码,血型等等)。
有些值是可变的(比如:年龄,体重,薪资)。
不变的值,C语言中用常量的概念来表示,变的值C语言中用变量来表示。

4.1 变量的定义方法

定义一个变量,有一个固定的写法:

变量类型 + 变量名 + 赋初值
如:int a = 10;

代码展示:

#include 
int main()
{
     
    int age = 20;
    float weight = 55.8;
    return 0;
}

4.2 变量的分类

变量分为两类:

  1. 全局变量
  2. 局部变量

下面用代码的形式给大家演示,方便理解

#include 
//全局变量 - 在大括号外部定义的变量就是全局变量
int a = 100;

//局部变量就是在main函数中定义的变量 - 对不对? - error

void test()
{
     
    int b = 10;
}

int main()
{
     
    //局部标量 - 在大括号(代码块)内部定义的变量就是局部变量
    int a = 10;
    printf("a = %d\n", a);//局部变量和全局变量名字冲突(一样)的情况下,局部优先
    return 0;
}

总结:

上面的局部变量global变量的定义其实是没有什么问题的!
局部变量和全局变量名字冲突(一样)的情况下,局部优先

全局变量 - 在大括号外部定义的变量就是全局变量
局部标量 - 在大括号(代码块)内部定义的变量就是局部变量

4.3 变量的使用

下面用代码的形式给大家展示变量在创建之后是如何使用的:

int main()
{
     
    int num1 = 0;
    int num2 = 0;
    int sum = 0;
    
    //printf()是输出函数 - 库函数
    //scanf()是输入函数 - 库函数
    
    //scanf函数要正常使用,就得在scanf所在的源文件的第一行加上#define _CRT_SECURE_NO_WARNINGS 1
    scanf("%d %d", &num1, &num2);
    
    sum = num1 + num2;
    
    printf("sum = %d\n", sum);
    
    return 0;
}

大家在使用编译器写代码的时候,难免会经常遇到一个问题:
总用如下所示的安全警告
请添加图片描述
这就是函数不安全问题

解决方法1:在当前代码第一行加上
请添加图片描述

_CRT_SECURE_NO_WARNINGS

如果每次写代码都要复制一次,未免太过于繁琐,所以给出了一劳永逸的方法:

找到VS安装路径 --> 找到newc++file.cpp文件 --> 编辑文件,在文件中加上上面这句话
之后每次使用会自动生成

解决方法2:我们可以看到警告后面会提示我们使用 scanf_s 函数,但博主这里建议大家使用第一种方法,因为 scanf_s 是编译器里的函数,C语言各种版本中没有这种函数,所以以后如果我们将代码放在其他编译器上运行,就会跑不起来,是我们的代码不具有可移植性

其他不安全的函数:strcat / strcpy

那么为什么会出现不安全的现象呢?

给出不安全示范代码如下:

//%d - 整型
//%s - 字符串

int main()
{
     
    char arr[5] = {
     0};//数组
    scanf("%s", arr);
    //scanf_s不是C语言的,是VS编译器提供的
    //如果你的代码中使用了scanf_s函数,你的代码可能在其他的编译器上无法编译
    printf("%s\n", arr);
    
    return 0;
}

运行结果:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第3张图片
如上述代码和运行结果可知,我们在定义数组的时候,只创建了大小为5的数组,而我们在输入的时候,如果输入的字符个数大于5,则会导致程序崩溃,这也就是函数为什么会不安全的原因

但是就算使用上述方法,也只不过是让编译器不再警告,也就是忽略警告的作用,让我们的代码可知正常跑过去,但我们还是要人为的控制输入字符的个数,不要让输入的字符过多,导致数组越界,程序崩溃。

4.4变量的作用域和生命周期

1)变量的作用域:

作用域(scope):程序实际概念,通常来说,一段程序中所用到的名字并不总是有效 / 可用的,而限定这个名字的可用性代码返回就是这个名字的作用域。

  1. 局部变量的作用域就是局部变量所在的局部范围
  2. 全局变量的作用域是整个工程

下面看两个代码解释:

代码1:

#include 
void test()
{
     
    int b = 100;
}

int main()
{
     
    {
     
        int a = 10;
    }
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    return 0;
}

这段代码的结果无法打印 a, b
因为 a 的作用域只能在自己的代码块内
b 只能在 test 函数内部使用

代码2

#include 

int g_val = 100;

void test()
{
     
    printf("g_val = %d\n", g_val);
}

int main()
{
     
    printf("g_val = %d\n", g_val);
    test();
    return 0;
}

可以打印两个 g_val = 100,因为 g_val 是定义在全局范围内的,在整个工程中都可以使用

生命周期:

变量的生命周期值指的是变量的创建到变量的销毁之间的一个时间段

  1. 局部变量的生命周期是:进入作用域(局部范围)生命周期开始,出作用域(局部范围)生命周期结束。
  2. 全局变量的生命周期是:整个程序(main函数)的生命周期
#include 
int main()
{
     
    {
     
        int a = 100;
        printf("1: a = %d\n", a);
    }
    printf("2: a = %d\n", a);
    
    //程序的生命周期和main函数的生命周期是一样的
    //全局变量的生命周期和程序,main函数的生命周期是一样的
    
    return 0;
}

打印结果为 1:a = 100
局部变量 a 在进入代码块时创建,出这个代码块之后就会销毁,遇到第二个 printf 函数时已经不存在 a 这个变量了

全局变量演示:
test1.c

int g_val = 2000;

test2.c

#include 

//声明外部变量
extern int g_val;  //  --  extern 关键字是声明关键字,在做声明时使用

int main()
{
     
    printf("g_val = %d\n", g_val);  // 2000
    
    return 0;
}

以上代码说明:全局变量可以在不同的源文件内起效用,但需要在使用之前提前声明(使用 extern 关键字)

4.5 常量

C语言中的常量和变量的定义的形式有所差异

C语言中的常量分为以下几种:

  • 字面常量
  • const 修饰的常变量
  • #define 定义的标识符常量
  • 枚举常量

下面 一 一 介绍

  1. 字面常量

就是类似于普通数字一样的常量,无法改变

下面用代码演示:

#include 
int main()
{
     
    "abcdef";
    3.14;
    100;
     
    return 0;
}
  1. const 修饰的常变量

一个变量在被 const 修饰之后就会具有了常属性,但本质上还是一个变量
在C99版本之前,被const 修饰的变量不能放在数组中使用作为数组的大小
但是在C99版本之后,引入了变长数组的概念,可以将被 const 修饰的变量放在数组定义大小的方括号( [ ] )内使用

#include 
int main()
{
     
    const int num = 10;
    num = 20;//对常变量进行赋值, num 的值无法被修改
    printf("%d\n", num);  // 结果依然是10
    
    const int n = 10;// n 虽然被 const 修饰,但本质上还是一个变量,不能用来被指定为数组的大小(C99版本之前)
    int arr[n] = {
     0};
    //在C99标准之前,数组的大小只能是常量
    //VS2019对C99支持的不是很好啊
    //不支持变长数组,所以会报错
    
    return 0;
}

在C99标准之前,数组的大小只能是常量,但是在C99版本之后,数组的大小可以用变量来表示,即为变长数组。
但是博主使用的编译器是: VS2019 ,而VS2019对C99标准支持的并不是很好啊,不支持变长数组,所以会报错,所以我们还是要对自己使用的编译器稍作了解,再结合不同的C语言标准版本去学习,效果才能最优!!!

  1. #define 定义的标识符常量

#define 定义的标识符常量其实就是给定一个符号,让他代表你在代码里想要表示的值,代码在编译过程中,会将所有的符号替换成给定的值

下面用代码给大家演示 #define 定义标识符常量的效果和用法:

#include 

#define MAX 100    // 注意用 #define 定义的时候,语句后面没有分号(;)

int main()
{
     
    printf("%d\n", MAX);
    MAX = 200; // err, 不能改变
    int arr[MAX] = {
     0};// 是可以的
    
    return 0;
}

我们要注意在使用 #define 定义的时候,语句后面没有分号(;),并且在习惯上用 #define 定义的标识符,我们都用大写字母表示。
因为用 #define 定义的标识符常量其本质上还是一个常量,代码在编译的过程中只是将其替换,所以在定义数组大小的过程中是可以使用被 #define 定义的表示符常量的,而且并不是变长数组。

  1. 枚举常量

我们在生活中会遇到很多可以 一 一列举的常量,这些常量在C语言中就被称为枚举常量。

比如:

性别:男(MALE),女(FEMALE),保密(SECRET)
三原色:R,G,B

下面用代码演示枚举常量的用法:

#include 

//enum 枚举关键字
enum Sex
{
     
    //枚举变量
    MALE = 5, // 定义时赋初值是可以的
    FEMALE,
    SECRET
};  // -- 枚举常量的定义需要在代码块末端加上分号(;)

int main()
{
     
    enum Sex s = FEMALE;
    //MALE = 5;  err 不能改,枚举是常量但可以在定义时赋初值
    printf("%d\n", MALE);
    printf("%d\n", FEMALE);
    printf("%d\n", SECRET);
    
    return 0;
}

注意使用枚举关键字定义枚举常量时,代码块后面的分号不能少!!
我们在默认状况下打印 MALE, FEMALE, SECRET 时,打印的是 0, 1, 2,这是编译器默认的,而且其本质就是个常量,所以我们后期无法对其进行修改或者赋值,如果想要让枚举常量具有我们想让它有的值,只能用过在定义时就对其进行赋初值,赋成我们想要的值!

五、 字符串 + 转义字符

1.字符串

我们都知道数据类型有:char int long …
那么有没有字符串类型呢?
答案是C语言中没有字符串类型

C语言中字符串的表示形式:

“hello world!\n”

这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串

ps:字符串的结束标志是一个 ‘\0’ ,在计算字符串长度的时候 \0 是结束标志,不算作字符串的内容

字符串用法代码演示:

#include 

int main()
{
     
    //"abcdef";
    //字符串可以存放在字符数组中
    char arr1[] = "abc";// 在字符串的末尾隐藏了一个\0,这个\0是字符串的结束标志
    char arr2[] = {
     'a', 'b', 'c'};
    printf("arr1 = %s\n", arr1);
    printf("arr2 = %s\n", arr2);
    
    return 0;
}

打印结果为:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第4张图片
我们可以通过试验发现,如果在 arr2 后面加上一个 ‘\0’,则打印的结果会相同
原因是 arr2 中如果没有 \0 判断字符串结束标志,那么就会继续访问内存中后面的内容,而这些内容都是编译器预先放进的随机值,当遇到内存中的 \0 (或者 0) 时,就停下来。

为解释 \0 的作用,下面再举一个例子,方便大家掌握,
代码:

#include 
#include 

int main()
{
     
    char arr1[] = "abc";
    cahr arr2[] = {
     'a'. 'b', 'c'};
    
    //库函数 - strlen - string lenth
    //string.h
    int len1 = strlen(arr1);
    int len2 = strlen(arr2);
    
    printf("len1 = %d\n", len1);
    printf("len2 = %d\n", len2);
    
    return 0;
}

打印结果:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第5张图片
首先 strlen 是一个计算字符串长度的库函数,在遇到 \0 后就停下来,计算遇到 \0 之前访问过得字符个数。len1 是 3很好理解,但是 len2 为什么是15呢?其实他的值不是永远都是 15 的,而是一个大于等于 3 的随机值
因为 arr2 中没有 \0 ,所以 strlen 函数会继续越界访问内存中的其他后面的内容,直到访问到内存中存放的 0 (或者 \0),就停下来,计算访问过的字符的个数,也就是字符串的长度

len1 :a, b, c, \0 在算到 \0 之前有3个字符,所以 len1 = 3;
len2 :a, b, c, …在 c 后面没有 \0 ,所以会一直访问内存后面的内容,遇到 \0 之前访问了 15 个数,是随机的。

再给出一个代码:

下面代码,打印的结果是什么?为什么?
(突出 ‘\0’ 的重要性)

#include 

int main()
{
     
    char arr1[] = "bit";
    char arr2[] = {
     'b', 'i', 't'};
    char arr3[] = {
     'b', 'i', 't''\0'};
    printf("arr1 = %s\n", arr1);
    printf("arr2 = %s\n", arr2);
    printf("arr3 = %s\n", arr3);
    return 0; }

2.转义字符

刚才一直说到 \0 ,那他到底是个什么东西呢?

其实 \0 就是是一个字符 - 转义字符 - 转变原来的意思的字符

给出一个代码,大家看一下:

代码:

#include 

int main()
{
     
    printf("abcdef\n");
    printf("\0");
    printf("---------\n");
    printf("abc\ndef\n");// \n --  换行
    return 0;
}

请大家思考片刻,你们认为这段代码的运行结果是什么呢?
.
.
.
.

.
.
.
.

运行结果结果:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第6张图片
\0 被转义为结束标志,不再是原来的字符 0,所以不会打印
n 加上 \ 变成 \n ,被转义为换行,不再是原来的字符 n ,所以在 abc 后面换行再输出 def

假如我们要在屏幕上打印一个目录:c:\code\test.c
我们该如何写代码?

下面给大家展示转义字符的效果:
代码:

#include 
int main()
{
     
    printf("c:\code\test.c\n");  //  \t - 水平制表符
    return 0;
}

运行结果结果:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第7张图片

这样就不得不提一下转义字符了。转义字符顾名思义就是转变意思,下面看一些转义字符:

给大家附上一张常用转义字符表(建议存起来,用到的时候可以查一查,不用特意去背出来):

转义字符 释义
\ ? 在书写连续多个问号时使用,防止它们被解析成三字母词
\ ’ 用于表示字符常量 ’
\ " 用于表示一个字符串内部的双引号 "
\ \ 用于表示一个反斜杠,防止它被解释成一个转义序列符
\ a 警告字符,蜂鸣
\ b 退格符
\ f 进纸符
\ n 换行
\ r 回车
\ t 水平制表符
\ v 垂直制表符
\ ddd ddd表示1-3个八进制的数字,如:\130
\ xdd dd表示2个十六进制数字,如:\x30

下面简单解释几个比较难懂的转义字符:

  • 三字母词 - ??) --> ]
    ??( --> [

    在问号前加上 \ 让它变成普通的 ?,不再构成三字母词
    现在大部分编译器上都无法演示三字母词了,用的太少!!!,导致很多编译器直接就不支持这种写法了,我们在这里作为了解即可

  • 打印单引号、双引号

代码演示:

#include 
int main()
{
     
    // %c - 字符格式
    // %s - 字符串
    printf("%c\n", '\'');
    printf("%s\n", "\"");
    
    return 0;
}

输出结果为一个单引号 ’ 和一个双引号 "
加上 \ 让其变成普通的单引号或者双引号,不再是和另一个单引号或者双引号结合构成的效果


ASCII编码

我们知道在键盘上有很多的字符: a % & & 9 0 i o 但是计算机只能识别二进制,所以给所有的字符一个编号,这些编号就叫做ASCII编码

#include 
int main()
{
     
    //十进制数字由0-9
    //十六进制数字:0-9 a b c d e f
    printf("%c\n", '\162');
    printf("%c\n", '\071');//57
    printf("%c\n", '\x5a');
    return 0;
}

第一行的运行结果为一个字符 r
分析:
\162 是转义字符\ddd 的形式,表示的是一个三位的八进制数字,八进制数字 162 转化为十进制数字对应的是 114,在ASCII码中对应的字符是 r

这里给大家放上一张博主珍藏多年的 ASCII 码值表,建议保存,不用背,遇到了就查一查!!!

(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第8张图片

简单介绍一下几个0:
0 数字0
\0 是一个转义字符 - ASCII值是0
‘0’ 字符0 - ASCII码值是48

下面看一道曾经某公司的笔试题:

代码:

#include 
#include 

int main()
{
     
    printf("%d\n", strlen("abcdef"));  // 6
    printf("%d\n", strlen("abc\0def"));  // 3
    printf("%d\n", strlen("c:\test\328\test.c"));  // 14
    //识别转义字符
    // \t, \32
    
    return 0;
}

这里特别注意:
第二行,遇到 \0 之后结束运行,后面的字符直接不进行计算了
第三行,\32 是一个转义八进制数字,8是一个单独的字符
虽然我们 \ddd 表示转义三个八进制数字,但我们应该了解,二进制数字是 0/1,八进制数字是 0-7, 十进制数字是 0-9 ,十六进制数字是0 - 9 + a b c d e f,也就是0 - 15,所以这里的 \328,8明显不是八进制数字,所以我们应该把 \32 看做一个字符,把 8 看做一个字符

六、注释

注释的用处:

  1. 代码中有不需要的代码可以直接删除,也可以直接注释掉
  2. 代码中有些代码比较难懂,可以加一下注释文字
#include 
int main()
{
     
    //printf("hehe\n");
    //此时运行不会出现任何结果
    
    int arr[10] = {
     0}; // 创建一个整型数组,10个元素
    return 0;
}

下面用代码演示C++和C语言两种不同风格的代码注释

  • C++注释风格(只能注释一行)
    // 这里是注释
    
  • C语言注释风格(可以注释多行)
/*
         这里是注释
*/

C语言的这种注释风格不支持嵌套使用,一般不建议,并且现在大多数编译器在编写C代码时是支持C++风格注释的,所以我们在平常使用的时候可以多使用C++注释风格

完整代码给大家展示一下注释的用法:

代码:

#include 
int Add(int x, int y) {
     
    return x+y; }
/*C语言风格注释
int Sub(int x, int y)
{
    return x-y;
}
*/
int main()
{
     
    //C++注释风格
    //int a = 10;
    //调用Add函数,完成加法
    printf("%d\n", Add(1, 2));
    return 0; }

七、选择(分支)语句

如果你好好学习,校招时拿一个好offer,走上人生巅峰,迎娶白富美!!!! 如果你不好好学习,毕业等于失业,只能回家卖红薯

这,就是选择!

选择语句(分支语句)流程图:

(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第9张图片
选择语句又叫分支语句

一般有以下两种选择(分支)语句

  • if else
  • switch

这里用代码演示 if else 语句用法:

#include 

int main()
{
     
    int num = 0;
    //1 0
    printf("进入学校\n");
    printf("你要好好学习吗?(选择1/0):\n");
    scanf("%d", &num);
    if (1 == num)   //  -- 写成 1 == num ,避免少些一个等号导致程序出bug
    {
     
        printf("坚持,拿到好offer\n");
    }
    else
    {
     
        printf("放弃,回家卖红薯\n");
    }
        
    return 0;
}

注意: 博主在 if 语句后边的判断语句中写成了 1 == num ,而不是 num == 1,这样写的目的是为了防止在写代码的时候,不小心漏掉一个等号,导致运行结果错误,程序产生 bug,这样写的好处是,如果少写了一个等号,会导致编译错误,程序无法正常编译,更不可能产生 bug。

八、 循环语句

有些事我们必须一直做,比如老师日复一日的讲课,学生日复一日的学习,我们日复一日的敲代码

循环语句流程图:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第10张图片
C语言中如何实现循环呢?:

  • for语句 - (专栏下期讲)
  • while语句 - 演示
  • do … while语句 - (专栏下期讲)

下面给出 while 循环的代码实例:

代码:

#include 

//while 循环的实例
int main()
{
     
    int line = 0;
    printf("进入学校\n");
    
    while (line <= 20000)
    {
     
        printf("我要努力敲代码!:%d\n", line);
        line++;
    }
    if (line > 20000)
    {
     
        printf("拿到好offer,迎娶白富美!!\n");
    }
    
    return 0;
}

九、 函数

我们从小学习数学,就一定会学到函数:
数学里的函数:
f (x) = 2 * x + 1

那么变成中的函数又是怎么一回事呢?
来吧,展示!
编程中的函数:

代码:

#include 

int Add(int x, int y)
{
     
    int z = 0;
    z = x + y;
    return z;
}

int main()
{
     
    int num1 = 0;
    int num2 = 0;
    int sum = 0;
    scanf("%d %d", &num1, &num2);
    //求和
    //sum = num1 + num2;
    sum = Add(num1, num2);
    printf("%d\n", sum)
    return 0;
}

在主函数中调用函数,在调用之前定义或者声明被调用函数,在函数调用中传入实参,在函数中定义相同类型形参接收实参,被调用函数返回值类型应当与函数类型保持一值,被调用函数返回值应当被相同类型变量接收,形成函数调用链。

其中函数调用涉及函数栈帧的内容,如果码友们有需要可以在评论区留言,博主去搜集整理!

函数的特点就是简化代码,代码复用,不同分工

十、 数组

想要存储 1- 10 的数字,应该怎么办?
C语言中给了数组的定义:一组相同类型元素的集合

10.1 数组定义

数组中元素类型 + 数组名 + 【数组大小】 + 初始化内容

int arr[10] = {
      1,2,3,4,5,6,7,8,9,10 };

10.2 数组的下标

C语言规定的每个元素都有一个下标,下标是从0开始的。
数组可以通过访问下标来访问数组内容。

如果数组10各元素,下标范围是0-9

int arr[10] = {1,2,3,4,5,6,7,8,9,10};

数组下标演示表:

int arr[10] 1 2 3 4 5 6 7 8 9 10
下标 0 1 2 3 4 5 6 7 8 9

10.3 数组的使用

数组使用代码演示:

#include 

int main()
{
     
    //数组
    // 0-9
    //arr[10] - 表示下标为10的元素
    int arr[10] = {
     1,2,3,4,5};//不完全初始化,剩下默认初始化为0
    int arr[10] = {
     1,2,3,4,5,6,7,8,9,10};
    printf("%d\n", arr[4]);
    int i = 0;
    //计算数组的元素个数
    //sizeof(arr)  计算的是数组的总大小,单位是字节
    //sizeof(arr[0])  计算的是数组的第一个元素的大小  单位是字节  -  4
    int sz = sizeof(arr) / sizeof(arr[0]);
    while (i = 0; i < 10; i++)
    {
     
        printf("%d ", arr[i]);// arr[i] 不是数组,是数组元素,i是变量
        i++;
    }
    return 0;
}

计算数组大小的方式:sizeof (arr) / sizeof (arr[0])
读者可能有的疑惑博主都在注释中做了解释,如果有其他问题,可以在下方评论区留言!

十一、 操作符

进行简单的介绍:

算数操作符

+ - * / %

用法:

代码演示:

#include 

int main()
{
     
    int a = 7 / 2;
    int b = 7 % 2; // 取模、余
    printf("%d\n", a); // 3
    printf("%d\n", b); // 1
    float f = 7 / 2.0;
    printf("%f\n", f); // 3.5
    
    return 0;
}

这里我们需要注意的是,整型除以整型的结果还是整型,这一点是永远不会变的,所以哪怕我们定义的变量是 float 或者是 double 类型的,7 / 2 的结果还是 3 ,如果想要得到正确的值,就必须将其中一个整型改为浮点型,比如:7.0 / 2 或者 7 / 2.0 ,这样的结果才会算出 3.5 ,请大家注意!

移位操作符

<< >>

用法:

代码演示:

#include 

int main()
{
     
    int a = 12; // a是整型,4个字节,32个bit
    //00000000000000000000000000001100
    int b = a << 1; // 左移操作符
    // 移动的是二进制位
    printf("%d\n", b); // 24
    
    return 0;
}

这里给大家解释一下:
a = 12的二进制序列如下:
00000000000000000000000000001100
右移一位
00000000000000000000000000011000
结果就为24

位操作符

& :按(2进制)位与
| :按(2进制)位或
^ :按(2进制)位异或

用法:

代码演示:

#include 

int main()
{
     
    int a = 3;
    int b = 5;
    //00000000000000000000000000000011
    //00000000000000000000000000000101
    
    //00000000000000000000000000000001   与
    //00000000000000000000000000000111   或
    //00000000000000000000000000000110   异或
    
    int c = a & b;  // 按位与 - 对应的二进制位有0则为0,两个同时为1,才是1
    int d = a | b;  // 按位或 - 对应的二进制位有1则为1,两个用时为0,才是0
    int e = a ^ b;  // 按位异或 - 相同为0,相异为1
    
    printf("%d\n", c); // 1
    printf("%d\n", d); // 7
    printf("%d\n", e);
    
    return 0;
}

赋值操作符:

= , += , -= , *= , /= , &= , |= , ^= , >>= , <<=

使用:

代码演示:

#include 

int main()
{
     
    int a = 10;// 初始化
    float score = 0.0;
    a = 45; // 赋值
    score = 95.5; // 直接写出来的浮点数默认是double类型
    //95.5f - 指定为float类型
    
    a = a + 5; //1
    a += 5;    //2 复合赋值符
    
    a *= 5;
    a /= 5;
    
    return 0;
}

单目操作符

将单目操作符之前,先解释一下双目操作符,对比起来看,就好理解了。

双目操作符

int main()
{
     
    3 + 5;//  + 操作符
    //3 和 5 是操作数
    //3是左操作符
    //5是右操作符
    //+ 是双目操作符
    return 0;
}

对于一个操作符而言,有两个操作数,就叫做双目操作符,
那么单目操作符,也就是对于一个操作符而言,只有一个操作数,那么这个操作符就被称为单目操作符

下面给出一张表,介绍常用的单目操作符:

单目操作符
逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
- - 前置、后置- -
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换

单目操作符 - 只有一个操作数的操作符

下面简单介绍几个单目操作符的用法:

  • 逻辑反操作: !

顾名思义,就是把真的变成假的,假的变成真的,就叫做逻辑反操作

代码演示:

#include 

int main()
{
     
    int flag = 1;
    //C语言是如何表示真假的?
    //0就是假, 非0就是真
    
    //flag为真就打印hehe
    if (flag)
    {
     
        printf("hrhr\n");
    }
    if (!flag)
    {
     
        printf("haha\n");
    }
    
    int a = !flag;
    printf("%d\n", a); // 非0默认打印1
    
    return 0;
}

表示真假,即为逻辑操作
但这里可能会有小伙伴陷入误区,C语言规定,0为假,并不是1才是真,所有的非0都为真,只不过我们在编译器上打印逻辑真的时候,编译器默认打印1而已,并不是只有1为真!!!

  • 正负操作符:+ -

这个跟生活中或者数学里的正负是一样的,不过多介绍,直接上代码:

代码演示:

#include 

int main()
{
     
    int a = -10;
    // a = -a;
    
    int b = +a;
    printf("%d\n", b);
    
    return 0}

这个概念比较简单易懂,尤其是正号(+)在写代码时用的很少,这里的是正负号,而不是加减号,可不敢轻易弄混了!!

  • sizeof 操作符

需要注意:
sizeof 是操作符, 不是函数
操作符也叫作运算符

用法:用于计算所占内存空间的大小的一个操作符

代码展示:

#include 
int main()
{
     
    int a = 10;
    int arr[10] = {
     0};
    int sz = sizeof(arr) / sizeof (arr[0]); 
    printf("%d\n", sizeof(int)); // 4
    printf("%d\n", sezeof(a)); // 4
    printf("%d\n", sizeof a); // 4
    printf("%d\n", sizeof(arr)); // 40
    printf("%d\n", sizeof(arr[0])); // 4
    printf("%d\n", sz); // 10 
    
    return 0;
}

可以看出,sizeof 计算变量所占空间大小时,可以写成 sizeof a ,把括号给省略了,但我们可不敢随便乱写,在计算 int 或者 long 这样的数据类型所占空间大小的时候,可不能轻易把括号给省略了;
使用 sizeof 还有一点需要注意,就是计算字符串所占空间大小的时候,虽然我们看不见字符串末尾隐藏的0,并且有strlen函数计算的时候也算不到这个\0,但它在内存中可是真实存在的,所以 sizeof 计算时也是会把 \0 所占内存空间的大小给算进去的!!

  • 按(2进制)位取反操作符: ~

用法:
如果一个整数存储在内存中的二进制序列是:
00010101001010101000101010100010

那么它的按位取反则是:
11101010110101010111010101011101

讲到按位取反操作符就不得不介绍原反补码的知识:

原反补

计算机在内存中存放的也是二进制
而整数在内存中存放的是二进制的补码
整数的二进制怎么表示呢?
整数的二进制表示方式有 3 种:
原码 - 直接按照数字的正负转换成二进制就是原码
反码 - 源码的符号位不变,其他按位取反,就是反码
补码 - 反码 + 1,就是补码

规定:
对于有符号整数,二进制最高位是符号位
最高位是0,表示正数
最高位是1,表示负数
无符号数的原码、反码、补码相同
有符号数(负数)的原码、反码、补码要通过计算获得

下面看按位取反操作符的用法:

代码演示:

#include 

int main()
{
     
    //int a = 0; // 32bit
    //00000000000000000000000000000000 - 原码
    //00000000000000000000000000000000 - 反码
    //00000000000000000000000000000000 - 补码
    //int b = -1;
    //10000000000000000000000000000001 - 原码
    //11111111111111111111111111111110 - 反码
    //11111111111111111111111111111111 - 补码
    
    int a = 0;
    //00000000000000000000000000000000 - 原码
    //11111111111111111111111111111111 - 取反后的结果 - 补码
    //11111111111111111111111111111110 - 反码
    //10000000000000000000000000000001 - 原码
    printf("~a = %d\n", ~a); // -1
    
    return 0;
}

我们的头脑要始终保持清晰,要知道,无符号整数其实是没有原码、反码、补码的
而有符号数在内存中存储的都是二进制的补码,要知道它代码多大的数,一定要通过计算得出

  • ++ - - 操作符

相信大家都有过跟博主一样悲惨的遭遇,就是遇到了这两个"可怕"的操作符,首先给大家展示一下博主在大一在学习C语言时遇到的期末考试题

#include 

int main()
{
     
    int a = 1;
    int b = (++a) + (++a) + (++a);
    
    printf("b = %d\n", b);
    
    return 0;
}

对于这样的代码,我只想用一个字来形容他,搓!!!!

其实这是一个错误的代码,千万不能写出这样的程序,也不要想这去研究这个代码,想着就是要理解它,算出他的值,有兴趣的码友们可以复制这段代码去不同编译器上跑一下试试,答案肯定是五花八门的,同一个代码在不同编译器下跑出来居然是不同的结果,这样的代码还有什么研究的价值吗?所以,希望大家在学习的时候遇到这样的代码直接跳过,千万不要想着去弄懂,这个代码本身就是错误的代码!!!!

接下来看看真正我们会用到的知识点:

代码演示:

#include 

int main()
{
     
    // ++ --
    int a = 10;
    int b = a++; // 后置++, 先使用,再++
    int c = ++a; ///前置++,先++,再使用
    
    printf("a = %d\n", a); // 12
    printf("b = %d\n", b); // 10
    printf("c = %d\n", c); // 12
    
    return 0;
}

我们唯一要会的就是前置++, - -和后置++,- -,所以这两个操作符其实还是很好学的。
大家可不要被错误的代码给带偏了喔!
ps(小声说:那些教我们这种代码的大学老师真的会编程吗??)

  • (类型),强制类型转换

用法:其实原理很简单,就相当于是亡羊补牢,发现自己的数据很所给的变量的数据类型不符合,编译器会报错,自己又懒得改或者特殊原因无法修改,加个强制类型转换就ok了,不过这里要提示一点:可不敢随便胡乱使用,毕竟是强制类型转换,一下搞不好就很容易丢失精度的!!

代码演示:

#include 

int main()
{
     
    int a = 3.14; // double -- > int
    int b = (int)3.14;// 将double强制类型转换为int
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    
    return 0;
}

这个操作符我们平时用的也很少,因为写代码一般要自己注意变量使用的规范,所以了解即可。

关系操作符

>
<
>=
<=
!=   // 用于测试:“不相等”
==   // 用于测试:“相等”

要注意将 == 和 = 两个操作符区分开

== :判断左右是否相等
!=:判断左右是否不相等
= : 一个等号是赋值操作符,将右值赋给左值

用法:

代码演示:

#include 

int main()
{
     
    int a = (3 > 5);
    printf("%d\n", a); // 0
    if (3 > 5)
    {
     
        printf("hehe\n"); // 不打印
    }
    
    return 0;
}

逻辑操作符

&&(逻辑与) | | (逻辑或)
他们的名字叫做逻辑操作符,也就是与和或,要和按位与和按位或区分开!
一个 & – > 叫做按(二进制)位与 或者取地址操作符,
两个 & – > && – > 叫做逻辑与
一个 | – > 叫做按(二进制)位或
两个 | – > || – > 叫做逻辑或

这边举个简单例子:
比如
法定结婚年龄为:
男:22
女:20
那么想要结婚就必须两个都满足,就要用到与逻辑

用法:

代码演示:

# include 
int main()
{
     
    int a = 25;
    int b = 19;
    // && 逻辑与 - 并且
    if ((a >= 22) && (b >= 20))
    {
     
        
    }
    // || 逻辑或 - 或者
    if ((a >= 22) || (b >= 20))
    {
     
        
    }
    return 0;
}

条件操作符(三目操作符)

格式:
exp1 ? exp2 : exp3
(exp表示表达式)

意思是先判断表达式1,如果表达式1满足,则整个表达式的结果为表达式2,如果表达式1不满足,则整个表达式结果为表达式3
光说理解得比较的抽象,直接上代码:

代码演示:

#include 

int main()
{
     
    int a = 10;
    int b = 20;
    int max = 0;
    //找出最大值
    /*if (a > b)
    {
        max = a;
    }
    else 
    {
        max = b;
    }*/
    //条件操作符
    max = (a > b) ? a : b;
    printf("max = %d\n", max);
    
    return 0;
}

可以看出,要实现找出两个数最大值,如果用普通的方法需要8行代码,最少也需要4行代码,但是如果使用三目操作符,一行就搞定了,你学废了吗?

逗号表达式

格式:
exp1, exp2, exp3, … expN
(exp表示表达式)

逗号表达式就是从左到右依次计算,然后将最后一个表达式的结果赋给整个表达式。

用法:

代码展示:

#include 
int main()
{
     
    int a = 3;
    int b = 5;
    int c = 6;
    // 逗号表达式 - 从左向右依次计算,整个表达式的结果是最后一个表达式的结果。
    int d = (a -= 2, b = a + c, c = a - b);  // -6
    // a = 1  b = 7  c = -6
    return 0;
}

注意在 int d 这行代码里,整个表达式结果是最后一个表达式的结果,赋给变量d,但其他的运算也是需要进行的,比如说,这里最后的结果a应该变成了1,b应该变成了7,然后才是c变成了-6,再将-6赋给我们的变量d。

下标引用操作符、函数调用操作符和结构体成员

[] , () , . , ->

看用法:
[] : 在数组中使用,叫做下标引用操作符
() : 在调用函数时使用,叫做函数调用操作符
. 和 -> 叫做结构体成员,在本文后面介绍结构体时给大家讲解

代码演示:

#include 

// int 表示函数调用完成之后返回一个整数
int Add(int x, int y)
{
     
    int z = x + y;
    return z;
}

//void 是无的意思
//就是说函数test调用完成之后什么都不返回
void test()
{
     
    printf("test\n");
}

//main函数最后也会返回
//main函数也是要被调用的
int main()
{
     
    int arr[10] = {
     1,2,3,4,5,6};
    arr[4]; // [] - 下标引用操作符
    // [] 的操作数是arr, 4
    
    int a = 10;
    int b = 20;
    // 函数调用, ()就是函数调用操作符
    // ()的操作数是 Add, a, b
    int sum = Add(a, b);
    printf("sum = %d\n", sum);
    test(); // ()函数调用操作符
    //操作数是test
    return 0;
}

代码中void 是无的意思
就是说函数test调用完成之后什么都不返回

一些可能有问题的知识博主都在注释中解释了,有什么问题可以在下方评论区留言哦!
有关于函数栈帧的问题篇幅较长,如果有想要看的,可以在评论区留言,博主单独整理喔~~

十二、 常用关键字

32个C语言关键字:

auto break case cahr 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

下面对关键字做一下分类,方便大家学习时理解。

auto 关键字 - 修饰临时变量
一般是省略的,给大家看看什么意思:

代码:

#include 

int main()
{
     
    auto int a = 10; //auto 
    //临时变量都是auto的,一般省略
    return 0;
}

我们平常学习一般是见不到这个关键字的,通常省略

循环:break continue do for while
分支(选择):case switch default else if
类型:char double float int long signed unsigned short
自定义类型:enum - 枚举 struct
extern - 声明
goto语句
register - 寄存器
return - 返回 - 函数
sizeof - 计算内存大小
static - 静态关键字
typedef - 类型重定义
union - 联合体关键字
void - 无,空
volatile - Linux系统部分
const - 修饰变量 - 常变量

关键字

  1. 关键字不能自己创建
  2. 变量名不能是关键字

注:关键字,先介绍下面几个,后期遇到讲解。

12.1 关键字typedef

typedef 顾名思义是类型定义,这里应该理解为类型重命名

用法:

其实就是在开头给你想要改名字的类型做一个重命名

代码演示:

#include 

//将unsigned int 重命名为unit_32,所以unit_32也是一个类型名
typedef unsigned int uint_32;

int main()
{
     
    //观察age1和age2,这两个变量的类型是一样的
    unsigne int age1 = 10;
    uint_32 age2 = 20;
    
    return 0;
}

上述代码中两种写法其实在 typedef 关键字的作用下变成了同一个意思,一般是为了方便使用,但使用时最好加上备注,好让我们的代码更具有可读性,日后别人看我们的代码或者我们自己再回过头来看自己的代码的时候,不至于看不懂。,

12.2 关键字 static

在C语言中:
static 是用来修饰变量和函数的

static 关键字有三种用法

1. static 修饰局部变量 - 静态局部变量
使得局部变量出了自己的范围也不销毁,其实是改变了局部变量的生命周期,但作用域还是局部的
2. static 修饰全局变量 - 静态全局变量
全局变量本身是具有外部链接属性的,但是用 static 修饰全局变量,会使得全局变量失去外部链接属性,变成内部链接属性,所以 static 修饰的全局变量吗,只能在自己的 .c 文件中使用
3. static 修饰函数 - 静态函数
函数默认是具有外部链接属性的,但是被 static 修饰之后,会使得函数失去外部链接属性,变成内部链接属性,所以 static 修饰的函数只能在自己所在的 .c 文件内部使用,不能在其他文件内部使用

下面给大家一 一罗列static的用法

  • static 修饰局部变量的用法:
#include 

void test()
{
     
    int a = 1;  // 每次退出销毁,进入重新创建 a = 1;
    //static修饰局部变量
    static b = 1;  // 出范围不会销毁
    a++;
    b++;
    printf("%d ", a); // 2 2 2 2 2 2 2 2 2 2
    printf("%d ", b); // 2 3 4 5 6 7 8 9 10 11
}

int main()
{
     
    int i = 0;
    while (i < 10)
    {
     
        test();
        i++;
    }
    return 0;
}

a 的输出结果为 :2,2,2,2,2,2,2,2,2,2
b 的输出结果为:2,3,4,5,6,7,8,9,10,11
原因就是static修饰了局部变量,延长了局部变量的生命周期,出了作用域不销毁,重新进作用域时自然也不会重新创建,所以此时的 a 还是保持上一次的赋值,所以会累加。

  • static 修饰全局变量的用法:

代码展示:
test1.c

//代码1
//test1.c
int g_val1 = 50;
static int g_val2 = 100;

test2.c

//代码2
//test2.c
#include 

//声明
int g_val1;
int g_val2;

int main()
{
     
    printf("g_val1 = %d\n", g_val1);
    printf("g_val2 = %d\n", g_val2);
    return 0;
}

以上代码只会输出 g_val1 而不会输出 g_val2,就是其中的道理,在源文件编译成目标程序(.obj)之后链接的时候,被 static 修饰的全局变量将不具有外部链接属性,无法正常打印 g_val1

  • static 修饰函数的用法:

代码展示:
test1.c

//代码1
//test1.c
#include 

void test1()
{
     
    printf("1: %d\n", g_val);
}

static void test2()
{
     
    printf("2: %d\n", g_val);
}

test2.c

//代码2
//test2.c
#include 

int main()
{
     
    int g_val = 100;
    test1(g_val);
    test2(g_val);
    return 0;
}

以上代码只会打印 : 1:100, 而不会打印: 2:100, 原因就是 test2 这个函数被 static 修饰,使得其失去了外部链接属性,无法正常链接运行

剩余关键字会在后续专栏里讲解,如果码友们有需要可以在评论区留言,博主去整理出一期C语言所有关键字详解~

十三、 #define 定义常量和宏

#define 定义标识符常量:

#define MAX 1000

#define 定义宏

#define ADD(x, y) ((x) + (y))

利用 #define 定义其本质上就是进行替换,甚至不占内存!非常方便!!

代码演示:

//define 定义标识符常量
#define NUM 1000
#include 
//define 定义宏
#define ADD(X, Y) ((X) + (Y)) // -- 这里注意习惯上字母全大写,并且无分号(;)  

int Add(int x, int y)
{
     
    int z = x + y;
    return z;
}

int main()
{
     
    int a = NUM;
    printf("a = %d\n", a);  //  1000
    // 函数 - 调用
    int x = 10;
    int y = 20;
    int sum1 = Add(a, b);
    printf("sum1 = %d\n", sum1);  // 30
    
    // 宏 - 替换
    int m = 10;
    int n = 10;
    int sum2 = ADD(m, n);
    printf("sum2 = %d\n", sum2);  // 20
    
    return 0;
}

输出结果博主都在注释中标明了喔~ 又不懂的地方欢迎在评论区留言!!


经过上述介绍,相比大家已经对编程有了一定的了解,接下来给大家介绍我们编辑的代码是如何实现的

PS 我们在编译器中编辑的代码是在源文件( .c 文件)中进行的,若干个源文件在编辑完成之后,首先由预处理程序对预处理指令进行编译,如将 stdio.h 文件替换
#include,接着分别对各个源文件进行编译,生成一个个目标程序( .obj文件)然后将生成的目标程序和函数库链接,生成一个可执行程序( .exe文件),然后进行程序运行。

这个知识点对我们写代码也许帮助不大,但其实能让我们更好的理解代码在编译器中的执行过程,如果练习算法相当于练习技能,那么学习这些知识应当属于修炼内功


十四、 指针

14.1 内存

内存是电脑中特别重要的存储器,计算机中程序的运行都是在内存中进行的。所以为了有效地使用内存,就把内存划分为一个个小的内存单元,每个内存单元的大小是一个字节。为了能够有效地访问到内存中的每个单元,就给内存单元进行了编号,这些编号就称为该内存单元的地址

下面给出我们常用来理解内存的图:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第11张图片
学习指针之前我们一定要了解一下两个问题:

  1. 一个小的格子称为一个内存单元 - 多大?
    1byte – 一个字节
  2. 编号 - 地址 - 地址是怎么产生的呢?
    在计算机中:
    分为32位机器和64位机器
    32位: 32根地址线 – 地址线(0/1)
    00000000000000000000000000000000
    00000000000000000000000000000001
    00000000000000000000000000000010
    00000000000000000000000000000011

    011111111111111111111111111111111111
    10000000000000000000000000000000

    1111111111111111111111111111111111111
    总共有 2 ^ 32 次方个不同的编号

下面给出内存条的地址示意图:
(☞゚ヮ゚)☞【精品C语言整理】☜(゚ヮ゚☜)女盆友缠着你让你教她写代码怎么办?安排,三万字博文带你走遍C语言,从此不再害怕编程_第12张图片

变量都有地址,取出变量地址如下:

下面代码介绍取地址操作符的用法:

代码:

#include 
int main()
{
     
    int a = 10;
    //打印地址,%p是以地址的形式打印
    printf("%p\n", &a); 
    // 注:&a 的时候,取出的是a所占内存中4个字节中第一个字节的地址(较小的地址)
    //取出a的内存地址
    int* pa = &a; // 数值
    // pa称为指针
    
    char ch = 'w';
    char* pc = &ch;
    
    //指针变量是一种变量,这个变量是用来存放地址的
    
    return 0;
}

指针变量是一种变量,这个变量是用来存放地址的
&a 的时候,取出的是a所占内存中4个字节中第一个字节的地址
pa称为指针变量

那地址如何存储,需要定义指针变量。

定义指针变量时,要根据地址中存放的元素的数据类型来定我们的指针变量定义为什么类型的

int num = 10;
int *p;//p为一个整形指针变量
p = &num;

指针的使用实例:
代码:

#include 
int main()
{
     
   int num = 10;
   int *p = &num;
   *p = 20;
   return 0; 
}

常用输出控制符:
%s - 字符串
%c - 字符
%d - 有符号的整型
%f - 单精度浮点数
%lf - 双精度浮点数
%p - 地址 - 地址的十六进制表示形式


* : 解引用操作符

指针的用法:
利用解引用操作符可以通过地址改变变量中的元素

代码演示:

#include 
int main()
{
     
    int a = 10;
    int* pa = &a;
    *pa = 20; // * 解引用操作符
    // a 被改成了20
    printf("%d\n", a); // 20
    
    return 0;
}

其实 const 可以修饰指针,让其无法进行解引用操作或者无法存放其他的地址,与 const 所处的位置有关,这些知识点在本专栏后期将指针的地方会详细介绍,有兴趣的小伙伴可以订阅该专栏喔~

以整型指针举例,可以推广到其他类型,如:

代码演示:

#include 
int main()
{
     
   char ch = 'w';
   char* pc = &ch;
   *pc = 'q';
   printf("%c\n", ch);
   return 0; 
}

4.2 指针变量的大小

指针变量就是用来存放地址的
地址就是那个编号 - 编号所占内存空间大小可能是4byte,也可能是8byte
32位环境下 :指针所占内存空间大小是4字节
64位环境下 :指针所占内存空间大小是8字节

代码试验:

#include 

int main()
{
     
    char ch = 'w';
    char* pc = &ch;
    
    printf("size of pc = %d\n", sizeof(pc));
    
    return 0;
}

输入结果为 4 或 8
与是什么类型的指针变量无关!!

如果是 32 位机器,每 8 位是一个字节,则有 4 字节
如果是 64 位机器,每 8 位是一个字节,则有 8 字节

结论:指针大小在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);

结构体 - 组合类型 - 自己创造的类型 - 自定义类型 - struct

代码举例:

#include 

//书的类型
//书名+定价+书号
struct Book
{
     
    char name[30]; // 书名
    float price; // 定价
    char id[20]; // 书号
};  //  -- 这里的分号不能漏了

void Print (struct Book* pb)
{
     
    //写法一:
    printf("书名:%s\n", (*pb).name);
    printf("定价:%f\n", (*pb).price);
    printf("书号:%s\n", (*pb).id);
    //写法二:
    printf("书名:%s\n", pb -> name);
    printf("定价:%f\n", pb -> price);
    printf("书号:%s\n", pb -> id);
}

int main()
{
     
    // 结构体变量的定义和初始化
    struct Book b1 = {
     "C语言程序设计", 55.0f, "C1001020"};
    struct Book b2 = {
     "数据结构"60.0f"DS001001"};
    struct Book b3 = {
     "操作系统"71.5f, "OS0001001"};
    printf("书名:%s\n", b1.name);
    printf("定价:%f\n", b1.price);
    printf("书号:%s\n", b1.id);
    
    Print(&b1);
    
    return 0;
}

打印时调用成员有两种写法:

  1. 结构体变量 .成员名
  2. 指针变量 -> 成员名

结构体类型就先介绍这么多,因为比较复杂,专栏后期也会继续将,想了解的小伙伴们可以跟进哦!

总结

本文介绍了C语言从入门到进阶的知识点内容,每个知识点介绍的其实并不详细,本专栏下一章会详细介绍每个分支的具体用法以及项目实战!!,本文目的旨在让菜鸟不再害怕学习编程,让高手重温经典,更深一步了解编程,以上就是本文所有内容,我是Aaron,感谢您的阅读,下期再见!!!

最后别忘了一键三连哦
点赞 + 收藏✔ + 关注!!!

你可能感兴趣的:(c语言)