【C语言——初识C语言(4)】


前言

接上文内容,本文仍然是C语言基础内容的预备知识。


11、 常见关键字

在这里插入图片描述
上面面是常见的关键字,先介绍以下几个关键字:

11.1 关键字 typedef

typedef 顾名思义是类型定义,这里应该理解为类型重命名,例如,将unsigned int 重命名为uint_32, 所以uint_32也是一个类型名,观察num1和num2,这两个变量的类型是一样的。

//将unsigned int 重命名为uint_32, 所以uint_32也是一个类型名
typedef unsigned int uint_32;
int main()
{
    
    
	//观察num1和num2,这两个变量的类型是一样的
	unsigned int num1 = 0;
	uint_32 num2 = 0;
	return 0;
}

11.2 关键字static

在C语言中,static是用来修饰变量和函数的,有3个用法:

  1. 修饰局部变量-称为静态局部变量
  2. 修饰全局变量-称为静态全局变量
  3. 修饰函数-称为静态函数

11.2.1 修饰局部变量

static修饰局部变量,延长作用周期:

对比代码1和代码2的效果理解static修饰局部变量的意义。
代码1打印结果: 1 1 1 1 1 1 1 1 1 1
代码2打印结果: 1 2 3 4 5 6 7 8 9 10

代码1中, 局部变量i在test()函数内,函数运行结束时,i的值就没有了,存放变量i的内存空间释放了。等下一次调用函数test()时,变量i又要重新初始化,赋值为0。
其作用范围: 就在test()函数内,出来函数数值销毁;
作用周期:,函数开始调用到函数调用结束。

代码2中, static修饰局部变量i,在test()函数内,函数运行结束时,i的值仍然存在,存放变量i的内存空间没有释放了。等下一次调用函数test()时,静态局部变量i不需要重新赋值为0,这句代码已经失效了,变量i会保留上一次的,并在此基础上执行语句。
其作用范围: 出了在test()函数,数值仍然存在;
作用周期:,整个工程结束时。

//代码1
#include <stdio.h>
void test()
{
    
    
	int i = 0;
	i++;
	printf("%d ", i);//输出10个1
}
int main()
{
    
    
	int i = 0;
	for(i=0; i<10; i++)
	{
    
    
		test();
	}
	return 0;
}
//代码2
void test()
{
    
    
	//static修饰局部变量
	static int i = 0;
	i++;
	printf("%d ", i);
}
int main()
{
    
    
	int i = 0;
	for(i=0; i<10; i++)
	{
    
    
		test();//输出1-10
	}
	return 0;
}

结论:
static修饰局部变量改变了变量的生命周期
让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。

11.2.2 修饰全局变量

代码1正常,代码2在编译的时候会出现连接性错误。

结论:
一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。

//代码1
//add.c
int g_val = 2018;//函数定义在add.c的源文件中

//test.c
int main()//主函数在test.c的源文件中
{
    
    
	printf("%d\n", g_val);
	return 0;
}

//代码2
//add.c
static int g_val = 2018;//函数定义在add.c的源文件中

//test.c
int main()//主函数在test.c的源文件中
{
    
    
	printf("%d\n", g_val);
	return 0;
}
//代码3
//extern 是用来声明外部符号的
extern int global;//在add源文件中定义的全局变量可以在test中使用

int main()
{
    
    
	printf("%d\n", global);
	return 0;
}

11.2.3 修饰函数

代码1正常,代码2在编译的时候会出现连接性错误.
结论:
一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。

//代码1
//add.c
int Add(int x, int y)
{
    
    
	return c+y;
}
//test.c
int main()
{
    
    
	printf("%d\n", Add(2, 3));
	return 0;
}

//代码2
//add.c
static int Add(int x, int y)//只能在本源文件中使用
{
    
    
	return c+y;
}
//test.c
int main()
{
    
    
	printf("%d\n", Add(2, 3));
	return 0;
}
//代码3
//将在其他源文件定义的函数,经过声明以后可以在本源文件中直接使用
extern int add(int x, int y);

int main()
{
    
    
	int num1 = 9;
	int num2 = 5;
	int sum = 0;

	sum = add(num1, num2);
	printf("%d\n", sum);
	return 0;
}

12、#define 定义常量和宏

宏定义,名称一般全大写

//define定义标识符常量
#define MAX 1000
#define STR "hello bit"//字符串直接用双引号

//define定义宏
#define ADD(x, y) ((x)+(y))

#include <stdio.h>
int main()
{
    
    
	int sum = ADD(2, 3);
	printf("sum = %d\n", sum);
	sum = 10*ADD(2, 3);
	printf("sum = %d\n", sum);
	return 0;
}

13、指针

13.1 内存

内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。

所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。

为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址:

在这里插入图片描述
变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。取出变量地址如下:

