初识C语言

前言:由于太久没有学习计算机这块的内容,决定从最基础的开始复习,首先复习的是C语言。首先,目标:基本了解C语言的基础知识,对C语言有一个大概的认识。
每个知识点就是简单认识,不做详细讲解,后期我都会细讲。

一、什么是C语言?

C语言是一门通用计算机编程语言,广泛应用于底层(操作系统及以下)开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

电脑(硬件),驱动层(作用:把操作系统和硬件结合起来,就是操作系统调用驱动程序驱动硬件工作),装有操作系统(Windows,Linux,Mac),这些属于底层。装有应用程序(QQ、百度网盘),属于上层。

计算机语言的发展:
低级-------> 高级
早期用不太方便的二进制写代码(机器语言)-----> 其中有一些二进制序列可能代表特殊的意义,于是给某些二进制序列取名字(比如:ADD、SUB、MOV、Jump,这些叫助记符),由助记符表示的语言叫做汇编语言-----> B语言 -----> C语言(高级语言)

标准:
二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。 [1] 目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。
最常用的是C98。
C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。

二、 第一个C语言程序

1.VS2019-----集成开发环境-----IDE
2.打开VS,新建项目,选择空项目,配置新项目;
3.写代码:
1)新建.c文件—源文件
2)在解决方案资源管理器找到源文件,右击,选择添加、新建项,再选择c++文件,把名称“源.cpp”改为类似于这样“test.c”的xxx.c文件,因为只有.c为后缀的才是c的代码。
3)写代码

//使用printf函数需要引用头文件--->#include <stdio.h>
#include <stdio.h>
//
//main函数,主函数
//main函数是程序的入口,有且仅有一个
// 
//Fn +F10 逐过程
// 
// 如果想在屏幕上打印数据,可以使用printf库函数
// printf是一个C语言编译器提供的库函数
// 库函数的使用要包含头文件,printf函数需要的头文件是stdio.h
// 
//int main()
//{
//	printf("hello bit\n");
//	printf("hello bit\n");
//	printf("hello bit\n");
//	printf("hello bit\n");
//	printf("hello bit\n");
//
//	return 0;
//}
//int是整型,与return 0返回的值相对应
//{} 是函数体,函数名+(),()这个代表是函数

标准写法---推荐
//int main()
//{
//	return 0;
//}

 C语言中有一个约定:
返回0表示正常返回
返回的是非零,表示异常返回

//
古老的写法---不推荐
//void main()
//{
//
//}
//
不规范的写法---不推荐
//main()
//{
//
//}


4)运行代码
编译+链接+运行
快捷键 :Ctrl+F5
没有反应的话就用Ctrl + Fn+F5或者 点击上方工具栏“调试”,选择“开始执行不调式”。
5)调试代码
按住Ctrl + Fn +F10
没有反应的话试试Fn +F10

三、数据类型

为什么写代码?
用来解决生活中的问题

计算机在处理数据的时候,处理的二进制数据:
以下是计算机常用存储计量单位
bit 位(计算机最小存储计量单位) Byte 字节(计算机最基本存储计量单位)
1 Byte = 8 bit
1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
1 PB =1024 TB

char        //字符数据类型
short       //短整型
int         //整形
long        //长整型
long long   //更长的整形
float       //单精度浮点数
double      //双精度浮点数
  • 为什么出现这么多的类型?
    类型丰富,选择就会更多,就能灵活地使用恰当的类型,内存的利用率更高
#include <stdio.h>
int main()
{
short age = 20;
double salary = 10000.5;
return 0;
}
  • 每种类型的大小是多少?
#include <stdio.h>
int main()
{
	//%d - 这个格式表示打印一个10进制的整数
	//“sizeof”计算大小的操作符,计算结果的单位是:字节 byte
	printf("%d\n", sizeof(char));//1
	printf("%d\n", sizeof(short));//2
	printf("%d\n", sizeof(int));//4
	printf("%d\n", sizeof(long));//4
	//这里的sizeof(long)>=sizeof(int) 即可
	printf("%d\n", sizeof(long long));//8
	printf("%d\n", sizeof(float));//4
	printf("%d\n", sizeof(double));//8
	return 0;
}
  • C语言有没有字符串类型?
    没有,c语言没有String 类型,c语言中字符串是通过字符指针来间接实现的。

四、变量、常量

生活中的有些值是不变的(比如:圆周率,性别,身份证号码,血型,π等等)
有些值是可变的(比如:年龄,体重,薪资)。
不变的值, C语言中用常量的概念来表示,变的值C语言中用变量来表示。

4.1定义变量的方法

int main()
{
	//类型 + 变量名,再赋值
	int age = 150;
	float weight = 45.5f;
	char ch = 'w';
	45.5;//编译器默认以为是double类型的,如果你希望是float类型的,应该写成45.4f
	return 0;
}

4.2 变量的命名

  • 只能由字母(包括大写和小写)、数字和下划线( _ )组成。
  • 不能以数字开头。
  • 长度不能超过63个字符。
  • 变量名中区分大小写的。
  • 变量名不能使用关键字(比如 int ,short 这样的)。

4.3 变量的分类

  • 局部变量:定义在大括号内部的是局部变量
  • 全局变量:定义在大括号外部的是全局变量
#include <stdio.h>
int num = 1000;//全局变量
int main()
{
	int num = 10;//局部变量
	printf("%d\n", num);
	//局部变量和全局变量名字冲突的情况下,局部优先
	return 0;
}

4.4 变量的使用

