重点要点目录
常见关键字
常见关键字有以下这些,我会挑一部分出来用代码来解释这些关键字用法,与其用文字详写,不如实战见真章。
auto break case char const continue default do double else enum
extern float for goto if int long register return short signed
sizeof static struct switch typedef union unsigned void volatile while
关键字auto
其实我们在使用代码的时候就一直是在用aoto关键字了,只是我们编译器省略了这个关键字,让你在没有aoto这个关键字时也可以正常的赋值以及coding。
//常见关键字
int main()
{
auto int a = 10;//局部变量等于自动变量
return 0;
}
关键字swhich case, break, continue,
知识点: continue 不能用于swhich。
switch case
//
//break 停止中断用于循环, switch
//continue 继续用于循环
关键字typedef
typedef 顾名思义是类型定义,这里应该理解成类型重命名。
让我们来用代码举个例子
typedef unsigned int uint;
int main()
{
unsigned int num = 100;
uint num2 = 200;
//这两个都是一样的,只是赋值不一样。
}
主要用法就是将unsigned int 重命名为 uint,导致uint也可以和unsigned有相同的用法,成为一个新的类型名。
关键字register
翻译过来是寄存器的意思,寄存器是电脑的一个存储空间,在电脑上一般是集成到CPU上的,和内存是不同的独立存储空间(不能取地址&a)。
在编译过程中电脑一般会优先处理寄存器的内容,但是因为寄存器的空间比较小,所以为了避免大量的寄存器内容,编译器会考虑有些内容是否需要寄存器来优先编译。
比如:
int main()
{
//建议把一百放在寄存器中,编译器最终会决定是否放进去
register int a = 100;
return 0;
}
关键字static
在c语言中:static是用来修饰变量和函数的
- 修饰局部变量-静态局部变量
- 修饰全局变量-静态全局变量
- 修饰函数-静态函数
修饰局部变量
修饰局部变量,改变变量的生命周期,不影响作用域
我们来看看代码一和代码二的对比就可以清楚明显的知道是如何操作的。
代码一:
void test()
{
int a = 1;
a++;
printf("%d\n", a);//2222222222
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}
明显可以看到在voidl里面无论函数如何反复的进入,int a = 1始终不会改变,不会随着反复的进入使得初始值叠加,所以为了解决问题,我们可以使用static来修饰局部变量。
void test()
{
static int a = 1;
a++;
printf("%d\n", a);//2到11,共十个数
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}
这个代码片的结果就是可以叠加变量。
结论:
static修饰局部变量改变了变量的生命周期,让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。
修饰全局变量
当我们设置两个.c文件时,我将其命名为test.c和Add.c, 假如我们想在add文件中赋值一个变量使得可以让test.c文件可以调用这个变量,应该如何操作?
这个主要涉及到一个知识点,声明外部符号(extern),没有这个符号就不能调用外部的变量。
代码一
//add.c file
int g_val = 2010;
//test.c
//声明外部符号
extern int g_val;
int main()
{
printf("%d\n", g_val);
return 0;
}
现在我们加入关键字static来看看代码是否可以正常运行
代码二:
//add.c file
static int g_val = 2010;
//函数是具有外部链接属性的,
//如果被static·修饰,外部链接属性变成内部连接属性
//test.c
//声明外部符号
extern int g_val;
int main()
{
printf("%d\n", g_val);
return 0;
}
代码二在编译过程中出现错误。
结论:
一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,
不能在其他源文件内使用。
而函数也是一样的操作。
修饰函数
代码一
//add.c file
int ADD(int a, int b)
{
return a + b;
}
//修饰函数
//test.c
extern int Add(int a, int b);
int main()
{
int a = 10;
int b = 20;
int c = Add(a, b);
printf("%d\n", c);
return 0;
}
代码二
//add.c file
static int ADD(int a, int b)
{
return a + b;
}
//修饰函数
//test.c
extern int Add(int a, int b);
int main()
{
int a = 10;
int b = 20;
int c = Add(a, b);
printf("%d\n", c);
return 0;
}
很明显,代码一和代码二的区别就是add.c文件中是否有static,所以最后显示的是代码一正常编译,代码二会出现错误。
结论:
一个函数被static修饰, 使得这个函数只能在本源文件内使用,不能在其他源文件内使用。
#define 定义常量和宏
//define定义标识符常量
#define NUM 100
//define定义宏
#define MAX(x, y) (x>y?x:y)
int main()
{
int a = 10;
int b = 20;
int c = MAX(a+2, b);
//上面的代码相当于int c = (a+2 > b ? a+2 : b);
printf("%d\n", c);//20
printf("%d\n", NUM);//100
return 0;
}
指针
内存:
内存是电脑上特别重要的存储器,计算机中所有程序的运行都是在内存中进行的 。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。就如同如果你想寄一个快递给朋友,你需要详细的地址去找到准确的人送达快递。
我们电脑有32和64位地址线,分为负电和正电,也就是 1 / 0。
所以我们可以从32位全0变为32位全1个地址
如下:
00000000000000000000000000000000
00000000000000000000000000000001
00000000000000000000000000000010
…
1111111111111111111111111111111111111
一般来说,
char = 1 byte;
int = 4 byte;
short = 2 byte;
而电脑里一般都是1个地址可以存放一个byte的内存;所以一个int类型要分配四个地址才行。
我们来弄个代码来详细看看地址是怎样的
int main()
{
int num = 10;//向内存申请了四个内存的空间存放10;
#//取出num的地址
printf("%p\n", &num);
//打印地址,%p——以地址的形式进行十六进制打印
return 0;
}
打印的地址结果是这个。又因为int有四个地址,但其实编译器一般打印的地址是最小的那个地址也就是第一个地址。
要记住内存地址会随时改变,它没有一个固定的值,因为他的数据时刻在发生变化。就好比如你去宾馆租一间房,等你退了之后这间房也就不将属于你,等于内存销毁。
如果我们想储存地址的话又如何操作?
首先我们需要定义指针变量
int n = 10;
int *p ;
p = &n;
// p 就是一个存放地址的变量,
//这样的变量就被称为指针变量
实操代码
int main()
{
int num = 10;
int* p = #
//*指向的那个对象num是int类型
//所以*p前面也为int类型
//而这个*告诉我们p是一个指针变量
*p = 20;// * -解引用操作符
printf("%d\n", num);//打印20
return 0;
}
当p前面加上一个的意思是:通过p里面存的地址去找到他所指的那块空间num,所以p的意思就是a。
如果我们存的是char类型呢?
也是同理
int main()
{
char ch = 'w';
char* pc = &ch;
*pc = 'q';
printf("%c\n", ch);//打印q
return 0;
}
指针变量的大小
int main()
{
printf("%d\n", sizeof(char *));
printf("%d\n", sizeof(short *));
printf("%d\n", sizeof(int *));
printf("%d\n", sizeof(double *));
return 0;
}
这些指针变量的大小都取决于你是多少的平台。
指针大小在32位的平台上是四个字节,在64位的平台上则是八个字节。
这是因为假如我们的电脑是32位的机器,则我们就有32位的地址线,而以二进制数进行储存
00000000000000000000000000000000
00000000000000000000000000000001
00000000000000000000000000000010
…
1111111111111111111111111111111111111
则32个bit就有4个byte
反之,64位就有8个字节
再来一个例子
int main()
{
char c = 'w';
char* pc = &c;
printf("%d\n", sizeof(pc));//打印4或者8
return 0;
}
由这个代码可知地址的大小和你什么类型的值没有关系,所有的地址,不管他是什么地址,它的大小都是四个或者八个字节,取决于平台。
结构体
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型/对象。
比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。
又比如书:书名+作者+出版社+书号+定价
这里只能使用结构体来描述了。
//声明一个学生类型
struct student
{
char name[20];
int age;
char sex[5];
char id[12];
};
struct book
{
char name[20];
int price;
char author[20];
};
int main()
{
//创建的结构体变量
//打印结构体信息
struct student s1 = {"小a", 18, "男", "2020614"};
struct student s2 = { "小b", 19, "女","2020615" };
struct book b1 = { "c语言", 55, "小c" };
printf("名字:%s 年龄 :%d 性别:%s 学号:%s\n", s1.name, s1.age, s1.sex, s1.id);
//方法一
printf("%s %d %s", b1.name, b1.price, b1.author);
//方法二
printf("%s %d %s", (*pb).name, (*pb).price, (pb*).author);
//. - 结构体变量.成员名
//->操作符
struct student* ps = &s1;
//ps 就是struct student*它的类型
//这颗星也说明了ps是指针,而前面struct student是说ps指向的s1它的类型是struct book类型。
//方法三
printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps->id);
return 0;
}
就此,C语言知识入门概述全部完结,撒花。
点赞的事就拜托你们了【dog】