【初识C语言】一篇文章带你快速入手C语言(适合新手)

在这里插入图片描述

个人主页:Weraphael
✍作者简介:目前正在回炉重造C语言(2023暑假)
✈️专栏:【C语言航路】
希望大家多多支持,咱一起进步!
如果文章对你有帮助的话
欢迎 评论 点赞 收藏 加关注


目录

  • 前言
  • 一、什么是C语言
  • 二、第一个C语言程序
      • 2.1 什么是main函数
  • 三、数据类型
      • 3.1 C语言中的数据类型
      • 3.2 数据类型的大小
      • 3.3 类型的使用
  • 四、变量的命名
  • 五、变量的分类
      • 5.1 全局变量和局部变量的变量名冲突的情况
      • 5.2 变量的使用
      • 5.3 scanf函数报错问题
      • 5.4 变量的声明和定义
  • 六、变量的作用域和生命周期
      • 6.1 作用域
      • 6.2 补充:extern
      • 6.3 变量的生命周期
  • 七、常量
      • 7.1 常量的分类
      • 7.2 常变量const的补充
  • 八、字符串和转义字符
      • 8.1 字符串
      • 8.2 计算字符和字符串的长度
      • 8.3 转义字符
  • 九、注释
  • 十、选择语句if
  • 十一、循环语句while
  • 十二、函数
  • 十三、数组
      • 13.1 数组的定义
      • 13.2 数组的下标及其使用
  • 十四、操作符
      • 14.1 算术操作符:+ 、-、*、/
      • 14.2 位移操作符: >> <<
      • 14.3 位操作符:&、^、|
      • 14.4 赋值操作符:=、+=、-=-、*=、%=、/=、&=、^=、|=、>>=、<<=
      • 14.5 单目操作符
        • 14.5.1 !
        • 14.5.2 &
        • 14.5.3 sizeof
        • 14.5.4 ~
        • 14.5.5 - -和++
        • 14.5.6 *
        • 14.5.7 (类型)
      • 14.6 关系操作符
      • 14.7 逻辑操作符
      • 14.8 条件操作符
      • 14.9 逗号表达式
      • 14.10 下标引用、函数调用和结构成员
  • 十五、关键字
      • 15.1 关键字typedef
      • 15.2 关键字static
        • 15.2.1 修饰局部变量
        • 15.2.2 修饰全局变量
        • 15.2.3 修饰函数
  • 十六、#define定义常量和宏
      • 16.1 #define定义常量
      • 16.2 #define定义宏
  • 十七、指针
      • 17.1 内存
      • 17.2 内存的管理与使用
      • 17.3 指针变量的大小
      • 17.4 指针变量的使用
  • 十八、自定义类型 -- 结构体
      • 18.1 定义
      • 18.2 结构体的访问 --- 点操作符
      • 18.3 结构体的访问 --- ->箭头操作符

前言

本篇文章是基本了解C语言的基础知识,对C语言有一个大概的认识,目前不做详解。篇幅很长,建议大家配合目录食用~

一、什么是C语言

  • C语言是一门计算机语言,是人和计算机交流的语言,它广泛用于底层开发(Linux就是用C语言写的)。当然,计算机语言还包括C++JavaPythonGo等等。
  • 其常用的编辑器有Clang(苹果公司编写)GCC(Linux环境)MSVC(visual studio - 集成开发环境IDE)等(本人用的是VS2019)

二、第一个C语言程序

每学习一门新的语言,当然是要打印hello world!

// 第一个C语言代码
#include 
int main()
{
	printf("hello world!");

	return 0;
}

【输出结果】

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第1张图片

  1. C语言代码中,不管是括号、分号、大括号等符号必须是 英文模式 下敲出来的。
  2. main主函数,在C语言必须要有主函数
  3. printfc语言标准函数库提供的一个格式化输出函数。因此使用printf函数就要包含头文件#include scanf - 输入函数,也要包含此头文件)。 其中stdio.h ---standard input output header – 标准输入输出头文件
  4. '\n' – 换行(相当于回车)