#include <stdio.h>
int main()
{
	int age = 10;
	age = age + 1;
	printf("age = %d\n", age);
	//这里的“age = ”是对打印结果的修饰
	//打印结果:age = 11
	return 0;
}

“.c"和”.cpp"有什么区别?
.c 就是 C语言,按照c的语法解析
.cpp 就是cplusplus c++ 的意思,按照c++的语法解析

可以用 51cto 写博客吗?
可以的,但是活跃度不够
也可以用这个,掘金-字节旗下,高端人群

写一个代码,求两个整数的和

//给变量赋初始值,是一个好习惯
// printf是输出函数
// scanf是输入函数
#include<stdio.h>
int main()
{
	int num1 = 0;
	int num2 = 0;//初始化
	//输入两个整数
	scanf("%d %d", &num1, &num2);
	//相加
	int sum = num1 + num2;
	//输出
	printf("%d\n",sum);
	return 0;
}

scanf是c语言的函数
scanf_s是VS编译器(IDE)提供的,不能跨平台使用
如果要正常使用scanf函数,这句“#define _CRT_SECURE_NO_WARNINGS 1”
一定要加到:整个.c文件的第一行

一劳永逸的方法:
在电脑文件里搜索newc++file.cpp,找到这个文件的路径后用记事本打开,
把这句#define _CRT_SECURE_NO_WARNINGS 1 复制到记事本里面并保存
假如保存不了,把它拖到桌面再复制进去然后就可以ctrl+s保存了,
保存后一定要把它拖回到原来的位置,只有替换掉原来的才行。
这样每次新建.c文件开头都会有这段代码,可以安全地使用scanf函数了

其实有很多函数都是不安全的,这里一scanf函数为例:

#include<stdio.h>
int main()
{
	char arr[5];//字符数组
	scanf("%s", arr);//%s - 字符串格式
	printf("%s\n", arr);
	return 0;
	//scanf这个函数不会去检测数组是否放得下多少个元素,
	// 所以一定程度上他是不安全的
	// 
	//
}

4.5 变量的作用域和生命周期

作用域:

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用
的而限定这个名字的可用性的代码范围就是这个名字的作用域。

#include<stdio.h>
int main()
{
	{
		int a = 100;
		printf("%d\n", a);
	}
	return 0;
}//这里的打印结果是100

int main()
{
	{
		int a = 100;
	}
	printf("%d\n", a);
	return 0;
}//打印不了,错误是未声明的标识符a

1 . 局部变量的作用域是变量所在的局部范围。

2 . 全局变量的作用域是整个工程。

int a = 1000;
void test()
{
	printf("3:a=%d\n", a);
}
int main()
{
	printf("1:a=%d\n", a);
	{
		printf("2:a=%d\n", a);
	}
	test();
	return 0;
}
//打印结果:
//1:a=1000
//2:a=1000
//3:a=1000

另一种写法:
要新建一个.c文件,把int a = 1000;放进去,然后在原来那个文件这样写:

//extern - 声明来自外部其他源文件的符号
extern int a;//有一个符号是int类型的,名字叫a,来自外部
void test()
{
	printf("3:a=%d\n", a);
}
int main()
{
	printf("1:a=%d\n", a);
	{
		printf("2:a=%d\n", a);
	}
	test();
	return 0;
}
//打印结果:
//1:a=1000
//2:a=1000
//3:a=1000

生命周期

变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段

1 . 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。

2 . 全局变量的生命周期是:整个程序的生命周期。

注意:作用域决定了生命周期,作用域是范围,声明周期是时间。

4.6 常量

C语言中的常量和变量的定义的形式有所差异。

C语言中的常量分为以下以下几种:

  • 字面常量
  • const 修饰的常变量
  • #define 定义的标识符常量
  • 枚举常量
    先介绍前面2种:
//std - standard
//i - input 输入
//o - output 输出
#include<stdio.h>//标准输入输出头文件。只要涉及输入输出操作,就包含此头文件
int main()
{
	//1.字面常量
	30;//整型的字面常量
	3.14;//浮点数的字面常量
	"abcdef";//字符串的字面常量
	'a';//字符的字面常量。
	//只要是键盘能敲出来的,在c语言中用单引号引起的就是字符,比如:'1' 'q' '+' ' ',单引号引起的空格叫空白字符

	//2.const 修饰的常变量
	const int num = 100;
	//因为这里的被const修饰的num本质上还是变量,具有常属性(不被改变的属性)
	//num = 200;所以num的值不能被修改
	//printf("%d\n", num);//200

	//怎么证明num是变量?前提条件:支持c99语法
	//数组 - 存放一组数
	/*const int n = 10;
	int arr[n] = {1,2,3,4,5,6,7,8,9,10};*/
	//这种写法会报错:表达式必须含有常量值
	// ->在c99 标准之前,不允许数组的大小使用变量指定
	//int n =10;
	//int arr[n];//err
	// ->c99 标准中,引入了变长数组的概念
	//int n =10;
	//int arr[n];//c99以及之后是ok的
	// 因为VS2019 不支持c99标准中变长数组的概念
	//所以被const修饰的常变量本质是变量
	//拓展一点:我们最常用的语法是:c89 c90 c98
	//c99之后用的语法细节是比较少的
	//语言在不断的演变过程中,它里面会加入一些新的语法特性,
	//变长数组就是在后来的语法里面加进去的
	return 0;
}

接下来介绍后面2种常量:
3.#define 定义的标识符常量

