关键字static
c语言中的static关键字是用来修饰变量和函数的,可以分为以下三种情况
1.修饰局部变量--静态局部变量
c语言中的局部变量和静态局部变量在内存中的存储位置。
static修饰局部变量的时候,改变了局部变量的存储类型,但是作用域还是不变的;本来一个局部变量是存储在栈区的,被static修饰的局部变量是存储在静态区的,存储在静态区的变量出了作用域变量也不会销毁,所以生命周期较长,即static修饰的局部变量、全局变量的生命周期和程序的生命周期是一样的。
#include<stdio.h>
void fun() {
static n = 1; //在汇编文件中没有该句对应的汇编语句
n++;
printf("%d\n", n);
}
int main() {
fun(); // 2 ,只有第一次调用fun()函数时 static n = 1;才会执行,然后该句在静态区中创建一个n变量
fun(); // 3 , 该句会直接执行n++,去静态区找到n变量,然后将n++,因为静态区的变量不会在出作用域时被销毁
//所以 n = 2,当执行n++后,n变为3。
return 0;
}
2.修饰全局变量--静态全局变量
val为add.c文件中定义的全局变量,而全局变量有外部链接属性,所以在test.c编译后的链接步骤中可以链接到add.c文件中使用val变量。而static修饰全局变量的时候,改变了全局变量的链接属性;本来一个全局变量具有外部链接属性的,但是被static修饰之后就变成了内部链接属性。这是static修饰的全局变量只能在本源文件(.c)中使用,其他文件无法再使用到。
3.修饰函数--静态函数
static修饰函数和修饰全局变量有相似的作用,当在Add.c中定义一个函数时,在test.c中使用extern声明后就可以使用。但是如果Add.c中的函数被static修饰后,就不能在test.c中使用了。
其实static修饰函数和修饰全局变量是类似的,一个函数本来也是具有外部链接属性的。但是当被static修饰的时候,外部链接属性就变成了内部链接属性,这个函数就只能在本源文件内部使用了,其他文件不能再使用了。
#define定义常量和宏
#define可以定义常量
#define定义的常量在预处理文件中都被替换为代表的值。
#include<stdio.h>
#define NUM 100 //定义int型
#define STR "string" //定义字符串
int main() {
int a = NUM; //在预处理文件中为 int a = 100; 直接将NUM都替换为100
char arr[10] = STR; //在预处理文件中为 char arr[10] = "string";
printf("%d\n", NUM); //都会将NUM替换为100
printf("%s", STR); //都会将STR替换为字符串"string"
return 0;
}
#define定义宏
#include<stdio.h>
//#define定义的宏是有参数的
#define ADD(x,y) ((x)+(y)) //尽量加括号,以保证使用宏时不会产生歧义
int main() {
int res = ADD(2, 3); //在预编译文件中会变为 int res = ((2) + (3));
printf("%d", res);
return 0;
}
指针
内存和内存单元
内存是电脑上特别重要的存储器,计算机中所有程序的运行都是在内存中进行的 。 所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。 为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
指针
指针就相当于地址,我们直到int a 就是用来存储一个int 型整数的,所以int* pa就是用来存储一个int* 型的指针(地址)的。
#include<stdio.h>
int main() {
int a = 10;
int* pa = &a; //& -- 取地址操作符
*pa = 20; //* -- 解引用操作符
printf("%d", a);
//指针变量pa就是用来存放地址的一种变量
return 0;
}
内存会被划分为小的内存单元,一个内存单元的大小是1个字节。
每个内存单元都有编号,这个编号也被称为:地址\指针。
地址\指针据可以存放在一个变量中,这个变量被称为指针变量
通过指针变量中存储的地址,就能找到指针指向的空间,并且可以取出或者修改该空间中存的数据。
任何数据放在指针变量里面,都会被解析为地址,如果指针变量里面存了3,即int *pa = 3,则*pa=5就会将0x 03 00 00 00当成地址解析,并且会将该地址里面存储的的数据变为5。
指针变量的大小
指针变量是用来存放地址的,地址的存放需要多大空间,指针变量的大小就应该是多大。
32位机器 -- 支持32位虚拟地址空间 - 产生的地址就是32bit位 -- 需要32bit的空间存储
即4byte -- 所以32位机器中指针变量的大小就是4byte。(因为指针变量就是存储地址的)
64位机器 -- 支持64位虚拟地址空间 -- 产生的地址就是64bit位 -- 需要64bit的空间存储
即8byte -- 所以64位机器中指针变量的大小就是8byte
#include<stdio.h>
int main() {
int a = 10;
char ch = 'a';
double d = 3.3;
int* pa = &a;
char* pch = &ch;
double* pd = &d;
printf("%d\n", sizeof(pa)); //32位机器为4,64位机器为8
printf("%d\n", sizeof(pch)); //32位机器为4,64位机器为8
printf("%d\n", sizeof(pd)); //32位机器为4,64位机器为8
return 0;
}
结构体
c语言中的内置类型有时候不足以存储我们的数据,所以我们可以根据结构体创建自己想要的类型,即自定义类型。
#include<stdio.>
//描述一个学生
//创建一个学生类型
struct Stu {
char name[20]; //成员
int age; //成员
char sex[5];
double score;
};
int main() {
struct Stu s1 = { "张三",20,"男",90.5 }; //初始化一个struct Stu类型的变量
struct Stu s2 = { "如花",30,"女",97.5 };
//输入结构体成员的数据
scanf("%s %d %s %lf", s1.name, &(s1.age), s1.sex, &(s1.score)); //因为成员name和sex为数组,所以数组名就是元素首地址
//结构体成员访问操作符 . 和 ->
//结构体变量.结构体成员
printf("%s %d %s %lf\n", s1.name, s1.age, s1.sex, s1.score);
struct Stu* ps1 = &s1; //将结构体s1的地址存储到指针变量ps1中
//结构体指针(地址)->结构体成员
printf("%s %d %s %lf\n", ps1->name, ps1->age, ps1->sex, ps1->score);
return 0;
}