2.1 什么是main函数

  1. 主函数是程序的入口
  2. C语言必须要有主函数
  3. 但需要注意的是:一个工程(项目)可以有多个源文件(.c后缀文件),main只能有一个

验证第3点main函数只有一个:
例如在一个项目中再创建一个源文件(Test2.c),内容如下:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第2张图片

三、数据类型

我们为什么要写代码?因为代码能够解决未来生活中的问题,C语言必须有能力描述我们的生活。假如设计在线商城,我们得用计算机的语言把它描述出来,比如商品陈列、详情、定价、编号等,所以C语言就引入了数据类型

3.1 C语言中的数据类型

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

现在我们利用以上类型来打印不同的数据到屏幕上:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第3张图片

  • %d是打印十进制的整数,所以第20行代码的意思是:把100以十进制的方式打印在屏幕上。
  • 当然还有一些常见的输出格式如下:
    【初识C语言】一篇文章带你快速入手C语言(适合新手)_第4张图片

3.2 数据类型的大小

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第5张图片

【程序结果】

// 以下单位是字节
char类型大小:1
short类型大小:2
int类型大小:4
long类型大小:4
long long类型大小:8
float类型大小:4
double类型大小:8
  1. 小伙伴们有没有发现,为什么长整型(long)不比整型(int)大呢?

原因是:C语言标准规定:sizeof(long) >= sizeof(int)

  1. sizeof是一个操作符,是计算变量的大小。(单位:字节)

因此这里就要说说计算机常见的单位:

bit   比特位   1 byte = 8 bit
byte   字节
KB            1KB = 1024 byte
MB            1MB = 1024 KB
GB            1GB = 1024 MB
TB            1TB = 1024 GB
PB            1PB = 1024 TB

记住int类型的数据范围:[-21亿+,21亿+]

3.3 类型的使用

有了类型就是为了创建变量

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第6张图片

在数据后加f后,就是float类型了

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第7张图片

这里提一个好的编程习惯:在创建变量的同时给一个初始值。

四、变量的命名

  1. 只能由字母、数字和下划线(_)组成。
  2. 不能以数字开头
  3. 变量名是区分大小写
  4. 变量名不能使用关键字。

五、变量的分类

变量分为局部变量和全局变量

  1. 局部变量:定义在{}里的变量
  2. 全局变量:定义在{}外的变量

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第8张图片

5.1 全局变量和局部变量的变量名冲突的情况

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第9张图片

通过以上代码我们发现,当局部变量和全局变量的变量名冲突时,局部优先。但是建议大家在平时尽量不要冲突。

5.2 变量的使用

哪里要使用变量,就在哪里创建

例如:编写代码,计算两个数的和

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第10张图片

scanf是一个库函数,可以从键盘接收数据,要引用头文件#include ,同时 需要在变量前加上&(取地址)

5.3 scanf函数报错问题

注意:如果没有第一行代码,若使用scanf时会报错。

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第11张图片

原因是:scanf是C语言提供的,当然也可以使用scanf_s(visual studio提供的),但是建议大家使用scanf函数。最后如何解决请看这篇文章:【点我跳转】

5.4 变量的声明和定义

  1. 变量的定义
// 当创建变量并给它赋值叫做定义
int a = 1; 
int main()
{
	printf("%d\n", a);

	return 0;
}
  1. 变量的声明
int a; //变量的声明
int main()
{
	printf("%d\n", a);

	return 0;
}
int a = 1;

如果变量的使用在变量的定义之前,使用前需要加上声明。原因是:代码在编译阶段是从上到下开始扫描的,当来到printf时,如果没有声明,编译器就不知道有a这个变量,所以会导致报错。

六、变量的作用域和生命周期

6.1 作用域

什么是作用域呢?直白来说,哪里可以使用变量,哪里就是它的作用域。

  1. 首先先来讨论局部变量的作用域
#include 

int main()
{
	int a = 100;
	printf("%d\n", a);

	return 0;
}

在上述代码中,变量a的作用域就是代码块{}的内部