//3.#define 定义的标识符常量
#include<stdio.h>
#define MAX 1000//define定义的一个符号MAX,它的值是1000
int main()
{
	int a = MAX;//把a的值赋值为MAX
	printf("%d\n", a);
	//MAX = 2000;//err  
	//错误原因:表达式必须是可修改的左值->此时的MAX不能被修改,但MAX是常量
	int arr[MAX];//ok   MAX是常量,可以指定数组的大小
	//此时运行成功,没有语法错误,不过有一个警告:未引用的局部变量 ->
	//意思是数组只定义了,并没有使用,但是这样写没有问题,是OK的
	int arr1[MAX] = { 1,2 };//ok
	//如果不想有警告,定义完数组可以使用它进行赋值
	return 0;
}

4.枚举常量

//4.枚举常量
//c语言就支持我们创建枚举类型
//enum - 是枚举的关键字,下面enum后面定义的Sex的意思是性别类型
#include<stdio.h>
//enum Sex
//{
//	//枚举类型中列出的可能取值都是枚举常量
//	MALE,//默认值为0
//	FEMALE,//默认值为1
//	SECRET//默认值为2
//};

//也可以初始化赋另外的值
enum Sex
{
	//枚举类型中列出的可能取值都是枚举常量
	MALE = 4,
	FEMALE = 8,
	SECRET
};
int main()
{
	//枚举 ---- 是把所有的东西一一列举的意思
	//生活中确实有一些值是可以一一列举的,比如:
	// 性别的取值范围:男、女、保密
	// 三原色: R、G、B  ->  红(red)、绿(green)、蓝(blue)
	// 血型······
	enum Sex s = SECRET;
	enum Sex s2 = FEMALE;
	//printf("%d %d %d\n", MALE,FEMALE,SECRET);//0 1 2
	printf("%d %d %d\n", MALE, FEMALE, SECRET);//4 8 9

	//MALE = 3;//err  表达式必须是可修改的左值
	return 0;
}

小总结:

#include <stdio.h>
//const 修饰的常变量是变量,#define 定义的标识符常量是常量,他俩都不可以改变
//枚举常量是常量,可以在枚举类型中改变
//#define MAX 1000
enum Sex
{
	MALE = 3,
	FEMALE = 6,
	SECRET
};
int main()
{
	/*3.14;
	const int a = 10;
	int arr1[MAX] = { 0 };*/
	enum Sex a1 = MALE;
	enum Sex a2 = FEMALE;
	printf("%d %d %d\n", MALE, FEMALE, SECRET);//3 6 7
	return 0;
}

五、字符串+转义字符+注释

5.1 字符串

" hel l o bi t . \n "

这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符
串。

//%d - 打印有符号的整型(比如正十,负十)
//%s - 打印字符串
//%c - 打印字符

//
//计算机中数据的存储、表示都是二进制的
//'a' - 97 
//'b' - 98
// c语言对字符的编码采用ASCII 编码,每一个字母所对应的值叫ASCII码值
// 编码的值可以在调试中的监视窗口看见
//
//“strlen”未定义,需要引用头文件
#include<stdio.h>
#include<string.h>
int main()
{
	char ch = 'a';//把字符a赋值给ch
	//单引号引起来的叫字符
	ch = 'x';
	printf("%c\n", ch);

	//双引号引起的一串字符叫做字符串
	"zhangsan";

	//只要是双引号引起的,包括单字符或者不放字符只有双引号也是字符串
	"a";
	"";
	//  \0  是字符串结束标志
	char arr1[] = "abcdef";
	//按住Fn+f10调试,在监视窗口输入数组名arr就可以看见,数组里的7个元素:
	// a b c d e f \0
	char arr2[] = {'a','b','c','d','e','f'};
	//调试后看见6个元素: a b c d e f 

	printf("%s\n", arr1);//abcdef
	printf("%s\n", arr2);//abcdef烫烫烫烫烫abcdef
	//因为打印字符串如果没有结束标志\0,就会打印随机的乱码

	//想要arr2打印结果为abcdef,可以用此方法:
	char arr3[] = { 'a','b','c','d','e','f','\0'};
	printf("%s\n", arr3);//abcdef

	printf("%d\n", strlen("abc"));//3
	printf("%d\n", strlen(arr1));//6
	printf("%d\n", strlen(arr2));//22  随机数
	printf("%d\n", strlen("abc\0def"));//3


	//strelen是一个库函数,是 string strlen 的缩写,是用来求字符串长度的 
	//统计的是字符串中\0之前出现多少个字符

	return 0;
}

注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串
内容。

5.2 strelen和sizeof的区别

推荐这篇文章,写的挺好的
http://t.csdn.cn/V7fCk
在这个搜索框输入才找得到
在这里插入图片描述

5.3 转义字符

假如我们要在屏幕上打印一个目录: c : \code\test . c
我们该如何写代码?

#include<stdio.h>
int main()
{
	printf("c:\test\code\test.c");
    //实际上程序运行的结果是这样的:
	//c:      estcode est.c
	return 0;
}

这里就不得不提一下转义字符了。转义字符顾名思义就是转变意思。
下面看一些转义字符。

  • ? 在书写连续多个问号时使用,防止他们被解析成三字母词

  • ’ 用于表示字符常量’

  • \“ 用于表示一个字符串内部的双引号

  • \ 用于表示一个反斜杠,防止它被解释为一个转义序列符。

  • \a 警告字符,蜂鸣

  • \b 退格符

  • \f 进纸符

  • \n 换行

  • \r 回车

  • \t 水平制表符

  • \v 垂直制表符

  • \ddd ddd表示1 ~3个八进制的数字。 如: \1 30 X

  • \xdd dd表示1~2个十六进制数字。 如: \x30 0

