大家好,我是阿亮。
在本篇文章,我将要给大家简单介绍一下C语言中的#define定义常量和宏、指针和结构体。那么C语言的全部基础知识就已经介绍完了。
什么是C语言
如何写出你的第一个C语言程序
C语言的数据类型
常量和变量
字符串+转义字符+注释
选择语句
循环语句
函数
数组
操作符
常见的关键字
#define定义常量和宏
指针
结构体
1.#define定义常量和宏
宏定义#define是C语言中常用的功能。用宏来定义一些字符串常量,可以方便编写程序。
宏定义的格式:
#define 宏名 宏定义字符串
define前面以#开始,标识它在编译预处理中起作用,而不是真正的C语句,行尾不用带分号。宏名可以自己定义,一般为了与变量名、函数名区别,常采用大写字母作为宏名,宏名与宏定义字符串间用空格分开,所以宏名中间不能有空格。宏定义字符串是宏名对应的具体实现过程,可以是任意字符串常量,也可以是数字。
好比如下面这个程序。
#include <stdio.h> #define MAX 100 #define WW "Hello world" int main() { printf("MAX = %d", MAX); printf("%s\n",WW); return 0; }
宏的用途包括:
符号常量,如MAX,WW等,以增加程序的灵活性。
简单函数功能的实现,因为宏在一行内完成,只能实现简单的函数功能。
为程序书写带来一些方便。当程序中需要书写一些相同的内容是,不妨把它定义为宏。
带参数的宏定义
宏要实现简单的函数功能,参数的使用必不可少。因为宏定义常常限制在一行中,所以只能实现简单的函数功能。
#include <stdio.h> #define FUN(x,y) ((x)*(y)) int main() { int a, b; scanf("%d %d", &a, &b); int c = FUN(a, b); printf("%d", c); return 0; }
宏引用形式与函数调用非常相似,但两者的实现过程完全不同。宏在程序编译时,所有出现宏名的地方,都会用宏定义字符串来替换,所以宏也常称为宏替换。宏替换在程序编译预处理时完成,对于FUN(x,y)的编译预处理,首先用变量a和b分别替换x、y,然后再用包含a、b的表达式来替换FUN(a,b)。编译结束后,程序中的FUN(a,b)便会消失。
如图所示。
int main { ...... int c = a*b; ...... }
如果定义函数FUN(x,y),对它的处理要到程序执行是才进行,首先进行参数传递,把实参值复制给形参x和y,然后主函数暂停执行,计算机转去执行函数FUN(),等求到x*y的值,通过return语句返回,主函数再继续运行。
函数调用时,如果实参是表达式,要先计算表达式,再把结果值传递过去。而宏替换不作计算,直接替换进去。例如 ,求n=(x+y)^2,如果写成n=SQR(x+y),宏替换后将变成:n=x+y*x+y。
很明显,这并不是我们想要的结果。为了避免这个问题,我们可以在宏定义中增加括号:
#define SQR(x) (x)*(x)
宏替换是会将括号保留,n=SQR(x+y)会变成n=(x+y)*(x+y)。
宏定义中对变量加上括号,可提高替换后的运算优先级,有效避免宏替换带来的错误,保证宏替换的正确性。
2.指针
讲指针之前,我们先来讲讲内存。内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的。所以为了有效地利用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是一个字节,为了能够有效地访问到内存的每个单元,就给内存单元进行编号,这些编号就被称为内存单元的地址。
如果我们要想存储一个变量的地址,那么我们就可以创建一个变量来存储它。那么创建的变量就是指针变量,它的值就是另一个变量的地址,也就是该指针变量指向那个变量。
定义指针变量的一般形式为:
类型名 *指针变量名;
类型名是指针变量所指向变量的类型,必须是有效的数据类型,如char、int、float等。指针变量名就是指针变量的名称,必须是一个合法的标识符。
那么现在我们就写一个程序来取出变量的地址。
#include <stdio.h> int main() { int n = 100; int* pn = &n; //将n的地址存储在指针变量pn中 printf("%p\n", pn); //打印变量n的地址,%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(long *)); printf("%d\n", sizeof(long long *)); printf("%d\n", sizeof(float *)); printf("%d\n", sizeof(double *)); return 0; }
结论:指针大小在32位平台是4个字节,64位平台是8个字节。
3.结构体
结构类型是一种允许程序员把一些数据分量汇合成一个整体的数据类型。一个结构中包含的每个数据分量都有名字,这些数据分量称为结构成员或者结构分量,结构成员可以是C语言中的任意变量类型。像数组一样,结构也是一种构造数据类型,它与数据的区别在于:数组中所有元素的数据类型必须是相同的,而结构体各成员的数据类型可以不同。
结构体定义的一般形式为:
struct 结构名 { 类型名 结构成员名1; 类型名 结构成员名2; ...... 类型名 结构成员名3; };
struct是定义结构体的关键字,在struct之后,自行命名一个结构名,它必须是一个合法的C标识符。struct与结构名两者联合起来共同组成结构类型名。
利用结构体我们可以描述一个学生,学生包含名字+学号+成绩这几项信息。
struct Stu { char name[20];//名字 char id[15]; //学号 int score; //成绩 };
那我们现在就编写一个程序来定义一个学生。
#include <stdio.h> struct stu { char name[20]; char id[15]; int score; }; int main() { struct stu s = { "zhangsan","202200202022",98 }; // .为结构成员访问操作符 printf("name = %s id = %s score = %d\n", s.name, s.id, s.score); //->操作符 struct stu* ps = &s; printf("name = %s id = %s score = %d\n", ps->name, ps->id, ps->score); return 0; }
定义一个学生
struct stu s = { "zhangsan","202200202022",98 }; //初识化
注意:定义的时候信息要一一对应
我们可以通过scanf("%s %s %d", s.name, s.id, &s.id); 来录入一个学生的信息
打印学生信息
.为结构成员访问操作符,我们可以通过这个操作符来访问到学生信息。
->操作符也可以用来打印学生信息。但是使用这个操作符,我们需要定义一个指针变量来存储变量s的地址。
那么C语言的基础知识已经介绍完了,如果觉得有收获的话,可以点小赞噢。