总的来说,局部变量的作用域:就是变量所在的局部范围。

  1. 接下来看看全局变量的作用域

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第12张图片

代码解析:因为main是程序的入口,代码先从第119行开始执行,接下来开始打印main:211在屏幕上,接着又调用test函数,最后打印test:211在屏幕上。(这里使用了函数部分知识,先凑合看,后面会讲)

有没有发现,全局变量既可以在主函数中使用,也能在其他函数中使用,这意味着在任意地方都能使用。由此可以得出结果,全局变量的作用域是整个工程

6.2 补充:extern

全局变量还能怎么用呢?假如我把变量a放在同一工程不同源文件Test1.c),程序是否能运行起来呢?

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第13张图片

程序报错了,让我们应该如何解决呢?声明外部符号extern

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第14张图片

6.3 变量的生命周期

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

  1. 局部范围的生命周期

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第15张图片
以上代码是编译不过的,这是为什么呢?原因是:变量a是个局部变量,它的作用域是中间的代码块。进入作用域生命周期开始,出作用域生命周期结束,所以变量a出了中间部分的代码块作用域,它就被销毁(还给了操作系统),所以当打印第二个a时,程序就报错了。这就是局部变量的生命周期。

  1. 全局变量的作用域就是整个程序的生命周期,直到整个程序结束,变量才会被销毁

七、常量

7.1 常量的分类

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

【举例】

#include 

// 3. #define定义的标识符常量(也能放在main函数里)
#define M 100; //定义了一个M,它的值是100

// 4. 枚举 --- 一一列举
//假设列举三原色
enum Color
{
	// 编译器默认red,green,blue分别是0,1,2(常量)
	red, 
	green,
	blue
};

int main()
{
	// 1. 字面常量
	3;
	100;
	'a';
	"abcdef";
	
	// 2. const修饰的常变量
	const int N = 100010;
	N = 1; // 这是错误的,const修饰的变量具有常属性,不可修改
	// const从语法层面上限制了变量不能被修改,但其本质上还是变量。

	return 0;
}

7.2 常变量const的补充

常变量,是常量为什么会有一个“变“呢?让我们再举一个例子,加深对const的理解

我们可以使用数组来验证,因为数组[]操作符里必须是常量

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第16张图片

显然报错了。这说明编辑器依然认为**a的属性是变量**。

总结:const从语法层面上限制了变量不能被修改,但其本质上还是变量。

八、字符串和转义字符

8.1 字符串

“hello world!\n”

这种由双引号引起来的一串字符称为字符串字面值,或者简称字符串

注意:字符串的结束标志是'\0'的转义字符。在计算字符串长度时,'\0'是结束标志,不是字符串内容。

一般存多个字符或者字符串都是用数组存储的

#include 
int main()
{
	char ch1[] = { 'a','b','c' };
	char ch2[] = "abcdef";

	return 0;
}

8.2 计算字符和字符串的长度

C语言提供了一个库函数:strlen,可以计算字符串的长度。但使用strlen需要包含头文件:#include

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第17张图片

这里注意一下:

  1. 其实ch1字符串长度其实不止15,它是个随机值,因为它没有结束字符'\0'
  2. 字符串ch2在计算长度时没有算上末尾的'\0'它统计的是'\0'之前字符的个数

8.3 转义字符

顾名思义就说转变原来的意义

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第18张图片

【例如】

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第19张图片

【经典笔试题】

以下代码输出的结果是多少?

#include 

int main()
{
	printf("%d\n", strlen("c:\test\628\test.c"));

	return 0;
}

【答案】

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第20张图片

解析:从左往右,\t\62\t是转移字符。分别都只算一个字符。

九、注释

当代码中有些代码比较难懂,可以添加文字注释。当然也可以注释掉不需要的代码

注释风格:

// 这是一个注释,只能注释一行

/*
这是一个多行注释
这是一个多行注释
这是一个多行注释
注意:这种注释风格不能嵌套
*/

十、选择语句if

//以下是伪代码