#include<stdio.h>
int main()
{
	//printf("abcndef");
	//printf("abc\ndef");
	//abcndefabc
	//def
	
	//printf("c:\test\code\test.c");
	//实际上程序运行的结果是这样的:
	//c:      estcode est.c


	//转义字符
	//\?  -  在书写连续多个问号时使用,防止他们被解析成三字母词
	//三字母词: 只要是 ?? 随便连接另一个符号,都会被打印成   ]  。比如: 
	//在一些早期的编译器里面会把   ??)   打印成  ]
	//printf("%s\n","(are you ok\?\?)");//(are you ok??)
	//printf("%s\n", "(are you ok??)");//(are you ok??)

	// \' 用于表示字符常量'
	//printf("%c\n",'\'');//'
	//printf("%s\n","'");//'

	//\\ 用于表示一个反斜杠,防止它被解释为一个转义序列符。
	//printf("c:\\test\\code\\test.c");//c:\test\code\test.c

	//\a 警告字符,蜂鸣
	//printf("\a\a\a");//触发电脑报警机制,就是嘟的一声

	// \t 水平制表符,是按住电脑键盘 Tab 键产生的效果
	//printf("ab\tcd");//ab      cd


	// \ddd ddd表示1 ~3个八进制的数字。 如: \1 30 X
	printf("%c\n", '\130');//X
	//为什么打印结果是X:八进制130转化为十进制是88,88对应的ASCII码值是X

	//\xdd dd表示1~2个十六进制数字。 如: \x30 0
	printf("%c\n", '\x30');//0
    //为什么打印结果是0:十六进制30转化为十进制是48,48对应的ASCII码值是0
	printf("%c\n", '\x3a');
	//:(冒号)3*16+10=58对应的ASCII码值为:

	printf("%d\n", strlen("c:\test\628\test.c"));//14
	return 0;
}

5.4注释

1 . 代码中有不需要的代码可以直接删除,也可以注释掉

2 . 代码中有些代码比较难懂,可以加一下注释文字

#include<stdio.h>
int main()
{
	//下面是创建一个整型变量并赋值10
	//int a = 10;
	//这种//在C++里面有,所以是C++注释风格
	//在C99标准中也引入到C语言里了

	/*
	int b =30; 
	int c = 60;
	printf("hehe\n");
	*/
	//    /**/ 是C语言的注释风格,缺点是不支持嵌套注释
	return 0;
}

六、选择语句

如果你好好学习,校招时拿一个好offer,走上人生巅峰。
如果你不学习,毕业等于失业,回家卖红薯。
这就是选择!
这里只是简单介绍:

#include<stdio.h>
int main()
{
	int input = 0;
	printf("加入比特好好学习\n");
	printf("你要好好学习吗?(1/0)\n");
	scanf("%d",&input);//&input的意思是提供一个地址,把你输入的值放到这个空间里
	if (input == 1)
		printf("好offer\n");
	else
		printf("卖红薯\n");
	return 0;
}

七、循环语句

有些事必须一直做,比如我日复一日的听课,比如大家,日复一日的学习。
这里只是简单讲一下while循环:

#include<stdio.h>
int main()
{
	int line = 0;
	printf("加入比特\n");
	while (line < 20000)
	{
		printf("写代码:%d\n",line);
		line++;
	}
	if (line == 20000)
		printf("好offer\n");
	return 0;
}

八、函数

这里简单讲,函数的特点就是简化代码,代码复用。

#include<stdio.h>
int Add(int x,int y)
{
	/*int z = 0;
	z = x + y;
	return z;*/   //ok
	return (x + y);// ok  这样写简洁一点
}
int main()
{
	int num1 = 0;
	int num2 = 0;
	int sum = 0;
	scanf("%d %d", &num1,&num2);
	//求和
	//sum = num1 + num2;
	//用函数求和
	sum = Add(num1, num2);
	int sum1 = Add(2, 3);
	int sum2 = Add(5, 5);

	printf("%d\n", sum);//输入一个数,然后空格,再输入另一个,再回车得相加的结果
	printf("%d\n", sum1);//5
	printf("%d\n", sum2);//10

	return 0;
}
//这里的Add是函数名,int x 和 int y是形式参数
// Add 前面的 int 是函数结果的返回类型
// 下面的 {} 叫函数体

九、数组

9.1 数组定义

c语言中给了数组的定义:一组相同类型元素的集合

#include<stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	//假如要存1~10个数字,难道要创建10个变量吗?
	//存放一组相同类型的数据 - 数组
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//定义一个整形数组,最多放10个元素

	//写一个数组可以放5个字符
	char ch[5] = {0};//不完全初始化,剩余的默认会初始化为0

	//没有规定大小的数组要根据后面初始化的内容决定
	char ch1[] = {'a','b','c'};//存放了3个元素, ok
	char ch2[] = {0};//存放了1个元素, ok

	return 0;
}

9.2数组的下标

C语言规定:数组的每个元素都有一个下标,下标是从0开始的。
数组可以通过下标来访问的。

//数组的下标
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//如果数组存放10个元素,那么下标范围是0~9
	printf("%d\n", arr[8]);//9
	//printf("%d\n", arr[18]);//err  越界访问
	char ch3[] = "abcd";
	//每一个字符存的都是对应的ASCII码值