int main()
{
    
    
	int num = 10;
	&num;//取出num的地址
	//这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址)
	printf("%p\n", &num);//打印地址,%p是以地址的形式打印
	return 0;
}

在这里插入图片描述
那地址如何存储,需要定义指针变量,指针就是地址
内存单元都有编号,这个编号就是地址,我们把这个地址也叫指针.

//内存单元都有编号,这个编号就是地址,我们把这个地址也叫指针
int main()
{
    
    
	int a = 10;
	//%p取地址操作,存放变量a数值的地址
	printf("%p\n", &a);
	return 0;
}
int num = 10;
int *p;//p为一个整形指针变量
p = &num;//地址传给指针p,  

#include <stdio.h>
int main()
{
    
    
	int num = 10;
	//pa是用来存放地址的变量,所以pa为指针变量
	int *p = &num;
	//*是解引用操作,*pa,就是将pa存放的地址所对应的值取出来
	//*pa原来对应的值是10,现在重新赋值,就是20了
	*p = 20;//重新给地址存放的变量赋值
	printf("%d\n", a);
	return 0;
}

在这里插入图片描述
字符使用指针的例子:

int main()
{
    
    
	char ch = 'w';
	char* pc = &ch;
	*pc = 'q';
	printf("%c\n", ch);
	return 0;
}

13.2 指针变量的大小

指针变量的大小取决于地址的大小
32位平台下地址是32个bit位(即4个字节)
64位平台下地址是64个bit位(即8个字节)

//指针变量的大小取决于地址的大小
//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(double *));
	return 0;
}

下面这个例子中,一个字符的地址占4个字节,整形数组也是4个字节,两个输出结果都是4。

指针大小就是固定的4个字节。地址的大小和地址存放的数值类型没有任何关系

int main()
{
    
    
	char ch = 'w'; //0x0012ff48
	int a = 10;//0x0012ff40

	int * pa = &a;
	char * pc = &ch;
	
	printf("%d\n", sizeof(pa));//地址占4个字节
	printf("%d\n", sizeof(pc));	
	//两个输出结果都是4,指针大小就是固定的4个字节
	//大小和地址存放的数值类型没有任何关系
	//32位平台就是x86, 指针大小是4个字节
	//64位平台就是x64, 指针大小是4个字节
	return 0;
}

14、 结构体

操作符 -> 是结构成员访问操作符,使用方法如下:
结构体指针->结构体成员
操作符 . 是结构成员访问操作符,使用方法如下:
结构体变量.结构体成员

//结构体变量
struct stu
{
    
    
	char name[20];
	int age;
	char sex[5];
	char id[20];
};

int main()
{
    
    
	struct stu s = {
    
     "张三",20,"男", "20180101" };
	struct stu s2 = {
    
     "李四",19,"女", "20180102" };
	
	//printf("name=%s age=%d sex=%s id=%s\n", s.name, s.age, s.sex, s.id);
	printf("%s %d %s %s\n", s.name, s.age, s.sex, s.id);
	
	struct stu *ps = &s2;
	printf("%s %d %s %s\n", ps->name, ps->age, ps->sex, ps->id);
	return 0;
}

使用typedef可以将结构体的名称简写:
stu就是struct stu

typedef struct stu
{
    
    
	char name[20];
	int age;
	char sex[5];
	char id[20];
}stu;

void print(struct stu* ps)//结构体类型的指针变量
{
    
    
	//printf("%s %d %s %s\n", (*s3).name,(*s3).age, (*s3).sex, (*s3).id);
	printf("%s %d %s %s\n", ps->name, ps->age, ps->sex, ps->id);
	//-> 结构成员访问操作符
	//结构体指针->结构体成员
};

int main()
{
    
    
	//结构体的初始化
	struct stu s1 = {
    
     "张三",20,"男", "20180101" };
	struct stu s2 = {
    
     "周六",21,"女", "20180103" };
	stu s3 = {
    
     0 };//这是使用typedef的效果
	//stu就是struct stu
	
	输入结构体数据    name是数组名,就是首地址,age是整数,必须取地址
	scanf("%s %d %s %s", s1.name, &(s1.age), s1.sex, s1.id);
	//直接打印的
	printf("%s %d %s %s\n", s1.name, s1.age, s1.sex, s1.id);
	//. 结构成员访问操作符
	结构体变量.结构体成员

	//使用函数打印
	print(&s2);//传入地址,则函数定义必须使用指针了

	return 0;
}

总结

本文是初始C语言系列的最后一点内容了,目前算是将C语言的大部分内容快速预习了一遍,可以看作是C语言基础内容的预备知识,接下来将进入C语言基础阶段的学习。博客更新内容完全参照B站的学习视频。

之后接着是C语言进阶阶段的学习,最后再学习初级的数据结构与算法内容。这样完整的C语言阶段就结束了。后续也会跟着学习C++了。

猜你喜欢

转载自blog.csdn.net/taibudong1991/article/details/123714121