目录
常量指针与指针常量
常量指针
- 定义格式:
const *
//const 在*的前面。 - 指针所指向的内存单元的内容不能被改变。
- 指针变量本身的内容可以被改变也即可以改变指针变量的指向。
#include<stdio.h>
int mian()
{
int x = 0, y = 0;
const int * p = &x;//定义一个常量指针p并让p指向变量x
p = &y;//改变常量指针的指向是合法的
*p = 20;//非法(不能修改常量指针所指向的内存单元的内容)
return 0;
}
指针常量
- 定义格式:
* const
//*在const的前面 - 指针变量本身的内容不可以被改变。
- 指针变量所指向的内存单元的内容可以被改变。
#include<stdio.h>
int main()
{
int x = 0, y = 0;
int * const p = &x;//指针常量在定义的时候要对其进行初始化
p = &y;//非法(不能改变常量指针的指向)
*p = 20;//指针变量所指向的内存单元的内容可以被改变
return 0;
}
static在C语言中的三种用法
static修饰局部变量(静态局部变量)
- static修饰局部变量的时候改变了局部变量的生命周期但是并不会改变局部变量的作用域,而且此时被static修饰的局部变量会在编译器编译源文件的时候分配存储空间。
- 被static修饰的局部变量,当其所在的函数被调用的时候,该变量的声明语句并不会被执行而是会被跳过。
- 由于被static修饰的局部变量会在编译的时候分配内存且其会被分配在静态存储区。静态存储区用来存储被static修饰的局部变量和全局变量,所以被static修饰的局部变量的生命周期和全局变量的生命周期相同。
//代码段1
#include<stdio.h>
void test()
{
int i = 0;//auto类型的局部变量i
i++;
printf("%d\t",i);
}
int main()
{
int i = 0;
for(i = 0;i < 10; i++)
{
test();
}
return 0;
}
程序输出的结果:1 1 1 1 1 1 1 1 1 1
分析:变量的默认存储类型是auto类型。当进入变量的作用域的时候,变量会被分配内存。当离开其作用域的时候,变量会被销毁掉。所以,这里每次调用test()函数的时候,test()函数中的语句int i = 0;
会被执行,来给变量i分配内存并将其初始化为0。当离开test()函数的时候变量i
会被销毁。因此,每次对test()
的调用都会得到一个新的局部变量i
且其初值为0
。所以,这段程序执行的结果是:输出10个1。
//代码段2
#include<stdio.h>
void test()
{
static int i = 0;//static修饰的局部变量i
i++;
printf("%d\t",i);
}
int main()
{
int i = 0;
for(i = 0;i < 10; i++)
{
test();
}
return 0;
}
程序输出的结果:1 2 3 4 5 6 7 8 9 10
分析:在函数test()
中,由于变量i
的声明方式为static int i = 0;
所以,此时变量i
为静态局部变量。静态局部变量会在编译的时候被分配内存而且当其所在的函数被调用的时候,该变量的声明语句并不会被执行而是会被跳过。因此,当函数test()
每次被调用的时候语句static int i = 0;
并不会被执行而是会被跳过。由于被static修饰的局部变量的生命周期和全局变量相同,故当函数test()
被执行完毕的时候,变量i
并不会释放而是继续存在于静态存储区中。所以,这段程序的执行结果是:输出 1 2 3 4 5 6 7 8 9 10。
结论:
static
修饰局部变量改变了局部变量的生命周期,编译器会在编译源程序的时候为static修饰的局部变量在静态存储区分配存储空间,使得静态局部变量的生命周期与全局变量的生命周期相同。从而让被static修饰的局部变量出了作用域依然存在,到程序结束的时候被static修饰的局部变量的生命周期才会结束。
static修饰全局变量(静态全局变量)
- static修饰全局变量会改变全局变量的链接属性:
外链接--->内链接
。 - 这会使得对被static修饰的全局变量的引用只能在其被定义的源文件的内部被链接程序所解析,在其他源文件内部对被static修饰的全局变量的引用无法被链接程序所解析。
- static修饰的全局变量相当于使得该全局变量变为其被定义的文件内的私有的全局变量,在其他文件内不能对其进行引用。
//在add.c中将全局变量g_val声明为静态全局变量,使其变为文件内私有
//其他源文件中对add.c中所定义的静态全局变量g_val的引用在链接的时候不能被解析
//VS2017下面报错信息:LNK2001 无法解析的外部符号 _g_val
//add.c
static int g_val = 2018;
//test.c
#include<stdio.h>
extern int g_val;
int main()
{
printf("%d\n",g_val);
return 0;
}
结论:
一个被
static
修饰的全局变量,会使得其链接属性发生改变:外链接--->内链接
。进而使得被static修饰的全局变量只能在被定义的源文件中引用,不能在其他源文件中对其进行引用。
static修饰函数(静态函数)
- static修饰函数的时候同样会改变函数的链接属性:
外链接--->内链接
。 - 这使得对被static修饰的函数的引用只能在其被定义的源文件的内部被解析,在其他源文件内部对被static修饰的函数的引用无法被解析。
- static修饰的函数相当于使得该函数变为其被定义的文件内的私有的函数,在其他文件内不能对其进行引用。
//在add.c中将int Add(int x,int y)函数声明为静态函数,使其变为文件内私有
//其他源文件中对add.c中所定义的函数static int Add(int x, int y)的引用
//在链接的时候不能被解析
//VS2017下面报错信息:LNK2019无法解析的外部符号 _Add
//该符号在函数 _main 中被引用
//add.c
static int Add(int x, int y)
{
return x + y;
}
//test.c
#include<stdio.h>
int main()
{
printf("%d\n",Add(2,3));
return 0;
}
结论:
一个被static修饰的函数,会使得其链接属性发生改变:
外链接--->内链接
。进而使得被static修饰的全局变量只能在被定义的源文件中引用,不能在其他源文件中对其进行引用。
C语言中的内存模型(从变量分配的角度来看)
#include<stdio.h>
#include<malloc.h>
//编译器会为全局变量g_val在静态存储区分配存储空间
int g_val = 9;
//编译器会为静态局部变量g_val1在静态存储区分配存储空间
static int g_val1 = 10;
//当PrintX(int x)被调用的时候会在PrintX的栈帧上为形式参数x分配存储空间
void PrintX(int x)
{
printf("处于函数PrintX的栈帧中的形式参数x的值:%d\n",x);
}
int main()
{
//编译器会为静态局部变量在静态存储区分配存储空间
static int temp = 0;
//编译器会为局部变量pointer在main函数的栈帧上分配存储空间
//但是pointer所指向的由malloc()函数所开辟的空间是处于堆上面
int *pointer = (int* )malloc(sizeof(int));
*pointer = 8;
printf("处于静态存储区全局变量g_val的值:%d\n",g_val);
printf("处于静态存储区的静态全局变量g_val1的值:%d\n",g_val1);
printf("处于静态存储区的静态局部变量temp的值:%d\n",temp);
printf("处于main函数的栈帧中的局部指针变量pointer的值:%p\n",pointer);
printf("处于堆中的变量*p的值:%d\n",*pointer);
PrintX(100);
free(pointer);
return 0;
}