9.3数组的使用

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	//下标为0~9
	//输入10个值给数组
	int i = 0;
	while (i < 10)
	{
		scanf("%d", &arr[i]);
		i++;
	}
	//输出数组中的10个值
	i = 0;
	while (i < 10)
	{
		printf("%d ", arr[i]);
		i++;
	}
	return 0;
}

十、操作符

简单介绍为主

10.1 算术操作符:

+ - * / %
//加减乘较为简单,后面两种讲一下

//#include<stdio.h>
//int main()
//{
//	//	/(除号)两端的操作数如果都是整数,执行的是整数除法,
//	//至少有一个操作数是浮点数执行的才是浮点数的除法
//	int a = 7 / 2;
//	printf("%d\n", a);//3
//
//	float f = 7 / 2;
//	printf("%f\n", f);//3.000000
//
//	float f1 = 7.0 / 2;
//	float f2 = 7 / 2.0;
//	float f3 = 7.0 / 2.0;
//	printf("%f\n", f1);//3.500000
//	printf("%f\n", f2);//3.500000
//	printf("%f\n", f3);//3.500000
//	return 0;
//}

#include<stdio.h>
int main()
{
	//	%(取模操作符),关注的是整除后的余数
	//取模操作符的两个操作数必须是整数
	//假如模负数,建议看看B站 蛋哥:c语言深度解剖
	int a = 7 % 2;
	printf("%d\n", a);//打印结果是 1
	//商3 ,余1
	//如果余数模n,它的余数的范围是0~n-1
	return 0;
}

10.2 移位操作符

//移位操作符:<<	>>
//整数可以写成二进制,当整数转化为二进制时,可以把整数的二进制位向左或向右移动

10.3 位操作符

//位操作符:&	^	|
//对一个数的二进制位进行相关运算
//按位与&,运算规则:只有两个数的二进制同时为1,结果才为1,否则为0。(负数按补码形式参加按位与运算)
//按位或|,运算规则:参加运算的两个数只要两个数中的一个为1,结果就为1。
//按位异或^,运算规则:参加运算的两个数,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。

10.4 赋值操作符

赋值操作符:= += -= *= /= &= ^= |= >>= <<=

#include<stdio.h>
int main()
{
	int a = 10;//创建变量,并初始化
	a = 20;//赋值

	//复合赋值操作符:+= -= *= /= &= ^=   |=    >>=   <<=
	// +=
	a = a + 5;
	a += 5;//上面两种写法是一种意思

	//以此类推,……
	a = a * 5;
	a *= 5;
	
	return 0;
}
	

10.5 单目操作符

单目操作符:有一个操作数

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

& 和 * 暂时先不讲,~:对一个数的二进制按位取反,这个先不讲,后面讲。

双目操作符:

//	2	   +	3
//左操作数 + 右操作数
//有两个操作数的操作符叫双目操作符

这里主要介绍单目操作符:

10.5.1 ! 逻辑反操作

//c语言是如何表示真假的呢?
//0表示假,非零表示真,意思是只有零才表示假
//例如:-1 表示真
#include<stdio.h>
int main()
{
	// ! 逻辑反操作:真变为假,假变为真
	int a = 10;
	if (a)
		printf("hehe\n");//打印结果:hehe

	if (!a)
		printf("haha\n");//没有打印,因为a为真,!a为假,if语句的判断条件为真才执行

	if (!!a)
		printf("haha\n");//haha

	int b = 0;
	if (!b)
		printf("haha\n");//haha


	return 0;
}

10.5.2 - 负值 + 正值

#include<stdio.h>
int main()
{
	int a = 10;
	printf("%d\n", +a);//10
	printf("%d\n", -a);//-10

	int b = -10;
	printf("%d\n", +b);//-10
	printf("%d\n", -b);//10
	//正号没怎么用,一般不写
	return 0;
}

10.5.3 sizeof 操作数的类型长度(以字节为单位)

# include <stdio.h>
int main()
{
	int a = 10;
	char ch = 'w';
	int arr[10] = { 0 };
	//变量的创建都要向内存申请空间
	
	printf("%d\n", sizeof a );//4
	printf("%d\n", sizeof(int));//4
	printf("%d\n", sizeof ch );//1
	printf("%d\n", sizeof(char));//1
	//sizeof后面括号里面是变量名称可以不加括号,但是后面是类型必须加括号
	//sizeof是一个操作符,不是函数!!!	因为调用函数时后面的括号不能省略
	printf("%d\n", sizeof(arr));//40  单位是字节,这里的40是数组总的大小

	//数组的元素的个数如何计算?
	int sz = sizeof arr / sizeof arr[0];//用总的数组大小除以每个元素的大小
	printf("%d\n", sz);//10
	return 0;
}

10.5.4 strlen 和sizeof 的区别(简略)

//strlen 是库函数,只能针对字符串,求字符串长度,计算的是字符串中\0之前的字符串个数
//sizeof 是操作符,是计算所占内存空间的大小,不论里面存放的内容是什么,包括\0

10.5.5 前置、后置- -,前置、后置+ +