if(判断条件)
{
	// 逻辑实现
}
else if(条件判断)
{
	// 逻辑实现
}
else
{
	// 逻辑选择
}

【例子】

编写代码,输入一个人的智商值,如果智商大于等于140,输出“Genius”。否则输出“fool”

#include 
int main()
{
	int score = 0;
	scanf("%d", &score);
	if (score >= 140)
	{
		printf("Genius");
	}
	else
	{
		printf("fool");
	}
	return 0;
}

十一、循环语句while

意思是循环做,直到满足条件停止。当然还有fordo while,这些循环会在后面讲到

【例子】

输出1~10

#include 
int main()
{
	int i = 1;
	while (i <= 10)
	{
		printf("%d ", i);
		i = i + 1;
	}

	return 0;
}

十二、函数

在数学中,我们经常把函数定义成:f(x);在C语言中,把函数定义为:函数名(类型 x,...),其特点是:简化代码,代码重复使用。

在变量的使用中,写过有关加法的代码,那么能否把加法的过程封装成一个函数呢?

#include 

int add(int x, int y)
{
	// 1. 第一种写法
	//return x + y;

	// 2. 第二种写法
	int res = x + y;
	return res;
}

int  main() 
{
	int num1 = 0;
	int num2 = 0;
	scanf("%d%d", &num1, &num2);
	
	// 封装一个add函数
	int ans = add(num1, num2);

	printf("num1 + num2 = %d\n", ans);
	return 0;
}

建立一个add函数,把num1传到int x,再把num2传到int y中,经过函数内部的逻辑运算,最后把res的结果作为返回值给到ans,因为res的结果一定是整型,所以add函数的返回值是int。但注意,函数名要根据实际的意义来命名

我们还能这样理解:可以把add看作一个工厂,把num1num2相当材料输入到int xint y中,工厂里再进行加工(x+y),最后通过return返回到ans中。

十三、数组

13.1 数组的定义

如果我们要存1-10的数字,怎么储存?难道是一直定义变量直到10吗?这样会不会显得麻烦?所以在C语言中给了数组的定义:一组相同类型元素的集合

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

// 定义整型数组,最多只能存放10个整型元素
// 注意:
// 在C99之前,[]内不能使用变量
// 在C99中引入变长数组的概念,这时候
// 这时候数组的大小是可以使用变量的,但数组不能初始化!!!

假如数组不放满指定数组元素个数是否可以呢?其内容又是什么?

#include 
int main()
{
	int arr1[10] = { 0, 1, 2,3,4,5,6,7,8,9 };
	int arr2[10] = { 0,1,2,3,4 };

	return 0;
}

可以在监视中看看效果,首先在编译器中先按F10,然后在调试中找到窗口,最后在窗口中找到监视:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第21张图片

随后在名称中输入arr1arr2,就能看到他们的内容:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第22张图片

有没有发现未放满10个元素的整型数组arr2后面补了5个0,这个叫:不完全初始化,剩余的默认初始化为0

如果我再创建字符数组arr3,数组中也不放满对应元素,结果又会是如何呢?

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第23张图片

结果很明显了,对于字符数组,它的剩余默认初始化为'\0'

13.2 数组的下标及其使用

C语言规定:数组的每个元素都有一个下标,且下标都是从0开始的。

假如打印数组中的3,就可以用到[]这个操作符:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第24张图片

对于数组4个元素,从语法上规定:第一个元素0的下标就是0,第二个元素1的下标是1,后面以此类推…

十四、操作符

14.1 算术操作符:+ 、-、*、/

  1. 如果算术操作符至少有一个运算对象是浮点型,其表达式的类型为浮点型。

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第25张图片

  1. 取模(取余)操作符(%)的两个运算对象必须都是整数,结果的正负号由被除数决定。

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第26张图片

  1. 注意不要把*和/写成数学中的×和÷。

14.2 位移操作符: >> <<

如果想深入了解建议看看这篇博客:点击跳转

14.3 位操作符:&、^、|

如果想深入了解建议看看这篇博客:点击跳转

