C语言修炼秘籍【第零章】c语言概述

C语言修炼秘籍【第零章】c语言概述

【心法】
【第零章】c语言概述
【第一章】分支与循环语句
【第二章】函数
【第三章】数组
【第四章】操作符
【第五章】指针
【第六章】结构体
【第七章】const与c语言中一些错误代码
【禁忌秘术】
【第一式】数据的存储
【第二式】指针
【第三式】字符函数和字符串函数
【第四式】自定义类型详解(结构体、枚举、联合)
【第五式】动态内存管理
【第六式】文件操作
【第七式】程序的编译



前言

c语言是一门编程语言。语言的作用就是交流,人们可以利用它与计算机进行交流,让计算机知道你需要它完成什么工作。本系列文章是对笔者在c语言学习的总结记录。本文会先粗略的介绍c语言中需要学习的内容。

c语言总体框架


一、数据类型

代码如下:

char // 字符数据类型
short // 短整型
int // 整型
long // 长整型
long long // 更长的整型 
float // 单精度浮点型
double // 双精度浮点型

c语言是用于让人们通过写程序,让计算机来解决现实生活中的实际问题的。所以它必须能描述这些问题,因此需要存在这些数据类型。

例如:现在需要描述一个人的身高–180cm,这就需要整型或短整型;描述体重–60.0kg,这就需要浮点类型。

每种类型所占字节数:

注释中前一个数字表示32位机器中类型所占空间,后者为64位机器中类型所占空间:

#include <stdio.h>

#define PRINT(type) printf(#type"`s size == %d\n", sizeof(type))

int main()
{
	PRINT(char); // 1/1
	PRINT(short); // 2/2
	PRINT(int); // 4/4
	PRINT(long); // 4/4
	PRINT(long long); // 8/8
	PRINT(float); // 4/4
	PRINT(double); // 8/8

	return 0;
}

32位机器中的执行结果:
32位机器中的执行结果
64位机器中的执行结果:
64位机器中的执行结果:

二、变量和常量

日常生活中即存在变量,如一个人的年龄,某天的气温等;也存在常量,如一个人的性别,身份证号等。

1.变量

1.1变量的定义

变量定义方法:类型 <变量名> = [初始值];

变量的定义示例,代码如下:

int age = 22;
char ch = 'a';
float weight = 66.6f;

1.2变量的分类

变量可分为

  • 局部变量
  • 全局变量

它们之间的区别在于作用域不同。局部变量的作用域仅在定义它的块中能够正常使用,它的生命周期从块的生命周期开始,出了块的生命周期就结束;全局变量的作用域是整个程序的生命周期中都有效,在程序的任何地方声明之后都能够使用。

变量示例,代码如下:

int global = 2025; // 全局变量

int main()
{
	int local = 2026; // 局部变量

	// 局部变量和全局变量重名时,程序会使用哪个变量?
	int global = 2027;
	printf("global == %d\n", global);
	
	return 0;
}

运行结果如下:
变量
结果说明,当出现局部变量和全局变量重名的情况时,局部变量的优先级高于全局变量。

tip:编程时要避免出现变量重名的情况发生。

2.常量

c语言中的常量可分为:

  • 字面常量
  • const修饰的常变量
  • #define定义的标识符常量
  • 枚举常量

常量示例,代码如下:

// 枚举常量
typedef enum {
	Red,
	Blue,
	Green
} Colour;

int main()
{
	// 字面常量
	3.14;
	114514;

	// const修饰的常变量
	const int i = 100; // i就是用const修饰的常变量,它是不能被修改的
	//i = 101;
	printf("i == %d\n", i);
	const char ch = 'a';
	//ch = 'A';
	printf("ch == %c\n", ch);

	// #define定义的标识符常量
	#define MAX 100
	printf("MAX == %d\n", MAX);

	// 枚举常量默认从0开始,依次递增
	Colour colour1 = Red;
	Colour colour2 = Green;
	printf("colour1 == %d\n", colour1);
	printf("colour2 == %d\n", colour2);

	return 0;
}

运行结果如下:

常量

其中,const修饰的常变量,其本质上仍是一个变量,但因为const的修饰,导致它的值不能被修改,所以也可以认为它是一个常量。当我们尝试去修改一个由const修饰的变量时,编译器一般都会报错,编译不会通过。

const编译错误

三、字符串、转义字符

1.字符串

"hello world.\n"

这种由双引号引起来的一串字符被称为字符串字面值,或简称为字符串。

注:字符串的结束标志为'\0',它是一个转义字符。在计算字符串长度时,'\0'仅作为结束标志,不计入字符串长度。但在计算字符数组的长度时,'\0'需要计入。

验证字符串中’\0’的存在示例,代码如下

#include <stdio.h>
#include <string.h>

