"零星的变好,最后也会像星河一样闪耀。” 今天我们从关键字开始学起吧!
十一.常见关键字
上一篇已经给大家介绍了一下简单介绍了一下常见的关键字有哪些,今天我们就简单介绍几种常见的关键字。
1.typedef
typedef顾名思义是类型定义的,这里理解为类型重命名。
#include <stdio.h>
//typedef-类型重命名
typedef unsigned int uint;
typedef int INT;
int main()
{
//以下两种表达方式相同:
unsigned int num1 = 10;
uint num2 = 10;
int num3 = 10;
INT num4 = 10;
return 0;
}
2.static
在C语言中,static是用来修饰变量和函数的。
1.修饰局部变量-称为静态局部变量
2.修饰全局变量-称为静态全局变量
3.修饰函数-称为静态函数
(1).修饰局部变量
#include <stdio.h>
test()
{
static int i = 1;//static修饰局部变量使得该局部变量为静态局部变量
//一个普通的局部变量,进入函数创建,出函数销毁
//但被static修饰后,进入函数时已经创建好,出函数的时候也不销毁,多次调用函数时,共享一个变量。
//主观感受就是生命周期变长了,但是作用域不变,只能在局部范围内使用
//普通局部变量放在栈区,而被static修饰后放在了静态区
i++;
printf("%d ", i);
}
int main()
{
int j = 0;
while (j < 5)
{
test();
j = j + 1;
}
return 0;
}
(2).修饰全局变量
全局变量具有外部链接属性,这种属性决定了全局变量可以在多个文件之间相互使用。
上图中的代码为什么不能正常运行呢?答案是每个.c文件都经过编译器单独处理的,那么我们该如何解决这种问题呢?这里就用到了extern这个关键字,extern是声明来自外部文件的符号,告诉编译器:year来自其他文件。
这里,我们再来看一看如果用static修饰全局变量,会发生什么呢?
这里,我们可以发现,又报错了。static修饰全局变量的时候,将外部链接属性变为了内部链接属性,使得year只能在当前的.c文件中使用。给我们的感觉是改变了作用域。
(3).修饰函数
通过下面这段代码,我们可以发现函数也是具有外部链接属性的,这种属性决定函数是可以跨函数使用的。
但是如果我们不希望函数可以跨文件使用时,这个时候可以用static修饰函数,这样可以使得该函数只能在其所在的.c文件中使用。
十二.#define定义常量和宏
前面也有提过,常量分为了字面常量、const修饰的常变量、#define定义的标识符常量以及枚举常量。下面给大家介绍一下#define定义的标识符常量:
#include <stdio.h>
//#define定义的标识符常量
#define M 100
#define C 'A'
int main()
{
printf("%d\n", M);
int a = M;
printf("%d\n", a);
printf("%c\n", C);
return 0;
}
关于#define定义的标识符常量可以理解为给常量起别名,如上述代码中,使得100为M,‘A’为C,程序在运行的时候,即将代码中的M再换回100,C再换回’A’,这样能够使得程序更加简便。
接下来,我们再来看一下#define定义的宏:
通过前面的学习,我们知道想要用函数求两个数的和可以这样写:
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 3;
int b = 5;
int c = Add(a, b);
printf("%d\n", c);
return 0;
}
那么,利用#define定义的宏我们又可以怎么写呢?
#include <stdio.h>//宏是替换的作用
#define Add(x,y) (x+y) //#define 宏的名字(宏的参数)宏的内容
int main()
{
int a = 3;
int b = 5;
int c = Add(a, b);
printf("%d\n", c);
return 0;
}
可以看出,两种方法得到的结果相同,对比可以发现宏的参数不需要写类型,也没有函数体的大括号,参数也没有形参与实参之分。
十三.指针
13.1内存
要学好指针,首先,我们先一起了解一下内存。那么,内存是什么呢?内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的,所以,我们为了更有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为了该内存单元的地址。C语言中把地址也叫做指针。
通过调试,我们可以发现a占有4个字节,每个字节都有它所对应的地址,如下图所示:
但是对a进行取地址的时候只会访问到最小的那个地址:
13.2指针变量
指针变量:用来存放地址的变量。(存放在指针中的值都被当作地址来处理)
#include <stdio.h>
int main()
{
int a = 10;
//&取地址操作符
//这里就是将a的4个字节的第一个字节的地址存放在pa变量中。
int * pa = &a;//数字,假设为0x0012ff48(起始位置的地址) -内存的编号==地址==指针,pa叫指针变量
//*是在说明pa是指针变量,int是在说明pa指向一个int类型的变量
*pa = 20;//*解引用操作符 - 通过地址找到地址所指的对象 *pa等价于a
printf("%d\n", a);
return 0;
}
这里我们可以发现pa等价于a,因此,我们可以通过改变pa的值,从而改变a的值。
小总结:
1.内存会被划分以字节为单位的一个个的内存单元。
2.每个内存单元都有编号,编号 = 地址 = 指针。
3.C语言中创建的变量,其实是向内存申请一块空间,比如int a = 10;就是向内存申请4个字节的空间,每个字节都有地址。
4.&a的时候,拿出的是4个字节中地址较小的那个字节的地址(编号)。
5.这个地址要储存起来,给一个变量,这个变量是用来存放地址(指针),所以叫做指针变量:int * pa = &a;
6.pa中存放的是a的地址,要通过pa中的地址找到a,*pa等价于a.
同样的,对于字符型的变量一样可以:
#include <stdio.h>
int main()
{
char ch = 'b';
char * pc = &ch;
*pc = 'c';
printf("%c\n", ch);
return 0;
}
13.3指针变量的大小
#include <stdio.h>
int main()
{
//指针变量的大小:
char* pc;
short* pv;
int* pi;
printf("%d\n", sizeof(pc));
printf("%d\n", sizeof(pv));
printf("%d\n", sizeof(pi));
return 0;
}
由运行的结果,我们可以看出,不管什么类型的指针变量,大小都是4个字节。由于指针变量是用来存放地址的,所以指针变量的大小就取决于存放一个地址需要多大的空间。因此,指针变量的大小在32位的平台上是4个字节,在64位的平台上是8个字节。
十四.结构体
这里可以先用结构体声明一个学生类型让大家初步了解一下:
//用结构体声明了一个学生类型:
struct Stu
{
char name[20];
int age;
float score;
};
#include <stdio.h>
int main()
{
int num;
struct Stu stu1 = {
"张三",20,88.8f};
struct Stu stu2 = {
"李四",19,90.5f};
struct Stu stu3 = {
"王五",21,95.5f};
printf("%s %d %f\n", stu1.name, stu1.age, stu1.score);
printf("%s %d %f\n", stu2.name, stu2.age, stu2.score);
printf("%s %d %f\n", stu3.name, stu3.age, stu3.score);
return 0;
}
同样,我们可以用上上面所学的指针来进行优化:
int main()
{
int num;
struct Stu stu1 = {
"张三",20,88.8f};
struct Stu stu2 = {
"李四",19,90.5f};
struct Stu stu3 = {
"王五",21,95.5f};
struct Stu* ps1 = &stu1;
struct Stu* ps2 = &stu2;
struct Stu* ps3 = &stu3;
printf("%s %d %f\n", ps1->name, ps1->age, ps1->score);
printf("%s %d %f\n", ps2->name, ps2->age, ps2->score);
printf("%s %d %f\n", ps3->name, ps3->age, ps3->score);
return 0;
}
注:1.结构体变量.结构体成员
2.结构体指针->结构体成员
好啦,今天就学到这里啦,欢迎大家关注、点赞和评论!