14.4 赋值操作符:=、+=、-=-、*=、%=、/=、&=、^=、|=、>>=、<<=

如果想深入了解建议看看这篇博客:点击跳转

14.5 单目操作符

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第27张图片

14.5.1 !

!   逻辑反操作

在C语言中,非零表示真,零表示假,操作符!即可以把真变成假,假变成真

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第28张图片

flag初始值为0,其本质为假;在if条件判断加了!,假变成了真,所以在屏幕上打印了hello world!

14.5.2 &

负值和正值操作符比较简单,这里就不过多赘述了

感兴趣请参考这篇文章:点击跳转

14.5.3 sizeof

sizeofstrlen的区别

  • sizeof是操作符,是计算变量所占内存空间的大小,单位是字节。
  • strlen是库函数,是计算字符串的长度,统计的是字符串中‘\0’之前出现的字符个数

感兴趣请参考这篇文章:点击跳转

14.5.4 ~

感兴趣请参考这篇文章: 点击跳转

14.5.5 - -和++

感兴趣请参考这篇文章: 点击跳转

14.5.6 *

感兴趣请参考这篇文章:点击跳转

14.5.7 (类型)

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第29张图片

3.14原先是浮点数类型,但在3.14前加上(int)就变成了整型(只取整数部分)。

14.6 关系操作符

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

关系操作符比较简单,这里要重点区分“=”和“==”。在C语言中,“=”是赋值操作符;两个等于才表示相等。

14.7 逻辑操作符

&&  逻辑与:两真为真,一假全假
||  逻辑或:一真全真,两假全假

14.8 条件操作符

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第30张图片

  • expl的值为真,则结果就是exp2的值。
  • exp1的值为假,则结果就是exp3的值 。

14.9 逗号表达式

exp1,exp2,exp3...

从左向右依次执行,最后的答案是最右边的表达式

14.10 下标引用、函数调用和结构成员

请参考这篇博客:点击跳转

十五、关键字

注意:以下关键字不能当变量名来使用!

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

注意:sizeof既是关键字,也是操作符。

另外,操作符是C语言本身预先设定好的,用户是不能创造关键字的。

最后,我对这些关键字做了分类:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第31张图片

15.1 关键字typedef

typedef的作用是:类型重命名。

我们应该怎么用呢? 比如我们要定义一个无符号的整型,我们可以这么写:unsigned int num = 0,大家有没有发现这个名字很长。因此我们可以用typedef来进行类型重命名:

#include 
typedef unsigned int ui;
int main()
{
	ui num = 0;
	return 0;
}

我们可以把unsigned int(类型)重命名为ui(开头首字母缩写),ui就是unsigned int的别名,这样写把代码复杂类型简单化。

15.2 关键字static

在C语言中:
static是用来修饰变量和函数的
①修饰局部变量 - 称为静态局部变量
②修饰全局变量 - 称为静态全局变量
③修饰函数 - 称为静态函数

15.2.1 修饰局部变量

以下代码会输出什么呢?

#include 

void test()
{
	int a = 0;
	a++;
	printf("%d\n", a);
}

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

【程序结果】

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第32张图片

为什么是10个1呢?原因是:a是个局部变量,进入作用域生命周期开始,出作用域生命周期结束。当每次调用test函数,创建局部变量a,出了作用域,变量a被销毁(还给了操作系统),因此每次调用test函数都只会打印1。

那如果我在变量a前加static结果还会是一样吗?那我们来看一下。

#include 

void test()
{
	static int a = 0;
	a++;
	printf("%d ", a);
}

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

【程序结果】

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第33张图片

答案是1~10。为什么能输出这个结果呢?static修饰局部变量的作用是什么呢?

分析:第一个结果为1很好理解,可是第二个结果为2有没有发现第一次的结果并没有销毁。以此类推…

那么static的本质是什么呢?我们来看看下面这幅图:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第34张图片

栈区是进入作用域创建,出了作用域就会释放,放在静态区的数据创建后,直到程序结束才会释放。被static修饰都是在静态区里。 堆区目前不做了解。

