【C语言】C语言入门宝典:核心概念全解析
.
C语言专栏 | C++专栏👉 个人主页 👈
前言
此篇文章我们主要是宏观的了解一下什么是C语言,C语言里面有那些知识点,所有的知识点我们此篇只是以入门为主,点到为止,简单易懂,后期的文章会一 一详细剖析这些知识
目录
- 1.什么是C语言
- 1.1 第一个C语言程序
- 1.2 main函数的几种写法
- 2.数据类型
- 3.变量和常量
- 3.1 定义变量的方法
- 3.2 变量的分类
- 3.3 变量的使用
- 3.4 变量的作用域和生命周期
- 3.5 常量
- 4.字符串+转义字符
- 4.1 字符串
- 4.2 转义字符
- 5.选择语句
- 6.循环语句
- 7.函数
- 8.数组
- 8.1 数组的定义
- 8.2 数组的下标
- 8.3 数组的使用
- 9.操作符
- 10.常见关键字
- 10.1 关键字typedef
- 10.2 关键字static
- 10.2.1 修饰局部变量
- 10.2.2 修饰全局变量
- 10.2.3 修饰函数
- 11.define定义常量和宏
- 12.指针
- 12.1 内存
- 12.2 指针变量的大小
- 13.结构体
1.什么是C语言
C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言
1.1 第一个C语言程序
#include int main() { printf("Hello world"); return 0; }main是主函数 是程序的入口,写的C语言代码都是从main函数的第一行开始执行的 main函数是必须有的,但是有且仅有一个 上面所使用的printf是库函数,库函数是C语言标准库中的函数,可以直接使用 printf--将信息打印到屏幕上 库函数的使用是需要包含头文件的,printf所需要的头文件是stdio.h
1.2 main函数的几种写法
①这种写法非常古老,不推荐这样写
void main() { printf("Hello world"); }②这种写法是🆗的
int main(void)//void是在明确表明main函数不接收任何参数 { printf("Hello world"); }③这种写法也是可以的,看见了也不要觉得意外
int main(int argc, char* argv[])//int argc, char* argv[] 是在指定main函数的参数 { return 0; }总结:我们平时用第二种写法会比较多,但是我们写的时候通常省略了参数void,这样写也是没问题的
2.数据类型
char //字符数据类型 short //短整型 int //整形 long //长整型 long long //更长的整形 float //单精度浮点数 double //双精度浮点数
每种类型的大小又是多少呢?
讲到大小,我们就不得不说一下计算机中的单位了
int main() { //%d -- 打印整形 printf("%d\n", sizeof(char));//1个字节 printf("%d\n", sizeof(short));//2个字节 printf("%d\n", sizeof(int));//4个字节 printf("%d\n", sizeof(long));//4个字节 printf("%d\n", sizeof(long long));//8个字节 printf("%d\n", sizeof(float));//4个字节 printf("%d\n", sizeof(double));//8个字节 return 0; }sizeof是一个操作符,用于计算数据的大小,单位是字节
C语言标准:
sizeof(long long)>sizeof(long)>sizeof(int)>sizeof(short)>sizeof(char)
3.变量和常量
生活中的有些值是不变的(比如:圆周率,性别,身份证号码,血型等等)
有些值是可变的(比如:年龄,体重,薪资)
不变的值,C语言中用常量的概念来表示,变的值C语言中用变量来表示
3.1 定义变量的方法
使用类型 变量名的形式来定义变量
int age=10; float weight=99.9f;//默认情况下写99.9编译器会将其识别为double类型,加上f就变成float类型 char ch='v'; //3.14 double类型 //3.14f float类型
🚩tips:变量的命名要规范
- 只能由字母、数字、下划线(_)组成
- 不能以数字开头
- 长度不能超过63个字符
- 变量名中是区分大小写的
- 变量名不能使用关键字
变量名尽量取的有意义一点
3.2 变量的分类
变量分为全局变量和局部变量
全局变量:在{ }外边定义的变量就是全局变量
局部变量:就是{ }内部定义的变量就是局部变量
int a = 100;//全局变量 int main() { int a = 1;//局部变量 printf("%d\n", a);//打印结果为1 -- 局部优先原则,先在局部范围搜索,没有再去全局范围找 return 0; }小结:当局部变量和全局变量同名的时候,局部变量优先使用
3.3 变量的使用
先简单介绍一下scanf这个函数,scanf也是库函数,你可以认为他和printf是一对,scanf用来输入printf用来输出(打印)
scanf 函数是输入函数 函数的返回值是: 1.如果读取成功,返回的是实际读取到的数据个数 2.如果读取失败,返回EOF,EOF的值是-1
int main() { int a; int b; int ret=scanf("%d %d", &a,&b); //& -- 取地址操作符,取出变量的地址 printf("%d\n", ret); return 0; }读取成功时:
读取失败时:
3.4 变量的作用域和生命周期
作用域:
作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。
- 局部变量的作用域是变量所在的局部范围。
- 全局变量的作用域是整个工程。
生命周期:
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
- 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
- 全局变量的生命周期是:整个程序的生命周期。
3.5 常量
C语言中的常量分为以下以下几种:
- 字面常量
- const 修饰的常变量
- #define 定义的标识符常量
- 枚举常量
//枚举常量的关键字enum //枚举 -- 就是一 一列举 //三原色:红,绿,蓝 //星期:星期一/二/三…… //性别:男,女 //等等这些都是可以一 一列举出来的 enum color { //枚举常量 RED, //0 GREEN, //1 BLUE //2 }; int main() { 3.14;//字面常量 100;//字面常量 //常变量 const int a = 10;//const修饰的变量叫常变量,本质上还是个变量 //a = 1;被const修饰的变量不能被修改 #define NUM 100;//#define 定义的标识常量符 int number = NUM;//这个NUM就是100,在预编译期间直接将所有的NUM替换为100 enum color c1 = RED; enum color c2 = GREEN; enum color c3 = BLUE; printf("%d\n", c1); printf("%d\n", c2); printf("%d\n", c3); return 0; }4.字符串+转义字符
4.1 字符串
由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。
注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
int main() { char arr1[] = "BCX"; char arr2[] = { 'B', 'C', 'X' }; char arr3[] = { 'B', 'C', 'X','\0' }; printf("%s\n", arr1); printf("%s\n", arr2); printf("%s\n", arr3); return 0; }提问:上面代码打印的结果是什么?为什么?
使用双引号引起来的字符串默认字符串的结尾是带有\0的,\0是字符串的结束标志,arr1有\0,打印结果正常,arr2赋值的都是字符,没有\0,打印的过程中会一直向后找\0,直至找到\0为止,所以后面会打印什么东西我们也不知道,都是随机的,arr3手动加上\0,也能正常打印出结果
4.2 转义字符
假如我们想打印一串路径
int main() { printf("c:\code\test.c\n"); return 0; }为什么打印的结果和我们想的不一样?这就不得不介绍一下转义字符了,转义字符顾名思义就是转变意思
三字母词
int main() { printf("(are you ok??)");//(are you ok] -- 在之前低版本的编译器上会被识别为这样,现在基本上不会 printf("(are you ok\?\?)");//这样写不管在那个版本的编译器上都能确保打印出(are you ok) //??) -- ] //??( -- [ //三字母词 return 0; }’ 和 "
int main() { //%s -- 打印字符串 //%c -- 打印字符 printf("%s\n",""");//打印双引号 printf("%c\n",''');//打印单引号 return 0; }上面这样写是会报错的,因为编译器会将前面两个双引号识别为一对,后面那个就成落单的了,这样会有语法错误,单引号也是同样的道理,这里我们需要用到转义符将其意义转变
//正确写法 printf("%s\n","\""); printf("%c\n",'\'');重点
①\ddd ,ddd表示1~3个八进制的数字
int main() { printf("%d\n", '\1');//打印的结果是1 -- 8^0=1 printf("%d\n", '\12');//10 -- (8^0)*2+8^1=10 printf("%d\n", '\123');//83-- (8^0)*3+(8^1)*2+(8^2)*1=83 return 0; }②\xdd dd表示1~2个十六进制的数字
int main() { printf("%d\n", '\x1');//1 -- 16^0=1 printf("%d\n", '\x12');//18 -- (16^0)*2+(16^1)*1=18 return 0; }5.选择语句
生活处处是选择,常见的选择语句有if,else,else if,switch等等,我们下面使用if else来进行演示
int main() { printf("你要吃什么(1--西瓜,2--烤红薯)?\n"); int choice; scanf("%d", &choice); if (choice == 1) { printf("吃冰西瓜\n"); printf("凉爽"); } else { printf("烤红薯\n"); printf("炎热"); } return 0; }6.循环语句
C语言中实现循环的语句有:while,do while,for
我们今天只简单讲解一下while,另外两个后期会详细介绍
while(表达式) { 循环语句; } 表达式为真,会反复执行循环语句,直至表达式为假例:求1~10的和
int main() { int i=1; int sum=0; while(i sum+=i; i++; } printf("%d", sum); } int sum=x+y; return sum; } //如何调用函数呢? int main() { int a = 10, b = 1; //函数调用 int z = Add(a, b);//将a传给x,b传给y return 0; } 1,3}; int arr2[10];//这样定义可以不用初始化,默认初始化为0,这个数组最多存放10个元素 int arr3[3]={1,2,3}; int i = 0; int arr[10] = {1,2,3,4,5,6,7,8,9,10}; while(i printf("%d ", arr[i]); //arr[i]访问i位置处的元素 i++ } return 0; }h29.操作符/h2 p这里简单介绍一下,后期文章会一一讲到/p p算术操作符:/p pre class="brush:python;toolbar:false" + - * / % /pre p计算机将/叫做除,%叫做取模(或取余)/pp例子:/p pre class="brush:python;toolbar:false"7/2 在数学中的结果为3……1 在计算机中 7/2=3 除法取商 7%2=1 模取余数 /pre p移位操作符:这个运算符涉及到二进制位,我们后期讲,现在知道有这么个东西就行/p pre class="brush:python;toolbar:false"> >= int i=2; i+=1;//实际上就是i=i+1; i-=1;//i=i-1; i*=2;//i=i*2; i/=2;//i=i/2; } //C语言中:0为假,非0为真 int ret=10; //! -- 真的变成假的,假的变成真的 if(ret!=10)//ret==10为真,ret!=10为假 printf("不为10"); else printf("为10");//会打印这个 return 0; } p++ 和 - -请看此文,里面详细介绍了 C语言中的++和- -/p p关系操作符:/p pre class="brush:python;toolbar:false" >=逗号表达式:
exp1, exp2, exp3, …expN
举例说明:
int main() { int a = 1; int b = 2; int c = 3; //逗号表达式要依次执行,但整体的结果以最后一个表达式为准 int d = (a = 3, c = 2, a + b + c); //第一个表达式将a的值修改为3,第二个表达式将c的值修改为2,所以到最后一个表达式时a,c的值已经发生了更改 a+b+c=3+2+2=7 printf("%d\n", d); return 0; }下标引用、函数调用和结构成员
[] () . ->
10.常见关键字
10.1 关键字typedef
typedef 顾名思义是类型定义,这里应该理解为类型重命名
//将double类型重命名为Dou,所以Dou也是一个类型名 typedef double Dou; int main() { double d = 19.2; Dou dt = 2.2; //这里的d变量和dt变量本质上没什么区别,都是double类型的变量 return 0; }10.2 关键字static
在C语言中:
static是用来修饰变量和函数的
- 修饰局部变量-称为静态局部变量
- 修饰全局变量-称为静态全局变量
- 修饰函数-称为静态函数
10.2.1 修饰局部变量
void test() { int i = 0; i++; printf("%d ", i); } int main() { int i = 0; for (i = 0; i这个代码的打印结果应该是循环打印5个1,因为test()函数里面的局部变量i每次调用完出了作用域之后就被销毁了,所以i每次调用时会重新创建,出函数就销毁
若是给test()函数里面的局部变量i用static修饰会怎样?
void test() { //static修饰局部变量 static int i = 0; i++; printf("%d ", i); } int main() { int i = 0; for (i = 0; i用static修饰后,使得局部变量i的生命周期变长(变得和全局变量的生命周期一样长),但作用域是不变的,上述代码的执行结果为打印1~5
小结:
- static修饰局部变量改变了变量的生命周期
- 让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束
10.2.2 修饰全局变量
test1.c文件中的代码:
//全局的 int a=100;
test2.c文件中的代码:
//extern--声明来自外部文件的符号 extern int a;//告诉编译器这个类型的变量a来自其他.c文件 int main() { printf("%d\n", a);//100 //test2.c文件中本来是没有a变量的,但是test1.c文件中有一个全局变量a,我们通过外部引用可以使用这个变量 return 0; }被static修饰:
test1.c文件中的代码:
//全局的 static int a=100;
test2.c文件中的代码:
//extern--声明来自外部文件的符号 extern int a;//告诉编译器这个类型的变量a来自其他.c文件 int main() { printf("%d\n", a); return 0; }当我们运行这个代码的时候会报错
编译器不认识这个变量a,我们不是声明了这个变量来自其他.c文件吗?为什么不认识这个变量
原因:全局变量是具有外部链接属性,这种属性决定了全局变量在多个文件之间可以互相用,static修饰全局变量的时候,将外部链接属性变成了内部链接属性,a只能在当前的.c文件内部使用,不能在其他的.c文件中使用了
小结:一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用
10.2.3 修饰函数
其实static修饰函数和修饰全局变量如出一辙
test1.c文件中的代码:
int add(int a, int b) { return a + b; }test2.c文件中的代码:
//extern--声明来自外部文件的符号 extern add(int a, int b); int main() { int x = 1, y = 2; int sum = add(x, y);//正常使用该函数 printf("%d\n", sum); return 0; }函数被static修饰后:
static int add(int a, int b) { return a + b; }再次运行时会报错
报错原因:函数也是具有外部链接属性的,这种属性决定了函数是可以跨文件使用的,static修饰函数是把函数的外部链接属性改成了内部链接属性,使得函数只能在自己所在的.c文件中使用
小结:一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用
11.define定义常量和宏
//define定义标识符常量 #define MAX 1000 //define定义宏 #define ADD(x, y) ((x)+(y)) //宏的名字是ADD,它接受两个参数:x和y // 宏名 参数 宏体 #include int main() { //宏的本质是替换 int sum = ADD(2, 3);//这里ADD(2, 3)会被替换为宏体((2)+(3)) printf("sum = %d\n", sum); return 0; }12.指针
12.1 内存
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
同样的64位的机器上,地址线有64根,内存空间就会更大一点
变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。
取出变量地址如下:
int main() { int num = 10; #//取出num的地址 //注:这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址) printf("%p\n", &num);//打印地址,%p是以地址的形式打印 return 0; }num的四个字节都有各自的地址,我们取出来的是地址较小的那个
有了地址,那我们要如何存储?使用指针变量对地址进行存储
例:
int main() { int num = 10; int *p = # //* 说明p是一个指针变量,int表示该变量指向的是int类型的数据 *p = 20; //* 解引用操作符 - 通过地址找到地址所指向的对象。*pa就等价于a return 0; }总结:
- 内存会被划分以字节为单位的一个个的内存单元
- 每个内存单元都有编号,编号 =地址=指针
- C语言中创建的变量,其实是向内存申请一块空间,比如:int a = 10,就是向内存申请4个字节的空间,每个字节都有地址
- &a的时候,拿出的是4个字节中地址较小的那个字节的地址(编号)
- 这个地址要存储起来,给一个变量,这个变量是用来存放地址(指针)所以叫指针变量:int *pa = &a;
- pa中存放的是a的地址,要通过pa中的地址找到a,怎么写?*pa–> 通过pa中的地址找到a *pa = 20;//本质是修改a
12.2 指针变量的大小
在32位机器的环境下,我们可以看到指针变量p的大小是4个字节的
我们来看一下其他类型的指针变量是否还是这个大小
int main() { printf("%d\n", sizeof(int*)); printf("%d\n", sizeof(char*)); printf("%d\n", sizeof(double*)); printf("%d\n", sizeof(short*)); return 0; }我们可以看到在x86环境下我们的指针变量大小都是4个字节,然而在x64环境下,指针变量大小是8个字节
总结:
指针变量的大小取决于地址的大小
32位平台下地址是32个bit位(即4个字节)
64位平台下地址是64个bit位(即8个字节)
13.结构体
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。这里只能使用结构体来描述了
例如:
//struct定义结构体的关键字 struct Stu { //这里写结构体的成员变量或其他 char name[20];//名字 int age; //年龄 char sex[5]; //性别 char id[15]; //学号 };//定义并初始化结构体 struct Stu s = {"张三", 20, "男", "20180101"}; //.为结构成员访问操作符 printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id); //->操作符 struct Stu *ps = &s;//ps是给结构体类型的指针,通过->操作符访问结构体成员变量 printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps- >id);C语言入门第一篇就讲到这里,如果有什么问题都可以在评论区留言哦,我会及时解决💌
