int main()
{
	char arr1[] = "hehe";
	char arr2[] = { 'h', 'e', 'h', 'e' };
	char arr3[] = { 'h', 'e', 'h', 'e', '\0' };

	//打印三个字符数组
	printf("arr1:> %s\n", arr1);
	printf("arr2:> %s\n", arr2);
	printf("arr3:> %s\n", arr3);
	printf("\n");

	// 打印三个字符数组的长度
	printf("sizeof arr1:> %d\n", sizeof(arr1));
	printf("sizeof arr2:> %d\n", sizeof(arr2));
	printf("sizeof arr3:> %d\n", sizeof(arr3));
	printf("\n");

	// 打印三个字符串的长度
	printf("length of arr1:> %d\n", strlen(arr1));
	printf("length of arr2:> %d\n", strlen(arr2));
	printf("length of arr3:> %d\n", strlen(arr3));

	return 0;
}

运行结果:

字符串

从上述结果中,可以看出,arr1和arr3打印的结果是一致的,"hehe"{ 'h', 'e', 'h', 'e', '\0' }相同,与{ 'h', 'e', 'h', 'e' }不同。接下来,我们从内存角度再观察这三者存储的内容。

内存地址
可以看出,arr1和arr3这两个字符数组中总共有5个元素,arr2中只有4个元素。后者较前两者末尾少了一个'\0'字符,在使用printf(“%s”),格式化输出字符串类型的arr2变量时,在输出完它自己的hehe之后,没有遇到应有的'\0',继续输出内存中的内容,直到遇到'\0',所以arr2的输出结果不为hehe

sizeof操作符用于计算数组类型所占空间,库函数strlen用于计算字符串长度,从上面的结果中验证数组的长度是包括'\0'在内的,而计算字符串的长度,则需依赖于'\0',所以arr2对应字符串的长度才不为4。

2.转义字符

转义字符释义
\’用于表示字符常量 ’
\"用于表示字符串内部的 ”
\\用于表示字符串内部的 \
\a警告字符,蜂鸣
\b退格符
\f进纸符
\n换行符
\r回车
\t水平制表符
\v垂直制表符
\dddddd表示1~3个8进制数字。如 \160 – p
\xdddd表示1~2个16进制数字。如 \x61 – a

转义字符的使用示例,代码如下

#include <stdio.h>
#include <string.h>

#define PRINT(arr) printf(#arr"`s length is %d\n", strlen(arr));

int main()
{
	// 指印字符串的长度
	PRINT("abcdef");
	PRINT("D:\test\628\test.c");
	PRINT("D:\\test\\628\\test.c");
	
	return 0;
}

运行结果:

字符串

字符串"abcdef"中的字符有'a', 'b', 'c', 'd', 'e', 'f',所以它的长度为6
字符串"D:\test\628\test.c"中的字符有'D', ':', '\t', 'e', 's', 't', '\62', '8', '\t', 'e', 's', 't', '.', 'c',所以它的长度为14;
字符串"D:\\test\\628\\test.c"中的字符有'D', ':', '\', 't', 'e', 's', 't', '\', '6', '2', '8', '\', 't', 'e', 's', 't', '.', 'c',所以它的长度为18;

四、选择语句

选择语句可分为:

  • if语句
  • switch诗句

其中if语句可用于单分支,也可用于多分支;switch语句用于多分支。

if语句

if语句示例,代码如下(单分支):

int main()
{
	int input = 0;
	printf("明天要写代码吗?\n");
	printf("请输入你的选择(1 -- 是;0 -- 否):>");
	scanf("%d", &input);
	if (input)
	{
		printf("代码功力+10086\n");
	}
	else
	{
		printf("代码功力-1");
	}
	
	return 0;
}

if语句示例,代码如下(多分支):

int main()
{
	int input = 0;
	printf("你今年多大了?\n");
	printf("请输入你的年龄:>");
	scanf("%d", &input);
	if (input < 18)
	{
		printf("不准谈恋爱\n");
	}
	else if (input > 50)
	{
		printf("变成老登了\n");
	}
	else
	{
		printf("刚满18岁\n");
	}

	return 0;
}

2.switch语句

switch语句,示例代码如下:

int main()
{
	int input = 0;
	printf("今天星期几?\n");
	printf("请输入:>");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		printf("星期一\n");
		break;
	case 2:
		printf("星期二\n");
		break;
	case 3:
		printf("星期三\n");
		break;
	case 4:
		printf("星期四\n");
		break;
	case 5:
		printf("星期五\n");
		break;
	case 6:
		printf("星期六\n");
		break;
	case 7:
		printf("星期天\n");
		break;
	default:
		printf("输入错误\n");
		break;
	}

	return 0;
}

五、循环语句