总结:普通的局部变量是放在栈区上的,这种局部变量进入作用域创建,出了作用域释放,但是局部变量被static修饰后,这种局部变量就放在了静态区,放在静态区的变量,创建好后,直到程序结束才释放。

本质:static的修饰改变了局部变量的存储位置,因为存储位置的差异,使得执行效果不一样。

注意:被static修饰是不影响作用域的!!!但是生命周期变长了。

15.2.2 修饰全局变量

假设我在另一个源文件创建一个全局变量:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第35张图片

若全局变量astatic修饰,结果又会是如何呢?

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第36张图片

程序发生报错了(无法解析的外部符号),所以为什么会出现这种现象呢?

原因是:全局变量本身是具有外部链接属性的,在一个文件中定义的变量,在另一个文件可以通过链接使用(extern),但是如果全局变量被static修饰,这个外部链接属性就变成了内部链接属性了,这个全局变量只能在自己所在的源文件内部使用。最终使得全局变量的作用域变小了。

15.2.3 修饰函数

其实static修饰函数和修饰全局变量非常类似。让我们看看下面的代码:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第37张图片

现在,我们在函数前加个static会怎么样呢?

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第38张图片

结果是程序报错了(未定义外部符号)

原因是:函数本身是具有外部链接属性的,被static修饰后,外部链接属性就变成内部链接属性,使得这个函数只能在自己所在源文件内部使用,其他源文件无法使用。和全局变量其实是一个道理。限制了作用域。

十六、#define定义常量和宏

16.1 #define定义常量

这个在前面已经讲过了,来看看简单的代码样例吧

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第39张图片

16.2 #define定义宏

比如:写一个函数求两个数的最大值,不难可以写出以下代码:

#include 

int Max(int x, int y)
{
	if (x >= y)
		return x;
	else
		return y;
	// 或者还可以用三目操作符
	//return x > y ? x : y;
}

int main()
{
	int a = 10;
	int b = 20;
	int c = Max(a, b);

	printf("最大值是:%d\n", c);

	return 0;
}

除此之外,我们还可以用宏来求出两个数之间的最大值

#include 
#define Max(x, y) (x > y ? x : y)

int main()
{
	int a = 10;
	int b = 20;
	int c = Max(a, b);

	printf("最大值是:%d\n", c);

	return 0;
}

解析一下代码:我这定义了一个宏叫Max后面跟着圆括号,xy参数,后面的三目运算符叫宏体 。其中a传给了的xb也传给了y,因此宏体其实就被替换成(a>b?a:b)。可能有人会想,这不就和函数差不多么?注意:宏一般是解决逻辑比较简单的问题,而函数通常用于解决复杂的问题。

如果我们要求两个数的和该怎么写呢?

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

十七、指针

17.1 内存

想要理解什么是指针,必须先了解什么是内存。内存是电脑上的存储设备,一般都是4G/8G/16G等,程序运行的时候会加载到内存中,也会使用内存空间,例如任务管理器:

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第40张图片

17.2 内存的管理与使用

我们将内存划分为一个个小格子,每一个格子是一个内存单元,大小为一个字节,对每一个内存单元进行编号,假设未来要找一个内存单元,就可以通过编号很快的找到,我们把这些编号叫做地址而地址在c语言中又叫做指针。

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第41张图片

举一个例子,在下图中,假设定义一个变量 int a=10,一个int类型的变量,需要占4个字节的空间,而每个空间都有地址,&a取出的是哪一个的地址呢?其实取出的是第一个字节的地址(也就是较小的地址),也就是说,&a最终取出来的地址是0x0012ff40,当然,可以把这个地址存到一个变量中,int* pa=&a*表示pa是一个指针,int代表pa所指向的类型是int类型,这个pa也叫做指针变量(它是专门用来存放地址的)。

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第42张图片

17.3 指针变量的大小

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第43张图片

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第44张图片

指针变量,就是用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
那么问题来了:一个内存单元到底是多大? — 刚刚讲过,就是一个字节
那它又是如何编址的呢?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。 对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0)
那么32根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001