#include<stdio.h>
int main()
{
	//int a = 10;
	//int b = ++a;//前置++,先++,后使用
	a = a+1 , b = a;
	//printf("a = %d b = %d ", a, b);//a = 11 b = 11

	//int a = 10;
	//int b = a++;//后置++,先使用,后++
	b = a ; a = a + 1;
	//printf("a = %d b = %d ", a, b);//a = 11 b = 10

	//int a = 10;
	//int b = --a;//前置--,先--,后使用
	a = a -1, b = a;
	//printf("a = %d b = %d ", a, b);//a = 9 b = 9

	//int a = 10;
	//int b = a--;//后置--,先使用,后--
	b = a , a = a - 1;
	//printf("a = %d b = %d ", a, b);//a = 9 b = 10

	//int a = 10;
	//printf("a = %d\n", a--);//先使用,后--   a = 10
	//printf("a = %d\n", a);//a = 9

	int a = 10;
	printf("a = %d\n", --a);//先--,后使用   a = 9
	printf("a = %d\n", a);//a = 9
	return 0;
}

#include <stdio.h>
int main()
{
	int a = 1;
	int b = (++a) + (++a) + (++a);
	printf("%d\n", b);//12
	//把这段代码拿到Linux服务器上的gcc编译器上测试,结果是10
	//同一段代码在不同的编译器上算出的结果是不同的,说明这一段代码是问题代码
	//如果有人写出这种超复杂的表达式让你去计算,不要管他,这是错误的代码,没价值
	//在公司里面是不允许写出这样的代码的
	return 0;
}

10.5.6 (类型) 强制类型转换

#include <stdio.h>
int main()
{
	//int a = 3.14;
	//warning C4244: “初始化”: 从“double”转换到“int”,可能丢失数据
	//警告的意思: 
	//3.14编译器会认为是double (占8个字节)类型,而a的类型是int(占4 个字节) ,
	//把3.14赋值给a会丢失精度(内存不够)
	//怎么解决这个问题?
	int a = (int)3.14;
	//强制类型转换,把double类型强制转换成int 类型,只取整型部分
	printf("%d\n", a);//3
	return 0;
}

10.6关系操作符

>
>=
<
<=
! =   用于测试“不相等”
==      用于测试“相等”
#include<stdio.h>
int main()
{
	两个等号 == 判断相等
	一个等号 = 赋值
	//int a = 3;
	//int b = 5;
	//int c = 3;
	//if (a != 5)
	//{
	//	printf("hehe\n");//hehe
	//}
	//if (a == c)
	//{
	//	printf("hahaha\n");//hahaha
	//}
 //   if (a == b)
	//{
	//	printf("hhhhh\n");
	//}


	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	//两个字符串是不能使用 == 来判断相等的,使用strcmp
	//基本上只有整型,char类型的可以用==判断相等
	if (arr1 == arr2)
	{
		printf("==\n");
	}
	else
	{
		printf("!=\n");
	}
	//打印结果:!=

	return 0;
}
//使用strcmp来比较字符串大小
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	if (strcmp(arr1, arr2) == 0)
	{
		printf("==\n");
	}
	else
	{
		printf("!=\n");
	}
	//打印结果:==
	return 0;
}
//不是所有的两个数据都可以用==来比较相等

10.7 逻辑操作符

&&     逻辑与

||     逻辑或

逻辑操作符,关注的是真假

#include <stdio.h>
int main()
{
	//&&	逻辑与		并且的意思
	int a = 3;
	int b = 5;
	if (a && b)//a和b都不为零,并且a和b同时为真
	{
		printf("hehe\n");//hehe
	}
	int c = a && b;
	printf("%d\n", c);//1
	//因为a和b都同时为真,整体为真,所以c的值为1。
	//规定逻辑操作符如果计算的结果为真的话,它的值就是1;为假的话,它的值为零。

	int a1 = 0;
	int b1 = 5;
	int c1 = a1 && b1;
	if (a1 && b1)//有一个为假,条件为假
	{
		printf("hehe\n");//不打印
	}
	printf("%d\n", c1);//0
	return 0;
}
#include<stdio.h>
int main()
{
	//||	逻辑或		或者的意思
	int a = 0;
	int b = 5;
	int c = a || b;
	if (a || b)//有一个为真条件为真
	{
		printf("hehe\n");//hehe
	}
	printf("%d\n", c);//1

	int a1 = 0;
	int b1 = 0;
	int c1 = a1 || b1;
	if (a1 || b1)
	{
		printf("hehe\n");//不打印
	}
	printf("%d\n", c1);//0
	return 0;
}

10.8条件操作符

exp1 ? exp2 : exp3

//条件操作符(三目操作符)
#include<stdio.h>
int main()
{
	int a = 10;
	int b = 0;
	//if (a > 5)
	//	b = 3;
	//else
	//	b = -3;
	//printf(" b = %d\n", b);// b = 3

	//同义转换
	//(a > 5) ? (b = 3) : (b = -3);//这样写有点麻烦,还有一种写法
	b = (a > 5 ? 3 : -3);
	printf(" b = %d\n", b);// b = 3

	return 0;
}

10.9逗号表达式:用逗号隔开的表达式

exp1, exp2, exp3, …expN

//逗号表达式的特点:从左向右依次计算,整个表达式的结果是最后一个表达式的结果
#include<stdio.h>
int main()
{
	int a = 3;
	int b = 5;
	int c = 0;
	int d = (a += 2, b = b - c + a, c = a + b);
	//       a=3+2=5  b=5-0+5=10    c=5+10=15
	//这里 d 的值就是最后一个表达式 c 的值
	printf("%d\n", d);//15
	printf("%d %d %d\n", a,b,c);//5 10 15
	return 0;
}

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

[] () . ->

10.10.1.下标引用操作符

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };//下标0~9
	//这里的[]是定义数组时指定数组大小的一种写法
	arr[4] = 5;//给第五个元素赋值5
	//这里的[]叫做下标引用操作符,arr 和 4 是[] 的两个操作数
	return 0;
}