循环语句可分为:

  • for循环
  • while循环
  • do…while循环

1.for循环

for循环,输出0-9

int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", i);
	}

	return 0;
}

2.while循环

while循环输出0-9

int main()
{
	int i = 0;
	while (i < 10)
	{
		printf("%d\n", i++);
	}

	return 0;
}

3.do…while循环

do…while循环输出0-9

int main()
{
	int i = 0;
	do
	{
		printf("%d\n",i++);
	}while(i < 10);

	return 0;
}

六、函数

将某功能的实现放在函数中,能够简化代码,提高代码复用率。

不使用函数实现两数相加

int main()
{
	int num1 = 5;
	int num2 = 8;
	int sum = 0;
	sum = num1 + num2;
	printf("num1 + num2 == %d\n", sum);

	return 0;
}

使用函数实现两数相加

int Add(int num1, int num2)
{
	return num1 + num2;
}

int main()
{
	int num1 = 5;
	int num2 = 8;
	printf("num1 + num2 == %d\n", Add(num1, num2));

	return 0;
}

七、数组

数组是一组类型相同元素的集合

1.数组的定义

定义数组的示例

int array[] = { 1,2,3,4,5,6,7,8,9,10 }; // 定义一个整型数组,最多能够存放10个int类型的元素
char arr[] = { 'a', 'b', 'c', '\0' }; // 定义一个字符数组,最多能够存放4个char类型的元素

2.数组的下标

数组中每个元素都有一个下标,数组的下标是从0开始,依次递增。能够通过下标对数组中的元素进行访问。

定义一个int[10]类型的数组

int array[10] = { 1 }; // 不完全初始化,首元素为1,其余全初始化为0

数组下标

3.数组的使用

打印数组中的所有元素

int main()
{
	int array[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", array[i]);
	}

	return 0;
}

八、操作符

操作符可分为

  • 算术操作符
  • 移位操作符
  • 位操作符
  • 赋值操作符
  • 单目操作符
  • 关系操作符
  • 逻辑操作符
  • 条件操作符
  • 逗号表达式
  • 下标引用、函数调用和结构成员

1.算术操作符

+ // 相加
- // 相减
* // 相乘
/ // 相除
% // 取模

2.移位操作符

对二进制位进行操作

>> // 右移
<< // 左移

3.位操作符

对二进制位进行操作

& // 与
| // 或
^ // 异或

4.赋值操作符

= // 赋值
+= // sum += 2 等价于 sum = sum + 2
-= // sum -= 2 等价于 sum = sum - 2
*= // sum *= 2 等价于 sum = sum * 2
/= // sum /= 2 等价于 sum = sum / 2
&= // sum &= 2 等价于 sum = sum & 2
|= // sum |= 2 等价于 sum = sum | 2
>>= // sum >>= 2 等价于 sum = sum >> 2
<<= // sum <<= 2 等价于 sum = sum << 2

5.单目操作符

! // 逻辑反操作
- // 负值
+ // 正值
& // 取地址 
sizeof // 操作数的类型长度(字节为单位)
~ // 对一个数二进制出取反
-- // 自减
++ // 自增
* // 间接访问操作符(解引用操作符)
(类型) // 强制类型转换

6.关系操作符

> 
>=
<
<=
!= // 不相等
== // 相等

7.逻辑操作符

&& // 逻辑与
|| // 逻辑或

8.条件操作符

exp1?exp2:exp3 // exp1为真,执行exp2,否则执行exp3

9.逗号表达式

exp1,exp2,.......,expN // 该表达式的结果为expN

10.下标引用、函数调用和结构成员

[] // 下标
() // 函数调用
. // 使用结构中的成员属性
-> // 使用结构中的指针成员

九、常见关键字

  • 关键字是由c语言提供的,用户不能自己定义关键字;
  • 关键字不能作为变量名;
auto // 用于局部变量,在它的作用域中自动创建,自动销毁,很少用到。
break
continue
case
default
const 
do
double
float
int 
char
long  
short
void
if
else
switch
for
while
goto
enum
signed
unsigned
sizeof
static
struct
typedef
union
extern
volatile
register

1.typedef

类型重命名

// 将unsigned int类型重命名为u_int
typedef unsigned int u_int;
// a和b的类型相同
unsigned int a = 1;
u_int b = 1; 

2.static

c语言中,static可以用于修饰

  • 局部变量 – 静态局部变量
  • 全局变量 – 静态全局变量
  • 函数 – 静态全局函数

2.1 修饰局部变量

static用于修饰局部变量时,会改变该局部变量的生命周期,使得该变量在离开了作用域仍能存在,直到程序结束才销毁。

验证static修饰局部变量时,会改变它的生命周期

int test()
{
	int i = 0;
	return i++;
}

