大家好,这里是anduin.今天将给大家带来初识C语言的最后一部分,和之前一样点到为止,适当补充,今天的内容是#define 定义常量和宏、指针和结构体三部分内容,事不宜迟,我们这就开始。
12. #define 定义常量和宏
定义标识符常量
我们在之前常量那一部分就认识到#define可以定义常量,凡是用到常量的地方都可以用define定义的宏来替换。
#include<stdio.h> //#define 定义标识符常量 #define MAX 1000//定义整形 #define STR "abcdef"//定义字符串 int main() { printf("%d\n",MAX); int a = MAX; int arr[MAX] = {0}; printf("%d\n",a); printf("%s\n",STR); return 0; }
分析:如代码所示,#define用来定义常量MAX,当对变量a进行赋值时,可以打印出1000,同样的对于数组arr的数组元素为MAX,也就是1000个,由于MAX为常量,所对应arr中的元素也就是1000个(如下图),对于字符串常量STR也是相同的原理。
定义宏
如果我们平时实现两个数相加的程序,我们可以直接在main函数中实现,或者是封装一个函数,代码如下:
#include<stdio.h> //函数实现 int Add(int x,int y) { return x+y; } int main() { int a = 10; int b = 20; int c = Add(a,b); printf("%d\n",c); }
那么除了函数,可不可以用其他方法实现呢?有,就是我们所说的宏:
#include<stdio.h> #define ADD(x,y) ((x)+(y)) int main() { int a = 10; int b = 20; int c = ADD(a,b); printf("%d\n",c); return 0; }
对比:我们可以看到对于这两种实现方式,他们俩是很像的,就如函数有函数体,宏也有宏体(((x)+(y))),虽然他们比较相似,但是他们也有着许多差别!!!(仅目前所学知识归纳,不全)
宏和函数的差别:
实现时有差异,定义时有差异(实现:函数实现时是调用函数,而宏是预处理指令;定义:函数有返回值类型,函数返回值,函数体,函数名,形参等等而宏则十分简单)
宏的参数没有类型,函数的参数有类型(代码可以看到形参的类型,和宏的无类型)
函数体 - 宏体
函数传实际参数,宏直接起替换作用(如代码中就是a,b就是直接替换宏中的x,y)
13. 指针
内存
众所周知,内存是电脑上特别重要的存储器,它是外存与CPU进行沟通的桥梁,计算机所有程序的运行都在内存中进行,当计算机没有出现寄存器和高速缓存区之前,计算机都是要从内存中调取数据到CPU中进行运算,内存的重要性可见一斑。
所以内存的使用效率也是要被有效划分的,我们把内存单元划分成一个个小小的内存单位,每个内存单位单位大小是一个字节,如下图所示:
但是访问内存单元又成了一个问题,我们在查找货物时需要给货物编号,在拜访别人家时需要借助地址,在C语言中也一样,为了能有有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号就被称为该内存单元的地址。但是地址在平时说起来比较拗口,所以我们把给他起了个好听的名字 - 指针。
指针的分析
&操作符
#include<stdio.h> int main() { int a = 10; int *pa = &a;//指针变量pa }
分析:我们知道,int类型a变量的大小是4个字节,我们启动调试,点击内存窗口&a,并将其内存显示一列,观察它的地址发现,因为a占用4个字节,每个字节都有一个地址,在内存中它们地址是逐次增大的,与之对应的a的地址与a中第一个字节所存放的地址是相同的,也就是说&a取出的是第一个字节的地址。
指针和指针变量
地址取出来了,那么用什么保存呢?指针变量。
分析:pa是创建出来存放地址的,这个变量就是指针变量,他们通常写成int *p,char *p等形式,而int *整体是一个类型,叫做整形指针类型,*说明pa是指针变量,而int说明pa指向的对象是int类型(我们口头语上说的指针一般指的是指针变量!)
*操作符与指针的关系
那么问题来了,生活中我们拿到一户人家的地址时,可以找到他家并去拜访他,那么指针是否也可以起到这种效果呢?
当然可以!这时候就要用到我们上次没讲的*解引用操作符。
#include<stdio.h> int main() { int a = 10; int *pa = &a; *pa = 20; printf("%d\n",a); //*&a;//也就是找到地址在拿数据,相当于就是a }
分析:*操作符其实就是起到一个间接访问的作用,*pa的意思其实就是通过pa中存放的地址,找到pa指向的空间,拿到空间里的数据,也就相当于a = 20,使用*操作符也就起到了"拜访"数据的作用。
与&操作符结合理解就是&操作符是你找到地址,*则是找到数据,一个是来,一个是去。
Tips:可能大家有些疑惑,解引用操作符会不会和乘号混淆?我可以明确地告诉你:不会!
因为解引用操作符*是单目操作符的缘故,并不会和双目操作符乘*所混淆的。
指针变量的大小
计算及其结果
那么指针变量的大小又是多少呢?让我们用sizeof来计算一下。
(由于pc是指针变量,而它是char*字符指针类型的,所以用计算大小时用pc和用它的类型本质上是一样的,通过类型来计算大小还是计算它的变量大小是一样的。)
#include<stdio.h> int main() { char ch = 'a'; char* pc = &ch; 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; }
解释
指针变量是用来存放地址的,其大小取决于一个地址需要多大的空间,我们的电脑是硬件,在电脑中有一层地址线(32/64位)。
电线上通电后,转化为1/0组成的数字信号(如图),这些地址组合有2的32次方个,而在这些地址也就是32位的由01组成的地址序列,每个1/0就占一个bit位,每8个bit位构成一个字节,所以地址存放起来的大小总共就是4个字节,而指针变量就是存放地址的,那么它的大小也就是4个字节!!!当然在64位平台上地址序列就是64个1/0组成的二进制序列,存起来就需要八个字节。
14. 结构体
概念
在C语言中存在着许多类型,但是他们所表示的往往是部分数据,并不能通过一个类型来描述生活中的一个事物,例如一本书:他们要有书名+定价+作者等组成,这些复杂对象不能简单地使用单一类型进行描述的,在C语言中可以用结构体来描述这种复杂对象。
使用方法
第一种访问方式
#include<stdio.h> //结构体类型 struct Book { char bookname[30]; float price; char writer[20]; }; int main() { struct Book s = {"chushiclanguage",1.01,"anduin"};//创建变量并初始化 //结构体变量.结构体成员 printf("%s %f %s\n",s.bookname,s.price,s.writer); }
对创建结构体类型及其变量初始化的分析:
如代码,首先创建结构体类型Book,在其内部创建bookname,price,writer等类型选项,再在main函数中定义结构体变量s,通过大括号的方式对其内容进行初始化。
.访问操作符就是通过结构体变量.结构体成员的形式,对结构体内容进行访问,运行代码输出结果为:
第二种访问方法
#include<stdio.h> struct Book { char bookname[30]; float price; char writer[20]; }; void Print(struct Book* ps) { printf("%s %.2f %s\n", ps->bookname, ps->price, ps->writer); //结构体指针->结构体成员 //printf("%s %.2f %s\n", (*ps).bookname, (*ps).price, (*ps).writer); } int main() { struct Book s = { "chushiclanguage",1.01,"anduin" };//创建变量并初始化 Print(&s); }
分析:从上面那段代码可以知道.操作符可以访问,那么可不可以用另外一种方式来访问呢?
1.(.)指针方式访问
如代码所示,定义Print函数,参数为s的地址,在函数中我们仍然是通过.操作符的方式来进行访问,传参传的是地址,有结构体指针ps进行保存,再通过*符号来找到结构体变量s,并通过.操作符进行访问。
2.->方式访问
由于参数是结构体指针,便可以通过->来进行访问,格式为结构体指针->结构体成员,这样也可以进行访问。
结构体数据输入方法
我们平常想要输入数据时,经常要用到scanf函数,那么对于结构体我们如何输入数据呢?
#include<stdio.h> struct Book { char bookname[30]; float price; char writer[20]; }; int main() { struct Book s; scanf("%s %f %s",s.bookname,&(s.price),s.writer); printf("%s %.2f %s\n",s.bookname,s.price,s.writer); }
Tips:这里的bookname,writer是数组名,数组名本来就是地址,所以不需要&,而price是浮点型,那就需要取地址了!!!
结语
好了,以上就是初识C语言的全部内容,对于C语言中的知识点,我们也都有了一个初步的了解,对于其深度理解,我会在之后的博文中一一剖析。