10.10.2.函数调用操作符

#include<stdio.h>
int add(int x, int y)
{
	return x + y;
}
int main()
{
	int c = add(2, 3);//这里的()是函数调用操作符,操作数是:add,2,3
	printf("c=%d\n", c);//5
	return 0;
}

11. 常见关键字

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
//1.关键字是直接使用的,我们得了解
//2.变量名不能是关键字

C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。
注:关键字,先介绍下面几个,后期遇到讲解。

//auto  自动-创建自动变量
//局部变量都是自动创建,自动销毁的,所以局部变量都是 auto 修饰的
#include<stdio.h>
int main()
{
	auto int a = 10;
	//所有的局部变量都是auto类型,所以auto可以省略掉

	//break在switch、循环里面使用
	//case里面也用到switch、break
	//default也是在switch语句里面用的,默认的意思
	// 
	//char、short、int、long、long long、float、double数据类型都是关键字
	//const 具有常属性,用来修饰变量、指针
	//continue 用于循环
	//do while
	//自定义类型,枚举enum
	//extern  声明外部符号
	//register   寄存器关键字,寄存器是电脑里面的存储设备
	//return  函数的返回
	//singed	有符号的
	//unsigned	无符号的
	//sizeof	是一个操作符
	//static	静态的,用来修饰变量的
	//struct	结构体,属于自定义类型
	//typedef	类型重定义
	//union		联合体-共用体
	//void		空(无)类型
	//
	return 0;
}

11.1.这里讲一下寄存器(数据存储):

数据在计算机上可以存放在哪里呢?
内存、硬盘、高速缓存、寄存器。
存储空间由小到大,速度由快到慢依次为:寄存器(Byte)、高数缓存(M)、内存、硬盘。
CPU 中央处理器<=>寄存器<-高数缓存<-内存<-硬盘。

硬盘:可以直接看到,划分为C盘、D盘等
在这里插入图片描述

内存:打开任务管理器就可以看软件所占内存
在这里插入图片描述

#include<stdio.h>
int main()
{
	//建议把10放在寄存器中,这样速度会更快
	//但是到底放进去没有取决于编辑器,register只是起建议作用
	//现在的编译器比较聪明,它认为有必要把a放到寄存器里面就会放
	register int a = 10;
	return 0;
}

11.2.关键字 typedef

#include<stdio.h>
typedef unsigned int uint;
int main()
{
	//typedef - 类型重定义
	//作用:把复杂的类型简化
	unsigned int num1;//无符号整型
	uint num2;//这里num1和num2是一样的类型
	return 0;
}

11.3. 关键字static

在C语言中:
static是用来修饰变量和函数的

  1. 修饰局部变量-称为静态局部变量
  2. 修饰全局变量-称为静态全局变量
  3. 修饰函数-称为静态函数
11.3.1 修饰局部变量
//static修饰局部变量->静态局部变量
#include<stdio.h>
void test()
{
	static int a = 3;//这句代码没有汇编语言
	a++;
	printf("%d ", a);
}
int main()
{
	
	int i = 0;
	while (i < 10)
	{
		test();
		i++;
	}
	return 0;
}
//不加static,打印结果:4 4 4 4 4 4 4 4 4 4
//加上static,打印结果:4 5 6 7 8 9 10 11 12 13
//Fn+F10调式,Fn+F11进入函数调试
//int a = 3;栈区上创建的变量都是临时变量,进入作用域创建,出作用域销毁
//static int a = 3;一个变量被static修饰,他在静态区域里面创建,
// 静态区里面创建的变量进入作用域范围创建,出作用域不销毁 ,生命周期比较长

总结:
static修饰局部变量改变了变量的生命周期
让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。

关于内存区域额外小知识:

内存区域有:栈区、堆区、静态区
栈区:局部变量、函数的形式参数
堆区:这些函数:malloc\calloc\realloc\free涉及的内存开辟都是在堆区里面进行的
静态区:全局变量、静态变量

普通的局部变量的特点:
普通的局部变量是放在内存的栈区上的,进入局部范围,变量创建,
出了局部范围变量销毁。
当static修饰局部变量的时候,局部变量是在静态区开辟空间的,
这时的局部变量出了作用域不销毁,下次进去作用域,使用的是上一次遗留的数据。
(改变了存储位置,由栈区->静态区,使得变量的生命周期发生了变化)

11.3.2 修饰全局变量
#include<stdio.h>
extern int g_val;
int main()
{
	printf("%d\n", g_val);
	return 0;
}//2022
//一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使
用。
#define _CRT_SECURE_NO_WARNINGS 1
//创建一个全局变量
int g_val = 2022;
//static int g_val = 2022;
//这里加了static就会出错

全局变量是具有外部链接属性的,如果全局变量被static修饰,
这个外部链接属性就变成了内部链接属性,(变成内部属性就只有自己这个文件能看到,其他地方看不到),其他源文件就没有办法再通过链接找到这个符号
补充:static修饰的全局变量只能在自己所在的.c文件内部使用

11.3.3修饰函数
#include<stdio.h>
//声明外部符号,简洁一点写,只要交代清楚类型和名称就可以
extern int add(int, int);
//extern int add(int x, int y);
int main()
{
	int a = 3;
	int b = 5;
	int c = add(a, b);
	printf("%d\n", c);
	return 0;
}
//函数是具有外部链接属性的,其他源文件想使用函数,正确的声明就可以
//但是函数被static修饰,外部链接属性就变为了内部链接属性,
//这个时候函数只能在自己所在的.c文件内部使用,不能在外部使用。
#define _CRT_SECURE_NO_WARNINGS 1
int add(int x, int y)
{
	return x + y;
}
//static int add(int x, int y)加了static会出错