int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", test());
	}

	return 0;
}

局部变量

int test()
{
	static int i = 0;
	return i++;
}

int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", test());
	}

	return 0;
}

静态局部变量
通过对比,可以看到,for循环输出的test()函数中的i的值,是从0一直输出到9,说明静态局部变量i,并没有像普通局部变量一样,它在离开test()函数时没有被销毁。

2.2修饰全局变量

使用static修饰全局变量时,会改变它的作用域,使得它只能在定义它的文件下使用。对其它文件是不可见的。

验证static修饰的全局变量的作用域发生了改变。

test.h

int global = 100

testt.c

#include "test.h"

extern int global;

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

运行结果:
静态全局变量

testt.c

static int global = 100

test.c

#include "test.h"

extern int global;

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

出现编译错误
静态全局变量
可以看出,testt.c中的全局变量global在用static修饰之后,test.c中找不到global变量。static改变了它的作用域。

2.3修饰函数

static修饰函数与它修饰全局变量的作用相同,都是改变了它的作用域,仅对定义它的文件可见,其它文件不可见。

testt.c

int Add(int num1, int num2)
{
	return num1 + num2;
}

test.c

int main()
{
	printf("%d\n", Add(3,5));

	return 0;
}

运行结果:
静态函数

testt.c

static int Add(int num1, int num2)
{
	return num1 + num2;
}

test.c

int main()
{
	printf("%d\n", Add(3,5));

	return 0;
}

出现编译错误
静态函数

从上述结果对比得知,static修饰函数时,确实改变了它的作用域。使得其只能在定义它的文件中使用。

十、#define定义常量和宏

#define使用示例

// #define定义一个名为MAX的标识符常量
#define MAX 100
// #defien定义一个宏,实现+法运算
#define ADD(num1, num2) ((num1) + (num2))

int main()
{
	printf("MAX == %d\n", MAX);
	printf("MAX + 3 == %d\n", ADD(MAX, 3));

	return 0;
}

运行结果:
#define的使用

十一、指针

1.内存

内存是计算机中特别重要的存储器,计算机中的程序都是运行在内存中的进行的。
为了能够有效的使用内存,就把内存分成一个个小的内存单元,每个内存单元为一个字节
为了能够访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址
在这里插入图片描述
创建变量时使用的空间就是内存空间,所以每个变量都是有内存地址的

验证每个变量都有地址

int main()
{
	int num = 100;
	printf("num`s address is 0x%p\n", &num); // 32位机器,8位16进制数表示;64位机器,16位16进制数表示;

	return 0;
}

运行结果:
地址
num的内存
而指针变量则是用来保存地址的。并且可以使用该指针来修改它指向变量的值。

用指针变量p来接收num的地址,并修改它的值

int main()
{
	int num = 100;
	int* p = &num;
	printf("num`s address is 0x%p\n", &num);
	printf("p is 0x%p\n", p);
	
	printf("\nnum == %d\n", num);
	*p = 200;
	printf("num == %d\n", num);

	return 0;
}

运行结果:

指针的使用
指针

2.指针变量的大小

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

验证代码

// 32位
#define PRINT(type) printf("sizeof "#type"`s address == %d\n", sizeof(type*))

int main()
{
	PRINT(char);
	PRINT(short);
	PRINT(int);
	PRINT(double);

	return 0;
}

运行结果:
指针变量的大小

// 64位
#define PRINT(type) printf("sizeof "#type"`s address == %d\n", sizeof(type*))

int main()
{
	PRINT(char);
	PRINT(short);
	PRINT(int);
	PRINT(double);

	return 0;
}

运行结果:
在这里插入图片描述

十二、结构体

在解决现实生活遇到的问题时,可能会出现无法通过c语言已有的数据类型来表述,需要使用用户自定义的复杂数据类型来描述的情况。结构体让c语言有能力描述复杂类型。

比如,现在要描述一个人,包括名字、性别、年龄、身份证号 这几项信息
就只能用结构体来描述

// 定义结构体
typedef struct
{
	char name[20];
	char sex[3]; 
	int age;
	char ID[18];
}Peoinfo;

int main()
{
	// 结构体的初始化
	Peoinfo p = { "Zhangsan", "1", 22, "123456" };

	// . 为结构体成员访问操作符
	printf("name is %s, sex is %s, age is %d, ID is %s\n", p.name, p.sex, p.age, p.ID);
	// -> 操作符
	Peoinfo* pf = &p;
	printf("name is %s, sex is %s, age is %d, ID is %s\n", pf->name, pf->sex, pf->age, pf->ID);

	return 0;
}

运行结果:

结构体


总结

本文对c语言中将要学到的内容进行了简单的梳理,接下来的文章将对思维导图中的各个部分进行详细介绍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值