如果觉的博主的文章还不错的话,还请点赞,收藏,关注支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。
本篇介绍C语言的一些基础知识
另分享一篇关于vs快捷键的博文可能对大家的工作有所帮助:
本篇暂时不深入讲解,后续会逐渐渗透
C 程序主要包括以下部分:
// 单行注释
以 // 开始的单行注释,这种注释可以单独占一行。
1
2
3
4
5
6
/* 单行注释 */
/*
多行注释
多行注释
多行注释
*/
/* */ 这种格式的注释可以单行或多行。
让我们看一段简单的代码,可以输出单词 "Hello World":
1 2 3 4 5 6 7 8 9 | #include <stdio.h>//预处理指令,#是预处理指令的开头 int main()//main是主函数,是程序的入口,有且只有一个 { /* 我的第一个 C 程序 */ printf("Hello, World! \n");// printf是库函数,使用需要包含头文件stdio std //input output(标准输入输出) ""括起来的是字符串 // \n换行 return 0;//函数结束的标志,对应开头的int整型 } |
---|
下面的这种代码也是可以的 int main(void)//void表示main函数不需要参数 { return 0; }
不建议这样写: void main() { //这种写法是非常古老的 } 不标准的写法: main() { }
存在这么多的类型,其实是为了更加丰富的表达生活中的各种值。
char //字符数据类型 short //短整型 int //整形 long //长整型 long long //更长的整形
float //单精度浮点数,精确度低 double //双精度浮点数,精确度高
#include <stdio.h> int main () { printf("%d\n", sizeof(char)); printf ( "%d\n" , sizeof ( short )); printf ( "%d\n" , sizeof ( int )); printf ( "%d\n" , sizeof ( long )); printf ( "%d\n" , sizeof ( long long )); // %d 打印10进制的整数 printf ( "%d\n" , sizeof ( float )); printf ( "%d\n" , sizeof ( double )); printf ( "%d\n" , sizeof ( long double )); return 0 ; }
右侧所得单位为字节byte
电脑支持的是二进制语言
只能由字母(包括大写和小写)、数字和下划线( _ )组成。 不能以数字开头。 长度不能超过 63 个字符。 变量名中区分大小写的。 变量名不能使用关键字。
局部变量
全局变量
当局部变量和全局变量同名的时候,局部变量优先使用。
float weight = 45.5f ; //不加f编译器默认为double类型,加f强制转换为float类型
#include <stdio.h> int main () { int num1 = 0 ; int num2 = 0 ; int sum = 0 ; printf ( " 输入两个操作数 :>" ); scanf ( "%d %d" , & num1 , & num2 ); sum = num1 + num2 ; printf ( "sum = %d\n" , sum ); return 0 ; }
作用域
作用域( scope )是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效 / 可用
的而限定这个名字的可用性的代码范围就是这个名字的作用域。
1. 局部变量的作用域是变量所在的局部范围。 看最近的{ }即可判断
2. 全局变量的作用域是整个工程。
生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
2. 全局变量的生命周期是:整个程序的生命周期。
C 语言中的常量和变量的定义的形式有所差异。
C 语言中的常量分为以下以下几种:
字面常量:如100、3.14浮点型字面值、’a‘字符字面值、“abcde”字符串字面值
#include<stdio.h>
int main() {
int num = 10;
num = 20; //改变了变量num的值
printf("%d\n", num);
return 0;
}
直接输入变量,可以看出通过第四行的操作直接改变了变量的输出值
当在变量前面输入const 如下:
#include<stdio.h>
int main() {
const int num = 10;
num = 20;
printf("%d\n", num);
return 0;
}
报错: 第四行左值指定说明变量的值不允许改了,说明coonst具有指定作用,这时候后面的值num就具有了常量的属性,但num本质还是一个变量,所以称之为常变量
综上const用于需要一个常量,但此值不能改的时候
代码如下:
如上图输出值为100,如果再输入MAX=200;会怎样呢?
如图,报错左操作数必须为左值,说明define定义的这个量是不可改变的即常量
枚举>一一列举
c语言中的枚举类型num
如上输出值为0、1、2,是不可以改变的
需要注意的是enum下的标点符号
“hello world”
这种由双引号( Double Quote )引起来的一串字符称为字符串字面值( String Literal ),或者简称字符 串。
注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串
#include<stdio.h>
int main() {
char arr1[] = "abc";
char arr2[] = { 'a','b','c' };
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
如图可监视到字符串的结束标志\0
arr2输出乱码,但如果在其后加入‘\0’就输出abc,这里就不演示了
另外想要输出字符串的长度可以使用strlen库函数(string length),需要注意的是包含头文件#include<string.h>
演示:
#include<stdio.h>
#include<string.h>
int main() {
char arr1[] = "abc";
char arr2[] = { 'a','b','c','\0' };
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));
return 0;
}
结果:
下面这种方式arr2的输出值为随机值,因为没有\0
假如我们要在屏幕上打印一个目录: c:\code\test.c
我们该如何写代码?
#include <stdio.h> int main () { printf ( "c:\code\test.c\n" ); return 0 ; }
实际上程序运行的结果是这样的:
这里就不得不提一下转义字符了。转义字符顾名思义就是转变意思。
下面看一些转义字符。
\? | 在书写连续多个问号时使用,防止他们被解析成三字母词 |
---|---|
\' | 用于表示字符常量 ' |
\“ | 用于表示一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符 |
\a | 警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 就是键盘上Tab的意思 |
\v | 垂直制表符 |
\ddd | ddd表示1-3个八进制的数字。 \130 X |
\xdd | dd表示2个十六进制的数字。 如: \x30 0 |
现在一般不用
5.21 三字母词
如图??)或??(即为三转义字符分别代表】和【 如下图若用\加在?前则可防止编译器将他们翻译成三字母词,不过现在的编译器大多不支持三字母词,一些老旧编译器还是支持的
2.
如图想打印字符形式的单引号如图在单引号前加\即可实现,如图双引号类似 3.
如图,若想使 \t 不以转义字符的形式输出,则在其前加 \ ,正常输出。 5.22 \ddd
八进制数130转换成10进制数字,对应的值88 作为 ASCLL码值表示的字符是’X‘
5.23 xdd
八进制数字是0——7,所以输出14
1. 代码中有不需要的代码可以直接删除,也可以注释掉
2. 代码中有些代码比较难懂,可以加一下注释文字
注释有两种风格:
C 语言风格的注释 /*xxxxxx*/
缺陷:不能嵌套注释
C++ 风格的注释 //xxxxxxxx
可以注释一行也可以注释多行
if
#include <stdio.h> int main() { int coding = 0; printf("你会去敲代码吗?(选择1 or 0):>"); scanf("%d", &coding); if(coding == 1) { prinf("坚持,你会有好offer\n"); } else { printf("放弃,回家卖红薯\n"); } return 0;
C 语言中如何实现循环呢?
while 语句
for 语句
do ... while语句
这里暂时只接触一下while循环的实例
#include <stdio.h> int main() { printf("规划学习\n"); int line = 0; while(line<=20000) { line++; printf("我要继续努力敲代码\n"); } if(line>20000) printf("好offer\n"); return 0; }
#include <stdio.h> int main() { int num1 = 0; int num2 = 0; int sum = 0; printf("输入两个操作数:>"); scanf("%d %d", &num1, &num2); sum = num1 + num2; printf("sum = %d\n", sum); return 0; } 上述代码,写成函数如下: #include <stdio.h> int Add(int x, int y) { int z = x+y; return z; } int main() { int num1 = 0; int num2 = 0; int sum = 0; printf("输入两个操作数:>"); scanf("%d %d", &num1, &num2); sum = Add(num1, num2); printf("sum = %d\n", sum); return 0; } int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素 函数的特点就是简化代码,代码复用。
要存储 1-10 的数字,怎么存储?
C 语言中给了数组的定义: 一组相同类型元素的集合
int arr [ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; // 定义一个整形数组,最多放 10 个元素 //数组的初始化 int arr[10] = {1,2,3};//不完全初始化,剩余的值为0 int arr[ ] ={1,2,3};//不指定大小时,根据后面初始化的值输出 int arr[ ] //这种写法是完全错误的,不指定大小必须进行初始化 int arr[10]//随机值 int main() { int n = 10; int arr[n];//c99 允许数组在创建的时候用变量指定数组大小,但是这种数组不能初始化 return 0; }
C 语言规定:数组的每个元素都有一个下标,下标是从 0 开始的。
数组可以通过下标来访问的。
比如:
#include <stdio.h> int main () { int i = 0 ; int arr [ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; for ( i = 0 ; i < 10 ; i ++ ) { printf ( "%d " , arr [ i ]); } printf ( "\n" ); return 0 ; }
c语言是非常灵活的,就是因为操作符多
简单介绍为主,后面课件重点讲。
+ - * / % 前面三个和数学中基本一样,这里介绍一下后两个
#include<stdio.h>
int main() {
printf("%d\n", 7 / 2);//3
printf("%lf\n", 7 / 2.0);//3.50000
printf("%.1lf\n", 7.0 /2);//3.5
return 0;
}
int main() {
printf("%d\n", 7 % 2);//7/2=3……1
printf("%d\n", 8 % 2);//……0
}
>> << 向右向左移动二进制位 这里涉及二进制的计算和存储,暂时不作介绍
&按位与 ^按位异或 |按位或
= += -= *= /= &= ^ = |= >>= <<=
int main() {
int a = 10;//这就是赋值操作符
a = a + 5;
a += 5;
return 0;
}
如上a +=5;等价于a =a+5; 后面的 -= *= /= 与之类似
,只有一个数的操作符
! 逻辑反操作 - 负值 + 正值 & 取地址 sizeof 操作数的类型长度(以字节为单位) ~ 对一个数的二进制按位取反 -- 前置、后置 -- ++ 前置、后置 ++ * 间接访问操作符 ( 解引用操作符 ) ( 类型 ) 强制类型转换
这里首先介绍一下c语言中如何表示真假以便以下代码片段的理解: 0表示假 非0表示真
int main() { //
int a = 0; //
scanf("%d",&a); // 1
printf("%d\n", a); // 1
printf("%d\n", !a); // 0 //只有一个操作数a
}
c语言语法规定:当假变为真时输出固定值1,假一直为0,手动输入任何非0值都输出真
int main() {
int flag = 0;
if (flag)//flag为真,打印hehe
{
printf("hehe\n");
}
if (!flag)//flag为假打印haha
{
printf("haha\n");
}
return 0;
}
int main()
{
int a = -10;
int b = -a; //通过-改变了a的符号
printf("%d\n", b);
}
int c = +a;
printf("%d\n", c);//这样输出无法改变a的正负
所以‘+’一般基本不用
后面所附数字是输出结果
> >= < <= != 用于测试 “ 不相等 ” == 用于测试 “ 相等 ”
&& 逻辑与 || 逻辑或
需要注意下面绿色的写法是错误的
exp1 ? exp2 : exp3 解析如下: exp1 ? exp2 : exp3 表达式 判断真假 真执行 假执行
如图,若a>b为真,则输出a的值 若a>b为假,则输出b的值
exp1 , exp2 , exp3 , …expN
按顺序执行,结束出结果
int main()
{
int a = 3;
int b = 0;
int c = 4;
int d = (a=b-3,b=a+c,c=a-b,a=c+3);
//a=-3 b=1 c=-4 a=-1
printf("%d\n", d);
return 0;
}
11.9 下标引用、 函数调用 和结构成员
[] () . -> 结构体中使用,后期介绍
下表列出了 C 中的关键字。这些关键字不能作为常量名、变量名或其他标识符名称。
关键字 | 说明 |
---|---|
auto | 声明自动变量 |
break | 跳出当前循环 |
case | 开关语句分支 |
char | 声明字符型变量或函数返回值类型 |
const | 声明只读变量 |
continue | 结束当前循环,开始下一轮循环 |
default | 开关语句中的"其它"分支 |
do | 循环语句的循环体 |
double | 声明双精度浮点型变量或函数返回值类型 |
else | 条件语句否定分支(与 if 连用) |
enum | 声明枚举类型 |
extern | 声明变量或函数是在其它文件或本文件的其他位置定义 |
float | 声明浮点型变量或函数返回值类型 |
for | 一种循环语句 |
goto | 无条件跳转语句 |
if | 条件语句 |
int | 声明整型变量或函数 |
long | 声明长整型变量或函数返回值类型 |
register | 声明寄存器变量 |
return | 子程序返回语句(可以带参数,也可不带参数) |
short | 声明短整型变量或函数 |
signed | 声明有符号类型变量或函数 |
sizeof | 计算数据类型或变量长度(即所占字节数) |
static | 声明静态变量 |
struct | 声明结构体类型 |
switch | 用于开关语句 |
typedef | 用以给数据类型取别名 |
unsigned | 声明无符号类型变量或函数 |
union | 声明共用体类型 |
void | 声明函数无返回值或无参数,声明无类型指针 |
volatile | 说明变量在程序执行中可被隐含地改变 |
while | 循环语句的循环条件 |
sizeof 计算的结果单位是字节 sizeof不是函数,是操作符
int main()
{
int a = 10;
printf("%d\n", sizeof(a));//4
printf("%d\n", sizeof a );//4
printf("%d\n", sizeof(int));//4
return 0;
}
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));//40,计算的是数组的总大小,单位是字节
printf("%d\n", sizeof(arr[0]));//4
printf("%d\n", sizeof(arr) / sizeof(arr[0]));//40 /4=10
//数组的元素个数如何计算
int sz = sizeof(arr) / sizeof(arr[0]);
return 0;
}
#include <string.h>
int main() {
char arr1[] = "abc";
char arr2[] = { 'a', 'b','c' };
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));
printf("%d\n", sizeof(arr1));
printf("%d\n", sizeof(arr2));
return 0;
}
输出结果如下:
strlen 是库函数 是求字符长度的,关注的是字符串中是否有\0,统计\0之前出现的字符个数
sizeof 是操作符 只关注占据了多大的内存空间,不关注内存中存放的数据
sizeof 返回的单位是字节
typedef 顾名思义是类型定义,这里应该理解为 类型重命名。 比如: // 将 unsigned int 重命名为 uint, 所以 uint 也是一个类型名 typedef unsigned int uint ; int main () { // 观察 num1 和 num2, 这两个变量的类型是一样的 unsigned int num1 = 0 ; uint num2 = 0 ; return 0 ; }
register 寄存器关键字,起一个建议的作用,可以加快处理的速度,但由于计算机的发展,会自行识别重要与否,从而决定
在 C 语言中:
static 是用来修饰变量和函数的
1. 修饰局部变量 - 称为静态局部变量
2. 修饰全局变量 - 称为静态全局变量
3. 修饰函数 - 称为静态函数
//代码1
#include <stdio.h>
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
//代码2
#include <stdio.h>
void test()
{
//static修饰局部变量
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
如下图
对比代码 1 和代码 2 的效果理解 static 修饰局部变量的意义。
输出结果如图 对比理解static修饰局部变量的意义。
结论:
static 修饰局部变量改变了变量的生命周期
让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。
static修饰局部变量的时候,改变了变量的存储类型
普通的变量是存储在栈区的,被static修饰的变量是存储在静态区的
存储在静态区的变量,除了作用域不会销毁,依然存在
静态变量的生命周期就是程序的生命周期,程序结束的时候静态变量才回收空间
static 修饰局部变量改变了变量的生命周期
让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。
//代码1
//add.c
int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0; }
//代码2
//add.c
static int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0; }
代码1正常,代码2 在编译的时候会出现连接性错误。
结论:
一个全局变量被 static 修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使
用。
全局变量是具有外部链接属性的,static修饰全局变量的时候,这个全局变量的外部连接属性就变成了内部连接属性,这个全局变量只能在自己所在的.c文件中看到,其他源文件无法使用
//代码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;
代码 1 正常,代码 2 在编译的时候会出现连接性错误 .
结论:
一个函数被 static 修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。
剩余关键字后续课程中陆续会讲解。
#include也称为预处理指令
代码演示如下:
//define 定义标识符常量 #define MAX 1000 // MAX 的值就是1000 //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 );// 宏会直接替换上面的(2)+(3)) 而函数则需要调用 printf ( "sum = %d\n" , sum ); return 0 ;
这里需要注意一下函数和宏的区别
宏和函数各有优缺点,具体暂时不谈
学习 C 语言的指针既简单又有趣。通过指针,可以简化一些 C 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。所以,想要成为一名优秀的 C 程序员,学习指针是很有必要的。
正如您所知道的,每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。请看下面的实例,它将输出定义的变量地址:
1 2 3 4 5 6 7 8 9 10 11 12 | #include <stdio.h> int main () { int var1; char var2[10]; printf("var1 变量的地址: %p\n", &var1 ); printf("var2 变量的地址: %p\n", &var2 ); return 0; } |
---|
当上面的代码被编译和执行时,它会产生下列结果:
1 2 | var1 变量的地址: 0x7fff5cc109d4 var2 变量的地址: 0x7fff5cc109de |
---|
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:
1 | type *var-name; |
---|
在这里,type 是指针的基类型,它必须是一个有效的 C 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。以下是有效的指针声明:
1 2 3 4 | int *ip; /* 一个整型的指针 */ double *dp; /* 一个 double 型的指针 */ float *fp; /* 一个浮点型的指针 */ char *ch; /* 一个字符型的指针 */ |
---|
所有实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,对应指针的值的类型都是一样的,都是一个代表内存地址的长的十六进制数。
不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。
使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 ***** 来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <stdio.h> int main () //变量var是创建在内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。 { int var = 20; /* 实际变量的声明 */ //var向内存申请4个字节的空间 int *ip; /* 指针变量ip 的声明 */指针变量是用来存放地址的 ip = &var; /* 在指针变量中存储 var 的地址 */ip的类型根据var的类型进行声明 //&var; //取出a的地址, // 注:这里a的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址) printf("Address of var variable: %p\n", &var );//打印地址,%p是以地址的形式打印 /* 在指针变量中存储var的地址 */ printf("Address stored in ip variable: %p\n", ip ); /* 使用指针访问值 */ printf("Value of *ip variable: %d\n", *ip ); return 0; } |
---|
当上面的代码被编译和执行时,它会产生下列结果:
1 2 3 | Address of var variable: bffd8b3c Address stored in ip variable: bffd8b3c Value of *ip variable: 20 |
---|
指针本质是地址,口头语中指的是指针变量(上面代码中的ip)
int main() { int a = 10; int* pa = &a;//& 取地址操作符 *pa = 20;//* 解引用操作 printf("%d\n", a); return 0; }
//要想知道指针变量有多大? //指针变量存储的是什么? - 地址 //地址的存储需要多大空间,指针变量的大小就是多大
int main() { printf("%zu\n", sizeof(char*));//zu专门用来打印sizeof返回值 printf("%zu\n", sizeof(short*)); printf("%zu\n", sizeof(int*)); printf("%zu\n", sizeof(long*)); printf("%zu\n", sizeof(float*)); printf("%zu\n", sizeof(double*)); return 0; }
//32位机器 - 一个地址是32个二进制位,存储需要32个bit位的空间,所32位机器上,指针变量的大小是4个字节 //64位机器 - 一个地址是64个二进制位,存储需要64个bit位的空间,所64位机器上,指针变量的大小是8个字节
//取决于编出程序的大小
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是 1 个字节 。
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该 内存单元的地 址 。
结构体是 C 语言中特别重要的知识点,结构体使得 C 语言有能力描述复杂类型。
比如描述学生,学生包含: 名字 + 年龄 + 性别 + 学号 这几项信息。
这里只能使用结构体来描述了。
例如:
struct Stu { char name [ 20 ]; // 名字 int age ; // 年龄 char sex [ 5 ]; // 性别 char id [ 15 ] ; // 学号 };
结构体的初始化:
// 打印结构体信息 struct Stu s = { " 张三 " , 20 , " 男 " , "20120101" }; //. 为结构成员访问操作符 printf ( "name = %s age = %d sex = %s id = %s\n" , s . name , s . age , s . sex , s . id ); //结构体变量.结构体成员 //-> 操作符 struct Stu * ps = & s ; printf ( "name = %s age = %d sex = %s id = %s\n" , ps -> name , ps -> age , ps -> sex , ps - > id );