11111111 11111111 11111111 11111111
这里就有2的32次方个地址。 一个地址管理一个内存单元,那么2的32次方个地址就能管理2的32次方个内存单元,也就是2的32次方个字节,那2的32次方个字节又是多大空间呢?
根据进制转化:
2^32Byte = 2^32÷1024KB÷1024MB÷1024GB = 4GB
同样的方法,64位机器,也可以计算出来。

这里我们就明白:

  • 在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以 一个指针变量的大小就应该是4个字节。
  • 那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。

总结:

  • 指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节。

17.4 指针变量的使用

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第45张图片

通过以上代码就验证了,指针变量p存放的就是a的地址。

接下来,我们可以使用*解引用操作符来对其使用

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第46张图片

十八、自定义类型 – 结构体

18.1 定义

结构体使得C语言有能力描述复杂信息。

假如我们要描述一个学生(名字+性别+年龄)

// 定义一个学生的类型
struct Stu // 这个是类型
{
	char name[10]; // 姓名
	char sex[5]; // 性别
	int age; //年龄
	// 以上三个变量叫做结构体成员
};
// 分号不能省略

int main()
{
	// 类型(struct) + 变量(s) 
	struct Stu s = {"张三", "男", 20};
	
	return 0; 
}

代码解析:首先我们要先定义一个学生的类型,其中{}里的是结构体里的成员,注意最后要有分号 。接下来,在主函数中创建一个struct Stu的类型,其中s是变量。

那么问题来了,我们应该怎样打印出学生的信息呢?让我们接着往下看。

18.2 结构体的访问 — 点操作符

我们需要利用点.操作符来访问结构体里的成员

模板:结构体变量.成员名

// 定义一个学生的类型
struct Stu // 这个是类型
{
	char name[10]; // 姓名
	char sex[5]; // 性别
	int age; //年龄
	// 以上三个变量叫做结构体成员
};

int main()
{
	struct Stu s = { "张三", "男", 20 };
	printf("姓名:%s\n性别:%s\n年龄:%d\n", s.name, s.sex, s.age);

	return 0;
}

【程序结果】

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第47张图片

当然还能使用指针解引用的方法

struct Stu // 这个是类型
{
	char name[10]; // 姓名
	char sex[5]; // 性别
	int age; //年龄
	// 以上三个变量叫做结构体成员
};

int main()
{
	struct Stu s = { "张三", "男", 20 };
	//printf("姓名:%s\n性别:%s\n年龄:%d\n", s.name, s.sex, s.age);

	struct Stu* p = &s;

	printf("姓名:%s\n性别:%s\n年龄:%d\n", (*p).name, (*p).sex, (*p).age);
	return 0;
}

【程序结果】

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第48张图片

取出结构体变量s的地址存放到指针变量p中,再对其解引用,因此*p本质上就是s

18.3 结构体的访问 — ->箭头操作符

大家有没有发现解引用再去访问成员变量写的怪长怪累的,因此这里引用了箭头操作符:

// 定义一个学生的类型
struct Stu // 这个是类型
{
	char name[10]; // 姓名
	char sex[5]; // 性别
	int age; //年龄
	// 以上三个变量叫做结构体成员
};

int main()
{
	struct Stu s = { "张三", "男", 20 };
	//printf("姓名:%s\n性别:%s\n年龄:%d\n", s.name, s.sex, s.age);

	struct Stu* p = &s;

	//printf("姓名:%s\n性别:%s\n年龄:%d\n", (*p).name, (*p).sex, (*p).age);

	printf("姓名:%s\n性别:%s\n年龄:%d\n", p->name, p->sex, p->age);
	return 0;
}

【程序结果】

【初识C语言】一篇文章带你快速入手C语言(适合新手)_第49张图片

这里运用到了->箭头操作符,因为p指向了s,所以ps->name(sex/age)就是ps指向了sname(sex/age)

模板:结构体指针->成员变量

你可能感兴趣的:(C语言航路,c语言,笔记,学习,开发语言,visualstudio)