一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。

链接属性补充:

链接属性有三种:
外部链接属性:所有文件都能通过链接的方式找得到
内部链接属性:被static修饰之后只能在自己所在的源文件内部使用,不能在外部使用。
无链接属性:局部变量是无链接属性的

区别: static修饰局部变量时改变存储区域,其他都是改变链接属性(起隔离作用)

12. #define 定义常量和宏

#define是一个预处理指令

12.1.定义常量

#include<stdio.h>
#define MAX 10
#define str  "abcdef"
int main()
{
	printf("%d\n", MAX);//10
	int a = MAX;
	int arr[MAX]={0};
	printf("%d\n", a);//10
	printf("%s\n", str);//abcdef
	return 0;
}

12.2.定义宏

宏是通过#define来定义的,宏的名字一般全部大写
宏的名字 + 参数(不需要写类型) + 宏体(宏的内容)

//定义函数,传参
int add(int x, int y)
{
	return x + y;
}
#include<stdio.h>
//定义宏,参数替换
#define ADD(x,y) ((x)+(y))//实现两个数相加
//((x)+(y))为什么宏体这里单独加括号?答:保持整体
#define MAX(x,y) ((x)>(y)?(x):(y))//比较两个数的大小
int main()
{
	int a = 10;
	int b = 20;
	int c = add(a, b);
	int c1 = ADD(a, b);
	int c2 = MAX(a, b);
	printf("%d\n", c);//30
	printf("%d\n", c1);//30
	printf("%d\n", c2);//20
	return 0;
}

12.3.define 与typedef的区别

推荐这篇回答https://blog.csdn.net/qq_42795061/article/details/121691567

13. 指针

13.1 内存

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

变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。

#include<stdio.h>
int main()
{
	int a = 10;//4个字节
	//当a创建好后,占用4个字节,每个字节都有一个地址(编号)
	//&a拿到的是第一个字节的地址
	int* pa = &a;//pa是创建出来存放地址(地址也叫指针)的(这里的地址是指&a,也就是第一个字节的地址)
	//pa就是指针变量
	//int*整体是一个类型,整型指针类型,
	//*说明pa是指针变量,int 说明pa指向的对象是整型
	*pa = 20;//*是解引用操作符,*pa就是通过pa中存放的地址,找到pa指向的空间。
	//a = 20;
	printf("%d\n", a);//20
	//& - 取地址操作符,取出谁的地址
	//* - 解引用操作符(间接访问操作符),通过地址找到地址所指向的内容

	char ch = 'a';
	char* pt = &ch;
	return 0;
}
//内存单元的编号=地址=指针
//口头语说的指针一般是指针变量

Fn+F10调试,点击调试->窗口->监视\内存,在监视里添加a和&a,内存这里地址填&a,行数改为1.
在这里插入图片描述
在这里插入图片描述

13.2 指针变量的大小

#include<stdio.h>
int main()
{
	char ch = 'q';
	char* pa = &ch;
	//sizeof计算的结果(返回值)是无符号整数
	//对应的打印格式是:%zu 用%d会有警告出现
	printf("%zu\n", sizeof(char*)); //等价于printf("%d\n", sizeof(ch));
	printf("%zu\n", sizeof(short*));
	printf("%zu\n", sizeof(int*));
	printf("%zu\n", sizeof(long*));
	printf("%zu\n", sizeof(long long*));
	printf("%zu\n", sizeof(float*));
	printf("%zu\n", sizeof(double*));

	return 0;
}
//指针变量的大小是多少呢?
//指针变量是用来存放地址的
//所以指针变量的大小取决于存储一个地址需要多大的空间
//x86 -> 32位环境 
//32跟地址线,一根地址线一个电信号,电信号转换为数字信号,
//32跟地址线同时产生一个二进制序列作为一个地址编号,
//也就是32个0或者1组成的地址序列,需要32个bit=4byte的空间来存储
//指针变量的大小也需要4个字节

//x64 -> 64位环境
//地址的序列就是32个0或者1组成的二进制序列,要存储起来需要8个字节

结论:指针大小在32位平台是4个字节,64位平台是8个字节。

14. 结构体

结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。
比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。
这里只能使用结构体来描述了。

#include<stdio.h>
struct stu//结构体类型
{
	char name[20];
	int age;
	float score;
};
void print(struct stu * ps)
{
	//1.
	//printf("%s %d %f\n", (*ps).name, (*ps).age, (*ps).score);zhangsan 20 95.500000
	//2.结构体指针->结构体成员
	printf("%s %d %f\n", ps->name, ps->age, ps->score);//zhangsan 20 95.500000
}
int main()
{
	struct stu s1 = { "zhangsan",20,95.5f };
	struct stu s2 = { "lisi",40,99.8f };
	//结构体变量.结构体成员
	//printf("%s %d %f\n", s1.name, s1.age, s1.score);//zhangsan 20 95.500000
	//printf("%s %d %f", s2.name, s2.age, s2.score);//lisi 40 99.800003
	// 输入数据到s2中
	scanf("%s %d %f", s1.name, &(s1.age), &(s1.score));
	//数组名本来就是地址,输入时不需要再取地址
	print(&s1);//
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值