零基础玩转C语言系列第一章——初始C语言(下)
目录
【前言】:该篇博文是对初始C语言(上)的补充,内容不多,不过这部分有很多的知识点属于C语言中的重难点,所以小伙伴们好好康康哦。
【声明】:初始C语言部分就是简单介绍一下C语言的大体知识,所有知识点都是点到为止,后面博文中笔者会详细介绍。
在进入正文之前,麻烦铁汁们将初始C语言(上)再回顾一遍。
https://blog.csdn.net/weixin_57544072/article/details/120799064?utm_source=app&app_version=4.17.0
1、数组
1.1 数组定义
//定义一个整型数组,并且给定了其大小,最多放10个元素
int array[10] = {1,2,3,4,5,6,7,8,9,10};
1.2 数组的下标
int array[10] = {1,2,3,4,5,6,7,8,9,10};
//该数组是10个元素,下标的范围是0-9
1.3 数组的使用
举个栗子:
#include<stdio.h>
int main()
{
int i = 0;//使用i产生下标
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
while (i < 10)
{
printf("%d ", arr[i]);//通过下标来访问数组
i++;
}
putchar('\n');
return 0;
}
2、操作符
C语言中包含了非常丰富的操作符,所以有人说,C语言是非常灵活的。甚至可以直接对二进制位进行操作。
2.1 算术操作符
+ - * / %
这里先简单介绍一下特别容易出错的/ 和 %
- / : double ret = 7 / 2; 结果是3.000000(暂时先不用管为什么小数点后面那么多0),实际上我们想要的结果是3.5, 那该怎么办呢?改成double ret = 7.0 / 2; 或者改成double ret = 7 / 2.0;
- %:取模,也叫求余,一定要注意的是取模操作符只能应用于整数哦,浮点数是不可以的,这点一定要注意。比如:7 % 2 = 1;(商3,余1)
2.2 移位操作符
>> <<
为什么叫移位操作符呢?因为其作用于一个数的二进制位
左移:<< 相当于乘法
右移:>> 相当于除法
2.3 位操作符
& ^ |
这里的“位” 指的是二进制位
按位与&:对应的二进制位有0,则为0,全1在为1;
按位或|:对应的二进制位有1,则为1,全0才为0;
按位异或^:对应的二进制位相同,则为0,相异才为1;
注意:对位操作实际上是对存储在内存上的二进制位进行操作的,然而整数在内存上存储的是其二进制的补码形式,所以对位操作,也就是对二进制的补码进行的操作。
2.4 赋值操作符
= += -= *= /= &= ^= != >>= <<=
除了第一个,后面几个属于复合运算符
2.5 单目操作符
2.6 关系操作符
2.7 逻辑操作符
&& 逻辑与---“并且”
|| 逻辑或---“或者”
2.8 条件操作符
exp1 ? exp2 : exp3
注意exp代表的是表达式,后面还会提到。
条件运算符,又称为三目运算符,表达式1为真,则计算表达式2的值,跳过表达式3,也就是说表达式2的结果就是整个表达式的结果;反之,若表达式1为假,跳过表达式2,直接计算表达式3的值,也就是说表达式3的结果就是整个表达式的结果。
2.9 逗号表达式
exp1,exp2,exp3...expN
注意:逗号表达式会从左向右依次计算,整个表达式的结果是最后一个表达式的结果
3、常见关键字
- 关键字不能自己创建
- 关键字不能作为变量名
- define不是关键字
3.1 关键字typedef
typedef 顾名思义就是类型定义,这里应该理解为类型的重命名。
typedef unsigned int uint_32;
//由于unsigned int比较复杂,所以用typedef将它重命名为uint_32,所以此时uint_32就是一个类型名,代表了unsigned int
3.2 关键字register
register---寄存器关键字
register int a = 10; // a是寄存器变量
register 是起到的是建议作用,“建议” 编译器将a放到寄存器中,不会真的放进去,它有自己的一套判断规则。
注意:不能对寄存器变量取地址,如上面的&a就是错误的
3.3 static关键字
static ---静态的
C语言中,static是用来修饰变量和函数的。
- 修饰局部变量---静态局部变量
- 修饰全局变量---静态全局变量
- 修饰函数---静态函数
1.static修饰局部变量
//代码1
#include<stdio.h>
void test()
{
int a = 1;//局部变量a的作用域在test()中,当a出了作用域就被销毁了,下次调用test()时,又需要重新创建a
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
test();
}
return 0;
}
//代码2
#include<stdio.h>
void test()
{
//static修饰局部变量a
static int a = 1;
a++;
printf("%d ",a);
}
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
test();
}
return 0;
}
看:上面的两个代码几乎一样,只不过第二个代码中自定义函数test()里面用static修饰局部变量,所以出现了这样的差异。
根据代码2的结果推测出每一次调用test(),使用的a都是上一次函数调用时留下的a;第二次调用test()时,由于上次函数调用产生的a没有被销毁,所以不会再次创建a,直接跳到了下一步,a++
注意:static修饰局部变量的时候,其实是改变了变量的存储类型,由栈区存储变成了静态区存储,从而使得静态的局部变量出了自己的作用域也不会被销毁,其实也就是相当于改变了这个变量的生命周期。
这里补充一条小知识点:
内存是一块比较大的空间,在使用内存的时候,会划分出不同的功能区域:栈区、堆区、静态区
2.static修饰全局变量
//代码1
//add.c文件
int g_val = 2018;//g_val是在add.c文件中定义的
//test.c文件
//如果想使用来自其他文件(外部文件)的全局变量,要先声明一下
extern int g_val;
//extern是一个关键字,专门用来声明外部符号的
int main()
{
printf("%d\n", g_val);
return 0;
}
上面这个程序是正常编译的,不过下面的这个程序就不一定了哦
/代码2
//add.c文件
static int g_val = 2018;
//test.c文件
extern int g_val;
int main()
{
printf("%d\n", g_val);
return 0;
}
上面这个程序编译的时候会报错,因为出现连接性错误。
解释:一个全局变量在整个工程中的其他子文件内部能被使用,是因为全局变量具有外部链接属性 ,什么叫外部链接属性,一个变量在一个文件中定义,但是在另一个文件中可以使用(访问)叫外部链接属性。当一个全局变量被static修饰的时候。其外部链接属性就变成了内部连接属性;使得这个全局变量只能在只能在自己的源文件内部使用,其他文件不能再使用,因为它不再具有外部链接属性,给我们的感觉是作用域变小了。
另外,局部变量只有内部连接属性
3.static修饰函数
//代码1
//add.c文件
int Add(int x, int y)
{
return x + y;
}
//test.c文件
extern int Add(int x, int y);
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
上面的程序编译正常,但是下面的程序编译时会出现错误哦。
//代码2
//add.c文件
static int Add(int x, int y)
{
return x + y;
}
//test.c文件
extern int Add(int x, int y);
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
这个程序编译时出现连接性错误。
因为函数也具有外部链接属性,static修饰函数的时候,函数本来是具有外部链接属性的,但是被static修饰后,就变成了内部连接属性,导致这个函数只能在自己的源文件内部使用,给我们的感觉是改变了作用域。
4、#define定义常量和宏
//define定义标识符常量
#define MAX 100
//define定义宏(宏和函数是非常相似的)
#define Add(x, y) ((x) + (y))
5、指针
指针这块内容是非常重要的,与此同时,指针也是很难的,不过铁汁们放心哦,后面笔者会用大量的篇幅去介绍它,这里,简单让大家了解一下。
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的,为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节,为了能够有效的访问到内存中的每个单元,就把内存单元进行了编号,这些编号被称为内存单元的地址。
#include<stdio.h>
int main()
{
int num = 10;//num要在内存中开辟空间
#// 取出num的地址,地址也称为指针,注意这里num是一个整型变量,4个字节,每个字节都有地址
//但是取出的是第一个字节的地址(较小的地址)
printf("%p\n", &num);//%p是以地址的形式进行打印
int* p = #
*p = 20;//p是用来存放地址的,p是一个指针变量
return 0;
}
上面代码中的num 和 p 在内存中就像下图那样存储,只是一个抽象的图,现在看不懂没关系,因为这里只是简单了解,后面笔者会详细介绍的。
这里分析一段程序:
#include<stdio.h>
int main()
{
int num = 10;
int* p = #//int前面的‘*’告诉我们p是一个指针变量,这里的int表示p指向一个整型变量
*p = 20;//‘*’是解引用操作符,通过p的值,我们找到了p所指向的对象,所以‘*p’就是‘num’
return 0;
}
计算指针变量的大小:
指针变量有多大?地址的存放需要多大空间?地址是如何产生的?地址是什么样的数据?
指针大小在32位平台占4个字节,64位平台占8个字节
注意编译器上X86代表32位,X64代表64位
6、结构体
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型
人:复杂对象(名字 + 年龄 + 性别 + ...);
书:复杂对象(书名 + 作者 + 出版社 + ...)
.......
生活中还有很多这样的复杂对象
#include<stdio.h>
int main()
{
struct Stu//结构体类型
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
};
//结构体初始化
struct Stu s = { "小高", 20, "未知" };
//'.'为结构体成员访问操作符 用法:结构体变量 . 结构体成员
printf("name = %s age = %d sex = %s\n", s.name, s.age, s.sex);
//'->'操作符
struct Stu* ps = &s;
printf("name = %s age = %d sex = %s\n", (*ps).name, (*ps).age, (*ps).sex);
printf("name = %s age = %d sex = %s\n", ps->name, ps->age, ps->sex);
//注意'.'和'->'都是结构体成员访问操作符
return 0;
}
补充:一个汉字是占两个字节的哟。
7、结束语
初始C语言部分到此就结束咯,下一篇博文将会介绍选择语句和循环语句,感觉有所收获的铁汁们给笔者来个三连吧,感谢喔。
文章来源: bit-runout.blog.csdn.net,作者:安然无虞,版权归原作者所有,如需转载,请联系作者。
原文链接:bit-runout.blog.csdn.net/article/details/121000424
- 点赞
- 收藏
- 关注作者
评论(0)