从零开始C语言精讲篇1:初识C语言

文章目录

  • 前言
  • 一、什么是C语言(了解)
  • 二、第一个C语言程序
  • 三、数据类型
  • 四、变量、常量
    • 4.1变量
      • 4.1.1定义变量的方法
      • 4.1.2变量的分类
      • 4.1.3变量的使用
      • 4.1.4变量的作用域和生命周期
    • 4.2常量
      • 4.2.1 字面常量
      • 4.2.2. const 修饰的常变量
      • 4.2.3. #define 定义的标识符常量
      • 4.2.4. 枚举常量
  • 五、字符串+转义字符+注释
    • 5.1字符串
    • 5.2转义字符
    • 5.3注释
  • 六、选择语句
  • 七、循环语句
  • 八、函数
  • 九、数组
    • 9.1数组定义
    • 9.2数组的下标
  • 十、操作符
    • 10.1算术操作符
    • 10.2移位操作符
    • 10.3位操作符
    • 10.4赋值操作符
    • 10.5单目操作符
    • 10.6关系操作符
    • 10.7逻辑操作符
    • 10.8条件操作符
    • 10.9逗号表达式
  • 十一、常见关键字
    • 11.1typedef
    • 11.2static
  • 十二、#define定义常量和宏
  • 十三、指针
    • 13.1指针使用示例
    • 13.2指针的大小
  • 十四、结构体
    • 14.1结构体是什么?
    • 14.2初识结构体(我们以学生小明为例)
      • 14.2.1创建学生结构体
      • 14.2.2对小明进行描述
    • 14.3结构体指针
      • 14.3.1结构体指针的使用
  • 后记


前言

这里是C语言专栏重制版,笔者将定期更新C语言相关文章,让读者快速上手,并深入理解C语言。笔者在之前也有一些C语言和JAVA基础与进阶相关文章,感兴趣的读者可自行查看。本专栏是面向零基础或者刚刚入门又或者准备系统复习一下C语言的读者。也是为笔者本人考研的C语言打一个铺垫,未来与诸君共勉。希望大家读完文章都能有所收获。


从零开始C语言精讲篇1:初识C语言_第1张图片

提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是C语言(了解)

从零开始C语言精讲篇1:初识C语言_第2张图片

二、第一个C语言程序

我们的C语言中,main函数就是程序的入口,一个工程中main函数有且只有一个。

我们可以在main函数中写一些我们需要的程序代码。

#include 
int main() {//main函数是C语言程序的入口,有且只有一个main函数
	printf("hello world");//表示打印字符串hello world
	printf("1\n");//\n表示换行
	printf("2");
	return 0;
}

运行结果如下:
从零开始C语言精讲篇1:初识C语言_第3张图片
我们代码中hello world中没有使用\n,也就是换行,所以1会跟在hello world后面
而1使用了换行,所以2会到下一行进行打印。

三、数据类型

数据有很多类型啊,
比如笔者的姓氏字母是w,这个w就是一个字符类型
比如笔者175cm,这个175就是一个整形(你可以理解为一个整数)
再比如笔者69.5kg,这个69.5就是一个浮点型(一个小数)

可能会有同学问:“为什么叫浮点型?”
解释如下:69.5=6.95 * 10=0.695 * 100
如果采用科学计数法,小数点是会上下浮动的,所以叫浮点型

C语言中的数据类型如下:

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

而不同数据类型所占的空间大小也是不同的
我们可以用sizeof( )这个操作符进行测试,比如sizeof(char)表示char类型的大小

int main() {
	//%d打印有符号数
	//sizeof()表示...的大小
	printf("%d\n",sizeof(char));//1字节(byte)
	printf("%d\n", sizeof(short));//2
	printf("%d\n", sizeof(int));//4
	printf("%d\n", sizeof(long));//4
	//c语言规定sizeof(long)>=sizeof(int)即可
	//在32位下sizeof(long)是4
	//在64位下sizeof(long)是8
	printf("%d\n", sizeof(long long));//8
	printf("%d\n", sizeof(float));//4
	printf("%d\n", sizeof(double));//8

	int age = 21;//age在内存上分配4字节的空间
	char ch = 'w';//ch在内存上分配1字节的空间
	float weight = 69.1;

	return 0;
}

运行结果如下
从零开始C语言精讲篇1:初识C语言_第4张图片
我们这里打印了一堆数字,那这些数字的单位是什么?
这里的单位是字节(byte)

我们计算机中的单位如下:

bit //最小单位
byte
kb
mb
gb
tb
pb

我们计算机能够识别的是二进制,也就是0和1
而这些0和1,一个0(或1)所占的一个空间就是1比特位(bit)

换算关系如下

1byte=8bit
1kb=1024byte
1mb=1024kb
1gb=1024mb
1tb=1024gb
1pb=1024tb

四、变量、常量

生活中的有些值是不变的(比如:圆周率,性别,身份证号码,血型等等)
有些值是可变的(比如:年龄,体重,薪资等等)。

不变的值,C语言中用常量的概念来表示,变得值C语言中用变量来表示

4.1变量

4.1.1定义变量的方法

类型名 变量名 =值

举例如下:

int age = 150;
float weight = 45.5; 
char ch = 'w';

4.1.2变量的分类

变量分为两类:
1.局部变量
在大括号{ }内部定义的变量就是局部变量

2.全局变量
在大括号{ }外部定义的变量就是全局变量

int c = 99;//全局变量,在main函数外,没有{}限制它
int main() {
	int a = 100;//局部变量,在main函数一个范围内,有{}限制
	printf("%d", a);//100  
	return 0;
}

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

注意:局部变量就是在main函数内定义的变量是错误的
举个例子:

int c = 99;//全局变量
void test() {//test是一个没有返回值的函数,这个后面讲
	int b = 10;//b也是一个局部变量,且不是在main函数内
}
int main() {
	int a = 100;//局部变量,在main函数一个范围内,有{}限制
	printf("%d", a);//100  
	return 0;
}

上面的b,是在test函数里面定义的,它也是一个局部变量。

需要注意的是如果局部变量和全局变量名字相同,局部变量优先

int a = 99;//全局变量
int main() {
	int a = 100;//局部变量
	printf("%d", a);//100 
	//如果局部变量和全局变量名字相同,局部变量优先
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第5张图片

4.1.3变量的使用

int main() {
	int n1 = 0;
	int n2 = 0;
	scanf("%d %d", &n1, &n2);
	//输入两个数,一个放到 n1的地址处,一个放到 n2的地址处
	int sum = n1 + n2;
	printf("%d", sum);
}

比如我这里输入两个数:520和1314,那么就会自动输出1834
从零开始C语言精讲篇1:初识C语言_第6张图片

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

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

  1. 局部变量的作用域是变量所在的局部范围。
  2. 全局变量的作用域是整个工程。

生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
3. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
4. 全局变量的生命周期是:整个程序的生命周期。

4.2常量

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

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

4.2.1 字面常量

//字面常量
int main() {
	//直接写出来的值,就是字面常量
	3.14;
	100;
	"abc";//字面的字符串常量
}

4.2.2. const 修饰的常变量

我们知道变量是可以改变的,如下示例

int main() {
	int n = 1;
	n = 2;//用2赋值n,也就说变量n从1变成了2
	printf("%d", n);//打印2
}

但是如果在变量前加一个const呢?
大家可以对比一下我加const前和const后编译器的变化

加const前:没有报错信息
从零开始C语言精讲篇1:初识C语言_第7张图片

加const后:有报错信息
从零开始C语言精讲篇1:初识C语言_第8张图片

他提示你表达式必须是可修改的左值,也就是说被const修饰后的变量就不可修改了
从零开始C语言精讲篇1:初识C语言_第9张图片

特别说明:
从零开始C语言精讲篇1:初识C语言_第10张图片
在C99标准前,数组的大小只能是常量。笔者这里用的编译器是VS2017,对C99标准支持的不是很好,所以这里报错了。

那么我们是不是在n之前加一个const,就不会报错呢?
从零开始C语言精讲篇1:初识C语言_第11张图片
如上图,加了const后依旧会报错,这就说明了一件事:
被const修饰的变量只是不能改变了,但是他本质仍然是个变量,不是常量

4.2.3. #define 定义的标识符常量

#define x 100 //define也就是字面意思定义,
//这里是定义x 为100,注意是没有等于号的
int main() {
	printf("%d", x);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第12张图片

同样的,#define出来的量也是不能修改的,你要是修改就会如下图报错
从零开始C语言精讲篇1:初识C语言_第13张图片

注意:这里的define定义的值是可以做数组大小的,它是一个常量,请大家区别于const
可以看到,下图是没有报错的。
从零开始C语言精讲篇1:初识C语言_第14张图片

4.2.4. 枚举常量

枚举就是一 一列举的意思。

比如我们现在把一些值一 一列举出来:
性别:男、女
三原色:红、绿、蓝

enum Day//enum Day是一种类型
{
	Mon,//周一到周日这些叫枚举的可能取值,也叫枚举常量
	Tue,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun,
};

上述代码定义的enum Day是一种枚举类型,{}中内容是枚举类型的可能取值,也可叫作枚举常量。
这些枚举常量都是有值的,默认从0开始,依次往后递增1,如果你愿意赋值也是可以的。
代码如下:

#include
enum Color//enum Color是一种类型
{
	red,
	green,
	blue
};
int main()
{
	printf("%d\n", red);
	printf("%d\n", green);
	printf("%d\n", blue);
}

不赋初值打印0, 1,2
从零开始C语言精讲篇1:初识C语言_第15张图片

#include
enum Color//enum Color是一种类型
{
	red=2,
	green,
	blue=6
};
int main()
{
	printf("%d\n", red);
	printf("%d\n", green);
	printf("%d\n", blue);
}

赋初值后打印初值内容,如果你有一个没有赋值,会紧接上一个赋值内容+1
,这里green并没有赋值,但我们知道red是2,按照枚举规则,green会在red的基础上加1变成3,
注意,blue是有赋值的,所以blue不需要在green的基础上加1,blue就是6
从零开始C语言精讲篇1:初识C语言_第16张图片
注意:因为是枚举{}内的叫作枚举常量,常量是不能改的,比如你在main函数里进行赋值操作,red=9;这个铁铁的会报错,一定要区分枚举初始化和赋值的区别。

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

5.1字符串

“i love china”

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

如果将来读者学了Java会涉及到字符串类型String,但是C语言中是没有字符串类型的。
虽说C语言没有字符串类型,但是我们也是可以把字符串放到字符数组里面进行存储

示例代码如下:

int main() {
	char arr1[] = "abc";//把字符串abc放到数组arr1中
	//数组在创建过程中,如果后面进行了初始化,可以不指定大小
	//大小会根据后面初始化内容来自己变化
	return 0;
}

大家可以按f10进行调试(如果f10不起作用,按fn+f10)

从零开始C语言精讲篇1:初识C语言_第17张图片
可以看到我们arr1里面是存放了’a’ ‘b’ ‘c’ ‘\0’
可我们明明代码中只写了"abc"啊

其实代码中是隐藏了一个‘\0’作为结束标志
重点:字符串的结束标志是一个 \0 的转义字符。
在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。

如果我们用大括号的方式往字符数组里面放,会不会有’\0’呢?

int main() {
	char arr2[] = { 'a', 'b', 'c' };
	char arr3[] = { 'a', 'b', 'c', '\0' };
	return 0;
}

我们调试一下看:可以看到arr2中没有主动放‘\0’就不会有
从零开始C语言精讲篇1:初识C语言_第18张图片

我们再来试着打印一下arr1、arr2、arr3看它们之间到底有什么样的联系

int main() {
	char arr1[] = "abc";//把字符串abc放到数组arr1中
	//数组在创建过程中,如果后面进行了初始化,可以不指定大小
	//大小会根据后面初始化内容来自己变化
	char arr2[] = { 'a', 'b', 'c' };
	char arr3[] = { 'a', 'b', 'c', '\0' };
	printf("%s\n", arr1);//%s以字符串形式打印,后面会学 %c以字符形式打印,注意区别
	printf("%s\n", arr2);
	printf("%s\n", arr3);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第19张图片
可以看到arr2打印了abc然后一堆乱码…

原因如下:
我们是以%s的形式打印字符串,遇到\0后就知道是结束了,就不再打印了
但是你arr2里面没有\0,打印完abc后没有结束标志啊,
编译器就一直往后找,一直打印,直到找到\0然后才结束打印

因为我们“abc”会默认后面有一个\0,所以arr1打印没有问题
但是用{ }来写就没有默认添加\0了,你不自己添加,编译器就傻傻的找,直到找到\0

计算字符串长度:
strlen函数:从字符串开头往后找,找到\0结束

#include 
#include 
//要用库函数strlen,需要包含头文件string.h
int main() {
	char arr1[] = "abc";
	char arr2[] = { 'a', 'b', 'c' };
	char arr3[] = { 'a', 'b', 'c', '\0' };
	int len1 = strlen(arr1);//库函数strlen是用来求字符串长度的
	int len2 = strlen(arr1);
	int len3 = strlen(arr1);
	printf("%d\n", len1);//3
	printf("%d\n", len2);//随机值
	printf("%d\n", len3);//3
	return 0;
}

arr1中是有\0的,strlen从前往后数,直到\0结束(\0不计算),也就是数abc一共3个,所以打印了3
arr3和arr1是同理的

问题就是arr2为什么是随机值?
原因也很简单,因为我们没有给它安一个\0,而内存是连续的
我们strlen向后一直找,直到随机找到一个\0结束,所以它打印的值也是随机的
从零开始C语言精讲篇1:初识C语言_第20张图片

5.2转义字符

转义字符,也就是转变字符原有的意思
举例如下:

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

#include 
int main()
{
 printf("c:\code\test.c");
    return 0;
}

上述代码运行结果如下
从零开始C语言精讲篇1:初识C语言_第21张图片
这里就不得不提一下转义字符了。转义字符顾名思义就是转变意思。
下面看一些转义字符。

从零开始C语言精讲篇1:初识C语言_第22张图片
由上图可以知道了,如果我们想防止一个 \ 和后面的字母构成转义字符
我们在 \ 前再加一个 \ 即可

#include 
int main()
{
	printf("c:\\code\\test.c\n");
	return 0;
}

这下就可以正常打印了
从零开始C语言精讲篇1:初识C语言_第23张图片
关于转义字符,大家不要去背它的功能,因为一般也就用几个,比如\n是换行,稍微了解一下即可。

我们下面介绍两个比较重要的转义字符\ddd和\xdd
在这里插入图片描述

\ddd:

#include 
int main()
{
	printf("%c", '\162');//以字符形式打印'\162'
	//\162表示八进制数162,转换成十进制为114
    //打印出r
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第24张图片
162转换成八进制是1 * 8^2+6 * 8^1 +2 * 8 ^ 0=64+48+2=114
114正好对应我们的ASCII码表的114位

注:如果你的八进制数只有两位,比如\71,你写成\071也是可以的,最后结果一样

#include 
int main()
{
	printf("%c\n", '\71');
	printf("%c\n", '\071');
	//八进制71转换成十进制是7*8^1+1*8^0=57,对应ascii码的9
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第25张图片

\xdd:

int main()
{
	//16进制数由0-9和 abcdef(分别对应10-15)组成
	printf("%c\n",'\x5a');
}

从零开始C语言精讲篇1:初识C语言_第26张图片

16进制的5a转换成10进制是5*161+a*160=80+10=90
也就是ASCII码表中的Z

最后我们来看一道笔试题

//程序输出什么?
#include 
int main()
{
    printf("%d\n", strlen("abcdef"));
    printf("%d\n", strlen("c:\test\328\test.c"));
    return 0;
}

从零开始C语言精讲篇1:初识C语言_第27张图片
6的话很好理解,一共6个字符,到隐藏的\0结束

14怎么理解呢?
我们前面c:一共2个
然后到了\t,是一个转义字符,它是算1个
再往下est一共3个
再往下

这时有同学可能会抢答了:\328你之前讲过,是一个八进制数
我想问:“八进制数最高是多少?”
我们十进制数最高是9啊,同理,八进制数最高是7啊,怎么会出现8呢,
所以这里\32是一个 8是另外一个 ,一共2个

再往下\t 1个
最后est.c一共5个
综上一共14

5.3注释

  1. 代码中有不需要的代码可以直接删除,也可以注释掉
  2. 代码中有些代码比较难懂,可以加一下注释文字
#include 
int Add(int x, int y)
{
    return x+y;
}
/*C语言风格注释
int Sub(int x, int y)
{
    return x-y;
}
*/
int main()
{
    //C++注释风格
    //int a = 10;
    //调用Add函数,完成加法
    printf("%d\n", Add(1, 2));
    return 0;
}

注释有两种风格:
C语言风格的注释 /xxxxxx/
缺陷:不能嵌套注释

C++风格的注释 //xxxxxxxx
可以注释一行也可以注释多行

六、选择语句

生活中处处面临选择,比如大学里有的同学准备考研了,所以他努力学习;也有的同学天天混日子,所以他毕业就回家种地了
C语言中也有选择,不同的选择,对应不同的选择结果。我们常常通过下面的代码进行选择

if(条件)
{
...
}
else
{
...
}

举个例子:

int main()
{
	int a = 0;
	printf("你大学有好好学习吗?请输入1/0\n");
	scanf("%d", &a);
	if (a == 1) {
		printf("你好好学习了,你将拥有一个光明的未来");
	}
	else {
		printf("不好好学习就给老子爬");
	}
	return 0;
}

可以看到我们这里不同的输入,控制台会给出不同的结果,这就是选择
从零开始C语言精讲篇1:初识C语言_第28张图片
从零开始C语言精讲篇1:初识C语言_第29张图片

关于选择if还有一些细节,以及switch语句,这两个我会放在《从零开始C语言精讲篇2:分支与循环》
进行详细的讲解,这里的选择与循环只是做一个入门工作

七、循环语句

循环也是我们日常学习中经常用的一个知识点
比如我们学习总是日复一日,在达到一定程度之后,我们才能有所成就
循环也是这样,在经过反复操作后,到了一个触发条件,终于跳出循环继续往下执行代码。

C语言循环有三种:for循环、while循环、do while循环,我们这里做一个入门只介绍最简单的while循环,
for循环和do while循环我会放在《从零开始C语言精讲篇2:分支与循环》进行详细的讲解

while循环的语法如下:当满足执行条件时,执行{ }内的代码

while(执行条件)
{
...
}

举例如下:

int main()
{
	//比如我们假定写了20000行代码就可以出师了
	int line = 1;//标记我们写的代码行数
	while (line < 20000) {
		printf("我在写第%d行代码\n", line);
		line++;
	}
	printf("20000行代码已写完,我出师啦!");
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第30张图片

八、函数

函数的优点就是简化一些重复的代码,当你写了一个函数之后,你下次想要启用和这函数相同的功能时,
你就可以直接调用函数,而不是再写一遍函数的代码

函数的基本语法:

返回值类型 函数名(参数1类型 参数1,参数2类型,参数2...)
{
...
return 返回值
}

举个例子:我们现在实现一个简单的加法函数

int add(int x, int y) {//加法函数
	return x + y;
}

int main() {
	int a = 0;
	int b = 0;
	printf("请输入你要进行加法的两个数:\n");
	scanf("%d %d", &a, &b);
	int c = add(a, b);
	//把两参数a b放入函数add中,会分别对应x和y,
	//通过函数add计算后返回一个值,我们用c来接收这个值
	printf("两数和为:%d", c);

    //如果你懒的写c这个值,你直接打印add(a,b)也是可以的
	//printf("%d", add(a, b));
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第31张图片

九、数组

要存储1-10的数字,怎么存储?
C语言中给了数组的定义:一组相同类型元素的集合

9.1数组定义

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//定义一个整形数组,最多放10个元素

举个例子:

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int brr[10] = { 1,2,3,4,5 };//不完全初始化,剩下默认初始化为0
	return 0;
}

我们按f10进行调试,可以看到我们的数组可以存储相同的类型的一些元素,如果数组没有被放满,我们会以0进行填充
从零开始C语言精讲篇1:初识C语言_第32张图片
我们以后写代码经常会看见int arr[10]={0}这种初始化方法,
这句代码的意思和我写的int brr[10] = { 1,2,3,4,5 }是差不多的
只不过它是意思是只初始化第一个为0,然后剩下的全部默认初始化为0

9.2数组的下标

C语言规定每个数组元素都有一个下标,数组元素的下标是从0开始的,
从零开始C语言精讲篇1:初识C语言_第33张图片
推广一下,如果我数组大小不是10,而是n,那么我数组最后一位下标应该是n-1

举个例子:

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int brr[10] = { 1,2,3,4,5 };

	printf("%d\n", arr[2]);//下标为2,对应元素为数组第三个
	printf("%d\n", brr[0]);//下标为0,对应元素为数组第一个
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第34张图片
如果你想打印数组的所有元素,也很简单,加上前面说的循环即可

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;//标记数组下标
	while (i < 10) {//这里条件你写i<=9也可
		printf("%d\n", arr[i]);
		i++;
	}
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第35张图片

有同学可能会说,如果我将来把数组元素个数改变了,那你那个while也要改,好麻烦啊
对于这个问题,我们引入了sizeof()来改进代码

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;//标记数组下标
	int sz = sizeof(arr)/sizeof(arr[0]);
	//sizeof(arr)可以计算出数组arr总大小,
	//然后我们除以每个元素大小(每个元素大小都是和arr[0]一样的),就可以得到元素个数
	//比如我们这里整形数组arr总大小为40,每个整形大小为4,那么个数=40/4=10
	while (i < sz) {
		printf("%d\n", arr[i]);
		i++;
	}
	return 0;
}

十、操作符

10.1算术操作符

+ - * / %

加减乘没什么好说的,和我们数学上都是一样的,我们来说一说除"/“和求余”%"

关于除号“/”

int main()
{
	int a = 7 / 2;
	printf("%d\n", a);//如果除号两边都是整数,那么得到的一定是整数
}

从零开始C语言精讲篇1:初识C语言_第36张图片肯定会有人有疑问,那如果我非要得到一个小数呢?
也很简单,你把除号两边任意一个数变成小数即可,比如7/2变成7.0/2或者7/2.0

int main()
{
	float a = 7.0 / 2;//因为得到是小数,所以我们这里用float类型的a接收
	printf("%f\n", a);//打印也要用浮点型 %f来打印
}

从零开始C语言精讲篇1:初识C语言_第37张图片
如果想精确保留n位,那么在%f那里修改成%.nf,比如我这里想精确两位小数

int main()
{
	float a = 7.0 / 2;
	printf("%.2f\n", a);//如果除号两边都是整数,那么得到的一定是整数
}

从零开始C语言精讲篇1:初识C语言_第38张图片

关于求余数“%”

int main()
{
	int a = 7 % 2;//%是求余的意思,比如这里7/2=3...1,那么7%2=1
	printf("%d", a);
}

从零开始C语言精讲篇1:初识C语言_第39张图片

10.2移位操作符

>> <<
int main()
{
	//移位运算符移动的是二进制位
	int a = 12;
	
	int b = a << 1;//a左移一位得到的数放到b中
    //ps:0000 1100和1100是一个数,左边不管你补多少0都一样的
	//12的二进制表示是:  0000 1100  
	//向左移动一位为:    0001 1000 向左移动,右边补0
	//将0001 1000转换为10进制=1*2^4+1*2^3+0+0+0=16+8=24
	printf("%d", b);
	return 0;
}

因为是初识c语言,我们这里只是稍微介绍一下,后面笔者会更新操作符详解,对这里的移位进行详细介绍

10.3位操作符

& ^ |

从零开始C语言精讲篇1:初识C语言_第40张图片
关于按位与“&”:就是把二进制对应位进行与运算,全1为1,有0为0

int main()
{
	int a = 3;
	int b = 5;
	int c = a & b;
	//a的二进制:0011
	//b的二进制:0101
	//按位与   :0001  也就是十进制的1
	printf("%d", c);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第41张图片

关于按位或“&”:就是把二进制对应位进行或运算,有1为1,全0为0

int main()
{
	int a = 3;
	int b = 5;
	int c = a | b;
	//a的二进制:0011
	//b的二进制:0101
	//按位或   :0111  也就是十进制的7
	printf("%d", c);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第42张图片

关于按位异或“^”:就是把二进制对应位进行异或运算,相同为0,相异为1

int main()
{
	int a = 3;
	int b = 5;
	int c = a ^ b;
	//a的二进制:0011
	//b的二进制:0101
	//按位异或 :0110  也就是十进制的6
	printf("%d", c);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第43张图片

10.4赋值操作符

= += -= *= /= &= ^=  |=    >>=   <<=

赋值运算符很简单,我们举一个例子,大家就会全部的了

int main()
{
	int a = 10;//初始化
	a = 45;//赋值
	a += 1;//表示a=a+1;
	//其余的也是同样的意思,只不过把+改成了其他运算符号
	printf("%d", a);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第44张图片

注:关于浮点型赋值

int main()
{
	float a = 1.23;
	a = 1.24;
	//直接写出的1.24这样的值在c语言中是默认double类型的
	//我们最好写1.24f,这样可以指定为float类型
	return 0;
}

10.5单目操作符

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

单目操作符,就是操作数只有一个的操作符

! 逻辑反操作

int main()
{
	//!逻辑反操作
	int flag = 5;
	//c语言中用0表示假,非0表示真
	if (flag)
	{
		printf("哈哈");
	}
	if (!flag) //flag为真,!flag为假,所以这里就不会打印嘿嘿
	{//也就是说,如果想打印嘿嘿,flag需要为0
		printf("嘿嘿");
	}
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第45张图片

+ - 正值和负值

int main()
{
	int a = -10;
	a = -a;//也就是把a变成他的相反数,这没啥好说的
	printf("%d\n", a);//打印10

	int b = +a;//+正号,其实根本没有用,你不写这个正号又有什么影响呢==.==
	printf("%d", b);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第46张图片

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

int main()
{
	//sizeof()是一个操作符,不是函数!!!
	printf("%d\n", sizeof(int));//打印4
	//sizeof(int)表示计算int这个类型创建的变量所占内存空间大小
	int a = 1;
	printf("%d\n", sizeof(a));//打印4
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第47张图片
再次重申:sizeof不是函数,sizeof不是函数,sizeof不是函数!!!

sizeof也可以用来计算数组元素个数

int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d", sz);//打印10
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第48张图片

~ 对一个数的二进制按位取反

//计算机识别的是二进制
//整数存放在内存中的是二进制的“补码”
//怎么表示整数的二进制?


//规定:
//非负整数的原码、反码、补码相同
//负整数的原码、反码、补码需要计算,计算规则如下:
//原码:直接按照数字的正负转换成二进制就是原码
//反码:原码的符号位不变,其他位按位取反
//补码:反码+1
int main()
{
	int a = 0;//int是4字节,也就是32bit
	//a原码:00000000 00000000 00000000 00000000  非负数原反补相同
	//a反码:00000000 00000000 00000000 00000000
	//a补码:00000000 00000000 00000000 00000000
	printf("%d", ~a);
	//~a是对内存里的a进行计算的,而内存里存放的是a补码,
	//也就是对补码进行按位取反
	//取反后补码 11111111 11111111 11111111 11111111 
	//还原成反码 11111111 11111111 11111111 11111110
	//还原成原码 10000000 00000000 00000000 00000001
	//也就是-1

	int b = -1;
	//b原码:10000000 00000000 00000000 00000001 
	//b反码:11111111 11111111 11111111 11111110  原码的符号位不变,其他位按位取反
	//b补码:11111111 11111111 11111111 11111111  反码+1

	
}

从零开始C语言精讲篇1:初识C语言_第49张图片

- - 前置、后置–
++ 前置、后置++

这个是很常用的操作,也是很简单的,我们进行一个前置++和后置++的讲解,读者也很快能了解前置- -和后置- -

int main()
{
	//前置++:先加后用
	//后置++:先用后加
	int a = 10;
	int b = a++;

	int c = 10;
	int d = ++c;

	printf("b=%d\n", b);
	printf("d=%d\n", d);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第50张图片
前置++就是,在变量进行加1前,先把这个变量用了
后置++就是,在变量进行加1后,在使用这个变量

比如a++和++a
两者相同的是:a最后都变成了a+1,也就类似于a=a+1
不同的是:如果进行赋值,第一个得到的值是a,第二个得到的值是a+1

前置- - 和后置- -也是同理

* 间接访问操作符(解引用操作符)
这个和取地址操作符&是一对的,我们放指针那里进行具体介绍,不然读者会云里雾里,这个可以暂时跳过。

(类型) 强制类型转换

int main()
{
	int a = (int)3.14;
	//3.14是浮点型,你想把它赋给整形的a,直接赋是会报警告的(精度丢失)
	//如果不想报警告,我们在3.14前加一个(int)表示把3.14的类型强制转换成整形
	printf("%d", a);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第51张图片

10.6关系操作符

>
>=
<
<=
!=   用于测试“不相等”
==      用于测试“相等”

举个例子:

int main()
{
	int a = (3 > 5);
	printf("%d\n", a);//3>5不正确,返回一个0给a,这里打印0
	if (3 != 5) {//判断3是否不等于5
		//如果不等于就进入if
		printf("3不等于5");
	}
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第52张图片

10.7逻辑操作符

&&     逻辑与
||     逻辑或

这个和我们高中学的且与或是一样的
A && B :A和B都成立 则该式子成立
A || B:A和B有一个成立,则式子成立

举个例子:

int main()
{
	int a = 4;
	int b = 3;
	if (a > 3 && b > 4) {//逻辑与,两边都成立才算成立
		printf("呵呵\n");
	}
	if (a > 3 && a < 5) {
		printf("哈哈\n");
	}

	if (a > 3 || b > 4) {//逻辑或,两边有一个成立即可
		printf("嘿嘿\n");
	}
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第53张图片

10.8条件操作符

exp1 ? exp2 : exp3
//exp1是否正确,如果正确则exp2,否则exp3

举个例子:

int main()
{
	int a = 3;
	int b = 2;
	int max=(a > b) ? a:b;//该式表示:a如果大于b,则把a赋给max,否则把b赋给max
	printf("%d", max);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第54张图片

10.9逗号表达式

exp1, exp2, exp3, …expN
int main()
{
	int a = 3;
	int b = 5;
	int c = 6;
	int d = (a -= 2, b = a + c, c = a - b);
	//由逗号隔开的表达式,就叫逗号表达式
	//逗号表达式会从左向右依次进行计算
	//整个表达式结果是最后一个表达式结果

	//这里a-=2,也就是a=1了
	//b=a+c=1+6=7
	//c=a-b=1-7=-6
	//所以这里d=-6

	printf("%d", d);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第55张图片

十一、常见关键字

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

常见关键字如上,我们这里进行一个简单的分类,和一些比较重要的介绍:
从零开始C语言精讲篇1:初识C语言_第56张图片
这些关键字不用死记硬背,我们多写点c语言基本也就认识了

注:
关键字不能自己创建
变量名不能是关键字

现在我们来介绍一些关键字:

11.1typedef

typedef 顾名思义是类型定义,这里应该理解为类型重命名。
举个例子:

int main()
{
	unsigned int a = 10;//表示无符号整数
	//但是每次都写unsigned int很麻烦
	//能不能有办法把unsigned int简写成uint这种呢?
	return 0;
}

我们如果嫌弃某个类型写起来很麻烦,我们可以用typedef进行重命名

typedef unsigned int uint;//把unsigned int重命名为uint
//除了unit你也可以改其他名字
int main()
{
	unsigned int a = 10;//表示无符号整数
	uint b = 10;
	printf("%d", b);//可以正常打印10
	return 0;
}

11.2static

在C语言中:
static是用来修饰变量和函数的
1. static修饰局部变量-静态局部变量

举个例子:

void test()
{
	int a = 1;
	a++;
	printf("%d ", a);
}
int main()
{
	int i = 0;
	while (i<10)
	{
		test();
		i++;
	}
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第57张图片

上面这段代码,我们打印的结果为10个2,因为我们while会进行10次循环,然后调用10次test函数,进入test函数后,我们的a是每次都要重新创建的,并且在出了函数之后就会销毁,所以每次都是2

如果我们在int a前面加一个static呢?结果会有变化吗?

void test()
{
	static int a = 1;
	a++;
	printf("%d ", a);
}
int main()
{
	int i = 0;
	while (i<10)
	{
		test();
		i++;
	}
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第58张图片
可以看到,我们这次的打印结果变为了2,3,4,5…11
为什么呢?因为我们加了一个static让a这个变量出了函数也不会销毁,下次再进入这个函数也不会重新创建a,也就是说我们每次a++都是对同一个a进行的操作。所以我们会看到2,3,4,5…11

小结:使局部变量出了自己的范围也不会被销毁,
其实是改变了局部变量的生命周期,但是作用域还是局部的

2.static修饰全局变量-静态全局变量

全局变量是具有外部链接属性的,我们在一个.c文件中的全局变量可以在另一个.c文件中使用

比如我现在在源.c文件中创建一个全局变量a,并赋值100
从零开始C语言精讲篇1:初识C语言_第59张图片

从零开始C语言精讲篇1:初识C语言_第60张图片
从零开始C语言精讲篇1:初识C语言_第61张图片
可以看到,在声明后,我们可以在test.c中正常打印全局变量a的值

但是如果全局变量加了static后,全局变量会失去外部链接属性,变成内部链接属性,也就是说,被static修饰的全局变量,只能在自己所在的.c文件中使用。
从零开始C语言精讲篇1:初识C语言_第62张图片
从零开始C语言精讲篇1:初识C语言_第63张图片
小结:全局变量本身具有外部链接属性,但是static修饰全局变量,会使全局变量失去外部链接属性,变成内部链接属性,所以static修饰的全局变量,只能在自己所在的.c文件中使用

3.static修饰函数-静态函数

对于函数来说,也是可以在A文件中定义,在B文件中使用的(需要声明)

比如我们在源.c文件中写一个add函数
从零开始C语言精讲篇1:初识C语言_第64张图片
在test.c文件中也是可以正常使用它的(需要声明)
从零开始C语言精讲篇1:初识C语言_第65张图片

从零开始C语言精讲篇1:初识C语言_第66张图片

但是函数被static修饰后,就不能被其他文件使用了(外部链接属性没了)
从零开始C语言精讲篇1:初识C语言_第67张图片
这里再次调用就会报错了
从零开始C语言精讲篇1:初识C语言_第68张图片
小结:static修饰函数,函数默认是具有外部链接属性的,但是被static修饰后,会使得函数失去外部链接属性,变成内部链接属性。所以static修饰的函数只能在自己的.c文件内部使用,而不能在其他文件使用。

十二、#define定义常量和宏

#define定义常量在4.2.3讲过,我们这里只做简单介绍

#include
#define num 1000
int main()
{
	int a = num;
	printf("%d", a);
}

从零开始C语言精讲篇1:初识C语言_第69张图片

那#define 定义宏是什么意思呢?
宏和我们的函数很像啊
比如我们这里定义一个add的宏

#define _CRT_SECURE_NO_WARNINGS
#include
#define  add(x,y) (x+y)
int main()
{
	int a = add(3,4);
	printf("%d", a);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第70张图片
宏就相当于是替换式的工作,比如我们代码中#define add(x,y) (x+y)
那么我们在main函数中add(3,4);就会把add(3,4)替换成(3+4)

ps:宏和函数各自有优势,但是我本人写代码一般都是函数用的多,宏用的比较少

十三、指针

我们这里是初识c语言,我们指针只做一个初阶的理解,后面笔者会专门出一期指针的全面讲解

要学会指针,我们需要先了解一下内存
内存是电脑上特别重要的存储器,计算机中所有程序的运行都是在内存中进行的 。

为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节

为了有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址
从零开始C语言精讲篇1:初识C语言_第71张图片

13.1指针使用示例

每个变量都有它的地址,我们这里取一个变量的地址看一下

int main()
{
	int a = 1;
	printf("%p", &a);
	//&:取地址操作符
}

按f10进行调试,然后点击调试、窗口、内存
从零开始C语言精讲篇1:初识C语言_第72张图片
我们可以看到运行结果是00FAFBF8(你不一定和我一样)
从零开始C语言精讲篇1:初识C语言_第73张图片
我们在内存界面输入这个地址00FAFBF8或者&a(取出a的地址)
我们这里用用4列来看这个地址(一个内存单元1字节,然后int是4字节嘛)
从零开始C语言精讲篇1:初识C语言_第74张图片
我们用4列看地址是这样的
从零开始C语言精讲篇1:初识C语言_第75张图片
如果换成1列来看,可以看出来,我们的a虽然是占了4个内存单元,
但是&a(取出a地址)是算的第一个内存单元的地址
从零开始C语言精讲篇1:初识C语言_第76张图片

可能会有同学问:“我们&a是得到的a的地址啊,如果我想把这个地址存起来怎么存?”

我们把这个地址放到变量pa中,pa的类型为int*

int main()
{
	int a = 1;
	printf("%p", &a);
	//&:取地址操作符
	//&a取出的是a所占内存中4个字节中第一个字节的地址

	int* pa = &a;//我们把a的地址放到pa中,pa的地址叫int*
	//int*怎么理解?
	//*说明pa是个指针
	//*前面的int说明pa指向的变量是个int型

	return 0;
}

画个图来帮大家理解一下:
从零开始C语言精讲篇1:初识C语言_第77张图片
图中我们pa中存放的是a的地址,存放的这个地址我们也可以叫作指针(可以通过存放的地址找到a)

那么我们来做一个推广,对于char类型的a来说,我们用pa存放它的地址,
char*中的 * 表示pa是个指针,char表示pa指向的变量类型是char类型

int main()
{
	char a = 'A';
	char* pa = &a;
	return 0;
}

类似的,其他类型指针也是如此…

我们前面说过,可以通过指针找到它指向的对象,那怎么找呢?
需要用到“ * ”,注意,这里的 * 不是表示指针,是解引用的意思

解引用就是,我现在有一个地址pa,我在pa前加一个*,也就是 * pa
这个 * pa就相当于通过pa得到了a,简单理解,你就可以当*pa=a

打个比方,我去办身份证,然后我在警察局留了我的家庭住址(指针),然后如果以后警察需要找到我,就可以通过这个地址(指针),这个通过地址找我的过程就是解引用。解引用后就得到了我这个变量。也就是*pa=a

int main()
{
	int a = 1;
	
	int* pa = &a;//我们把a的地址放到pa中,pa的地址叫int*
	//int*怎么理解?
	//*说明pa是个指针
	//*前面的int说明pa指向的变量是个int型

	printf("%d\n", *pa);//对pa进行解引用,也就得到了a,就相当于*pa==a

	*pa = 2;
	printf("%d\n", a);//原先a是1,我们通过*pa=2进行了a变量值的改变
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第78张图片

13.2指针的大小

我们指针是用来存放地址的,那是不是很容易理解指针大小就是地址的大小呢?

32位环境下:指针大小为4字节
64位环境下:指针大小为8字节

这里的指针大小和指针指向什么类型是无关的。

int main()
{
	printf("%d\n", sizeof(char*));
	printf("%d\n", sizeof(int*));
	printf("%d\n", sizeof(short*));
	printf("%d\n", sizeof(double*));
	printf("%d\n", sizeof(float*));
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第79张图片

我们换成64位,把x86改成x64即可换成64位
从零开始C语言精讲篇1:初识C语言_第80张图片
可以看到,打印结果由4
从零开始C语言精讲篇1:初识C语言_第81张图片

十四、结构体

结构体它是一种组合类型,也是我们自己创造的类型,或者说自定义类型。结构体的关键字为struct

14.1结构体是什么?

结构体是一个c语言极其重要的板块,我们在现实生活中描述一个具体的事物时,总会列举这个事物的各个特征。举个例子,学生小明今年18岁,性别男,身高180.5cm,体重124.6kg。我们在描述小明时,对他的年龄、身高、体重做出了举例,我们用结构体来描述复杂对象(复杂类型),这便是结构体,它也是一种数据类型。

14.2初识结构体(我们以学生小明为例)

14.2.1创建学生结构体

代码如下(示例):

struct student 
{
	int age ;
	char sex[5];
	float height;
	float weight;
};//声明一个学生类型

注意点:这里struct是结构体关键字,student是结构体名,结构体默认会有大括号用来存放结构体成员,大括号最后别忘记有分号。完成上述代码,我们也就完成了一个学生结构体类型的创建,那么接下来我们就可以用这个类型来创建变量了。再次强调,结构体也是一种数据类型,它可以像其他类型一样创建变量

14.2.2对小明进行描述

创建一个结构体变量:xiaoming 并对他进行初始化用struct student xiaoming={…};大括号中间成员用逗号隔开。要打印小明的某个特点,只需将xiaoming.成员名与相应格式对应,比如:xiaoming.age对应%d,xiaoming.sex对应%s
代码如下(示例):

#include 
struct student
{
	int age;
	char sex[5];
	float height;
	float weight;
};
int main()
{
	struct student xiaoming = {18,"男",180.5,124.6};
	printf("小明年龄:%d,性别:%s",xiaoming.age,xiaoming.sex);
	return 0;
}

ps:这里对小明这个变量的创建也可直接跟在结构体大括号后,代码如下:

#include 
struct student
{
	int age;
	char sex[5];
	float height;
	float weight;
}xiaoming={18,"男",180.5,124.6};
int main()
{
	printf("小明年龄:%d,性别:%s",xiaoming.age,xiaoming.sex);
	return 0;
}

打印出来的效果是一样的
从零开始C语言精讲篇1:初识C语言_第82张图片

14.3结构体指针

示例:我们仍用上一期的小明同学进行举例
这里struct student *p=&xiaoming *p确认了p的类型是一个结构体指针,而前面的struct student确定了p指向的xiaoming是struct student类型,这里我们再次强调:结构体也是一种数据类型!!!

#include 
struct student
{
	int age;
	char sex[5];
	float height;
	float weight;
}xiaoming={18,"男",180.5,124.6};
int main()
{
	struct student *p=&xiaoming;
	return 0;
}

14.3.1结构体指针的使用

1.通过小明同学的地址找到小明

换句话说,工作时,你只有p=&xiaoming,怎么通过p找到xiaoming呢?
我们在前面的c语言指针学习中知道,*已知 int pa=&a 要通过pa找到a,只需要 * pa,也就是对pa进行解引用。结构体也是一样的,*p就是xiaoming嘛,再通过xiaoming找到小明的各项信息,即(*p).成员名=xiaoming.成员名,通过(*p).age找到小明的年龄,其他成员名以此类推。

下面两行代码打印出的信息是一样的(示例):

#include 
struct student
{
	int age;
	char sex[5];
	float height;
	float weight;
}xiaoming = { 18,"男",180.5,124.6 };
int main()
{
	struct student *p = &xiaoming;
	printf("小明年龄:%d,性别:%s\n", xiaoming.age, xiaoming.sex);
	printf("小明年龄:%d,性别:%s\n",(*p).age, (*p).sex);
	return 0;
}

从零开始C语言精讲篇1:初识C语言_第83张图片

2.另一种优化书写方案

上一种方法是同学们常常能想到的方法,但在实际中不便于书写,c语言给我们提供了另一种方法由上文已知p指向xiaoming,怎么通过p来找到小明的年龄?直接使用p->age
注解:p是一个指针,它有一个指向关系,p->的意思就是p指向的那个对象,那很容易理解,p->是小明这个对象,那p->age就是小明的年龄了,其他成员名以此类推

代码如下(示例):
你会发现下面三行代码打印出的东西也是一样的

#include 
struct student
{
	int age;
	char sex[5];
	float height;
	float weight;
}xiaoming = { 18,"男",180.5,124.6 };
int main()
{
	struct student *p = &xiaoming;
	printf("小明年龄:%d,性别:%s\n", xiaoming.age, xiaoming.sex);
	printf("小明年龄:%d,性别:%s\n",(*p).age, (*p).sex);
	printf("小明年龄:%d,性别:%s\n",p->age, p->sex);

	return 0;
}

后记

本文主要是c语言新手快速入门的一篇文章,后续还会有各个知识点的详细讲解,
希望日后与读者共同进步,相互共勉。

你可能感兴趣的:(C语言考研重制版,c语言)