初识C语言

一、main函数

每个C语言程序不管有多少行代码,都是从main函数开始执行的,main函数是程序的入口且有且仅有一个,即使一个项目(工程)中有多个.c文件,但是编译的时候是会一起编译的,所以只能有一个main函数(因为程序的入口只有一个),main函数也被叫做主函数main 前面的int 表示main函数执行结束时返回一个整型类型的值,所以在main函数的最后写return 0;,前后呼应。

main函数的标准写法:

int main()
{
	//写的代码
	return 0;
}

main函数的其他写法:

int main(void)//void:main函数不接收任何参数
{
	//写的代码
	return 0;
}

该写法少见,不需要main函数参数的话,那么这些参数为多余的,需要参数时再写:

int main(int argc, char* argv[])
{
	//写的代码
	return 0;
}

main函数的过去写法,今后就不要写了:

void main()
{

}

二、printf和库函数/标准库

printf是一个库函数,它的功能是在标准输出设备(⼀般指屏幕)上进⾏信息的打印。只要把想要打印的⼀串字符放在双引号中并传递给printf函数就可以打印。同时我们在使⽤库函数的时候,是需要包含头⽂件的,例如:printf函数需要包含的就是stdio.h这个头文件(stdio:standard input output,标准输入输出。标准输入设备一般指键盘),具体语法如下:

#include <stdio.h>
int main()
{
	int a = 10;
	printf("%d\n", a);//打印整型类型
	printf("%c\n", 'c');//打印字符类型
	printf("%lf\n", 3.14);//打印双精度浮点型
	return 0;
}

三、关键字介绍

C语⾔中有⼀批保留的名字的符号,这些符号被称为保留字或关键字。关键字都是有特殊意义的,自己在创建标识符时是不能和关键字重复的,关键字不能自己创建。
C语言32个关键字如下:

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

:在C99标准中加入了inlinerestrict_Bool_Complex_Imaginary等关键字。

四、字符和ASCII编码

在键盘上可以敲出各种字符,如:a,q,@,#等,这些符号都被称为字符,C语⾔中字符是⽤单引号括起来的,如:‘a’,‘b’,‘@’。给这些字符中的每个字符编⼀个⼆进制序列,这个叫做编码,C语⾔中的字符就遵循了ASCII编码的方式。

在这里插入图片描述
我们不需要记住所有的ASCII码表中的数字,使⽤时查看就可以,不过我们最好能掌握⼏组特殊的数据:
1.字符AZ的ASCII码值从65到90
2.字符az的ASCII码值从97到122
3.对应的大小写字符(a和A)的ASCII码值的差值是32
4.数字字符09的ASCII码值从48到57
5.换行符\n的ASCII码值是10
6.在这些字符中ASCII码值从0到31这32个字符是不可打印字符,无法打印在屏幕上观察

单个字符的打印可以使⽤%c来指定格式:

#include <stdio.h>
int main()
{
	printf("%c\n", 'Q');
	printf("%c\n", 81);//这里的81是字符Q的ASCII码值
	return 0;
}

可打印字符展示:

#include <stdio.h>
int main()
{
	int i = 0;
	for (i = 32; i <= 127; i++)
	{
		printf("%c ", i);
		if (i % 16 == 15)
			printf("\n");
	}
	return 0;
}

在这里插入图片描述

五、字符串和\0

使⽤双引号括起来的⼀串字符就被称为字符串,如:“abcdef”,就是⼀个字符串。字符串的打印格式用%s来指定,也可直接打印:

#include <stdio.h>
int main()
{
	printf("%s\n", "hello c");
	printf("hello c");
	return 0;
}

字符串的末尾隐藏着一个\0字符,是字符串的结束标志。对于字符串"abcdef",我们看到了6个字符:‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,但是实际上在末尾还隐藏⼀个\0的转义字符。所以我们在使⽤库函数printf打印字符串或者strlen()计算字符串⻓度的时候,遇到\0就⾃动停⽌了。
C语⾔中也可以把⼀个字符串放在⼀个字符数组中,我们在这⾥利⽤下⾯的代码验证⼀下\0的功能。

#include <stdio.h>
int main()
{
	char arr1[] = {'a','b','c'};//arr1数组中存放3个字符
	char arr2[] = "abc";//arr2数组中存放字符串
	printf("%s\n%s\n", arr1, arr2);
	return 0;
}

这样的代码,调试的时候,观察一下arr1和arr2的内容:
在这里插入图片描述
如何查看内容呢?键盘上按F10(若没有反应,按Fn+F10,其中Fn是辅助功能键,F1到F12是功能键)启动VS的调试,后按照下方图片指示点击,最后四个“监视”随便点哪个都行。
在这里插入图片描述
之后添加要监视的项
在这里插入图片描述
在VS上调试时,按F10是一步一步进行代码,按F11是进入函数。一次次按下F10就可以查看内容。
在这里插入图片描述
运行结果:
在这里插入图片描述
如果我们在arr1数组中单独放⼀个\0字符会怎么样呢?

#include <stdio.h>
int main()
{
	char arr1[] = { 'a','b','c','\0'};
	char arr2[] = "abc";
	printf("%s\n", arr1);
	printf("%s\n", arr2);
	printf("%s\n", "abc\0def");
	return 0;
}

在这里插入图片描述
这个例子能直观地看出\0字符的作用了。

六、转义字符

转义字符:转变原来意思的字符。
:一个转义字符表示一个字符。
例如:\n是一个转义字符表示换行,可以简单的理解为反斜杠\n的意思发生了转变,n本来是一个普通的字符,被\转义为换行的意思。
C语⾔中像这样的转义字符还有⼀些,具体如下:
\?:在书写连续多个问号时使⽤,防⽌他们被解析成三字⺟词,在新的编译器上没法验证了。例如:三字母词??)会被打印出];??(会被打印出[

#include <stdio.h>
int main()
{
	printf("are you ok??)");//are you ok],但在新的编译器上没法验证
	printf("are you ok\?\?)\n");//are you ok??)
	return 0;
}

\':⽤于表⽰字符常量’
\":⽤于表⽰⼀个字符串内部的双引号
\\:⽤于表⽰⼀个反斜杠,防⽌它被解释为⼀个转义序列符。
\a:警报,这会使得终端发出警报声或出现闪烁,或者两者同时发⽣。
\b:退格键,光标回退⼀个字符,但不删除字符。
\f:换⻚符,光标移到下⼀页。在现代系统上,这已经反映不出来了,⾏为改成类似于\v
\n:换行符
\r:回⻋符,光标移到同⼀行的开头。
\t:制表符,光标移到下⼀个水平制表位(TAB键),通常是下⼀个4/8的倍数(4/8个字符)。
\v:垂直分隔符,光标移到下⼀个垂直制表位,通常是下⼀⾏的同⼀列。
下⾯2种转义字符可以理解为:字符的8进制或者16进制表⽰形式
\ddd:1到3个八进制数字。如:\130 表示字符X
\xdd:2个十六进制数字(其中的a到f大小写都可以)。如:\x30表示字符0
\0:null字符,代表没有内容,\0就是\ddd这类转义字符的一种,用于字符串的结束标志,其ASCII码值是0。
代码演示:

#include <stdio.h>
int main()
{
	printf("%c\n", '\'');
	printf("%s\n", "\"");
	printf("c:\\test\\code\\test.c\n");
	printf("\a");
	printf("%c\n", '\130');
	printf("%c\n", '\x30');
	return 0;
}

在这里插入图片描述
关于转义字符我们⾸先要了解,然后要能在字符串中识别出来。
转义字符参考:https://zh.cppreference.com/w/c/language/escape

七、语句和语句分类

C语言的代码是由⼀条⼀条的语句构成的,C语言中的语句可为以下五类:

1.空语句

⼀个分号就是⼀条语句,是空语句。⼀般出现的地方是:这⾥需要⼀条语句,但是这个语句不需要做任何事,就可以写⼀个空语句。

#include <stdio.h>
int main()
{
	;//空语句
	return 0;
}

2.表达式语句

表达式语句就是在表达式的后边加上分号。例如:

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 0;
	b = a + 5;//表达式语句
	a+b;//表达式语句
	return 0;
}

3.函数调用语句

函数调用的时候,也会加上分号,就是函数调用语句。

#include <stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	printf("hehe\n");//函数调用语句
	int ret = Add(2, 3);//函数调用语句
	return 0;
}

4.复合语句

复合语句其实就是代码块,成对括号中的代码就构成⼀个代码块。

#include <stdio.h>
void print(int arr[], int sz)//函数的大括号中的代码构成复合语句
{
	int i =0 ;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

}
int main()
{
	int i = 0;
	int arr[10] = { 0 };
	for (i = 0; i < 10; i++)//for循环的循环体的大括号中的代码构成复合语句
	{
		arr[i] = 10 - i;
		printf("%d\n", arr[i]);
	}
	return 0;
}

5.控制语句

控制语句⽤于控制程序的执⾏流程,以实现程序的各种结构⽅式(C语⾔⽀持三种结构:顺序结构、选择结构、循环结构),它们由特定的语句定义符组成,C语⾔有九种控制语句
可分成以下三类:

  1. 条件判断语句也叫分⽀语句:if语句、switch语句;
  2. 循环执⾏语句:dowhile语句、while语句、for语句;
  3. 转向语句:break语句、goto语句、continue语句、return语句。

八、注释

注释是对代码的说明,编译器会忽略注释,也就是说,注释对实际代码没有影响。写注释⼀定程度上反应了程序作者的素质,建议写必要的注释。

1.注释的两种形式

(1)/*...*/形式

第⼀种⽅法是将注释放在/*...*/之间,内部可以分行。

/*注释*/

/*
这是注释
是注释
注释
*/

这种注释可以插在⾏内。

int fopen(char* s/*file name*/, int mode);

上⾯⽰例中,/*file name*/⽤来对函数参数进⾏说明,跟在它后⾯的代码依然会有效执⾏。这种注释⼀定不能忘记写结束符号*/,否则很容易导致错误。

printf("a ");/*注释一
printf("b ");
printf("c ");/*注释二*/
printf("d ");

上⾯⽰例的原意是,第⼀⾏和第三⾏代码的尾部,有两个注释。但是,第⼀⾏注释忘记写结束符号,导致注释⼀延续到第三⾏结束。
/*...*/不支持嵌套注释,/*开始注释后,遇到第一个*/就认为注释结束了。

/*
printf("a ");
printf("b ");
printf("c ");/*注释二*/
printf("d ");
*/

(2)//形式

这种写法是将注释放在双斜杠//后面,从双斜杠到⾏尾都属于注释。这种注释只能是单⾏,可以放在行首,也可放在一行语句的结尾。

//注释
int a = 10;//注释

不管是哪⼀种注释,都不能放在双引号⾥⾯。双引号⾥⾯的注释符号,会成为字符串的⼀部分,解释为普通符号,失去注释作⽤。

printf("//hello /*world*/");

2.注释会被替换

编译时,注释会被替换成⼀个空格,所以hello/*注释*/world会变成hello world,而不是helloworld

九、数据类型介绍

C语⾔提供了丰富的数据类型来描述⽣活中的各种数据。
使⽤整型类型来描述整数,使⽤字符类型来描述字符,使⽤浮点型类型来描述⼩数。
所谓“类型”,就是相似的数据所拥有的共同特征。
下⾯盘点⼀下C语⾔提供的各种数据类型,本章节主要探讨内置数据类型。
在这里插入图片描述
以下写在[]里的内容都可以省略

1.字符型

char //character
signed char //有符号的
unsigned char //无符号的

2.整型

//整数-integer

//短整型
short [int]
[signed] short [int]
unsigned short [int]

//整型
int 
[signed] int
unsigned [int]

//长整型
long [int]
[signed] long [int]
unsigned long [int]

//更长的整型(C99中引入)
long long [int]
[signed] long long [int]
unsigned long long [int]

3.浮点型

float
double
long double

4.布尔类型

_Bool

布尔类型是专门表示真假的。布尔类型的使用要包含头文件<stdbool.h>。布尔类型变量的取值:true或者false

#define bool _Bool
#define false 0
#define true 1

代码演示:

#include <stdio.h>
#include <stdbool.h>
int main()
{
	_Bool flag = true;
	if (flag)
		printf("haha\n");//输出:haha
	else
		printf("hehe\n");
	return 0;
}

5.各种数据类型的长度

每⼀种数据类型都有⾃⼰的⻓度,使⽤不同的数据类型,能够创建出⻓度不同的变量,变量⻓度的不同,存储的数据范围就有所差异。

(1)sizeof操作符(运算符)

sizeof是一个关键字,也是一个操作符(运算符)。用来计算sizeof操作符的操作数的类型长度,单位是字节。
sizeof操作符的操作数可以是类型、变量、表达式。它的操作数不是类型时,括号()可以省略不写。

sizeof(类型)
sizeof(变量)//或者sizeof 变量
sizeof(表达式)//或者sizeof 表达式

sizeof操作符的计算结果是size_t类型的。因为sizeof计算类型长度的结果是非负数,所以sizeof的返回值是无符号整型。用size_t来统一表示sizeof的返回值,即size_t的本质是无符号整型。

例如:

#include <stdio.h>
int main()
{
	int a = 10;
	printf("%zd\n", sizeof(int));//%zd:size_t类型,后面占位符会讲到
	printf("%zd\n", sizeof(a));
	printf("%zd\n", sizeof a);
	printf("%zd\n", sizeof 3);
	printf("%zd\n", sizeof(3 + 3.5));
	return 0;
}
4
4
4
4
8

(2)数据类型长度

sizeof(long)>=sizeof(int)sizeof(long double)>=sizeof(double),long doublelong在VS中分别是8和4个字节,但在其他编译器中分别还可能是16和8个字节。

#include <stdio.h>
int main()
{
	printf("%zd\n", sizeof(char));
	printf("%zd\n", sizeof(_Bool));
	printf("%zd\n", sizeof(short));
	printf("%zd\n", sizeof(int));
	printf("%zd\n", sizeof(long));
	printf("%zd\n", sizeof(long long));
	printf("%zd\n", sizeof(float));
	printf("%zd\n", sizeof(double));
	printf("%zd\n", sizeof(long double));
	return 0;
}

在这里插入图片描述

在这里插入图片描述

(3)sizeof中的表达式不参与运算

sizeof中的表达式不参与运算,sizeof操作符会根据表达式的类型计算出类型长度的。

#include <stdio.h>
int main()
{
	short s = 5;
	int a = 10;
	printf("%zd\n", sizeof(s = a + 1));
	printf("s=%d\n", s);
	return 0;
}

在这里插入图片描述
上示例中,a+1中的a和1都为int类型,即为四个字节,加一起也为int类型,还是四个字节,而short是两个字节。将四个字节的空间赋值给两个字节的空间,相当于将长度为四的木棍放进长度为二的空间里,放不下会被截断,所以sizeof结果为2。sizeof中的表达式不参与运算,所以变量s还是5。

十、signedunsigned

C语言使用signedunsigned关键字修饰字符型整型类型。
signed关键字表示一个类型带有正负号,包含负值。
unsigned关键字表示一个类型不带有正负号,只能表示零和正整数。
对于int类型,默认是带有正负号的,即int等同于signed intint类型也可以不带正负号,只表示非负整数,这时就必须使用unsigned关键字声明变量,unsigned int里的int也可以省略。

signed int a;//等同于int a;
unsigned int a;//等同于unsigned a;

整数变量声明为unsigned的好处是,同样长度的内存能表示的最大整数值增大了一倍。比如,16位(短整型2个字节,就是16个bit位,即16位)的signed short int的取值范围是:-32768~32767,最大是32767;而unsigned short int的取值范围是:0~65535,最大值为65,535。定义变量并赋值的时候,不能超过范围,否则会发生错误:

#include <stdio.h>
int main()
{
	signed short int a = 50000;
	printf("%hd\n", a);
    return 0;
}

在这里插入图片描述

32位的signed int的取值范围可以查看limits.h中给出的定义。那么怎么查看limits.h呢?——运用工具Everything
下载官网:https://www.voidtools.com/zh-cn/downloads/
下载安装版64位
在这里插入图片描述
下载后打开在搜索栏中输入limits.h,找到后拖拽到VS中即可。
在这里插入图片描述
下面是VS2022环境中,limits.h中相关的部分定义。

#define SHRT_MIN    (-32768)//有符号16位整型的最小值
#define SHRT_MAX      32767//有符号16位整型的最大值
#define USHRT_MAX     0xffff//无符号16位整型的最大值
#define INT_MIN     (-2147483647 - 1)//有符号32位整型的最小值
#define INT_MAX       2147483647//有符号32位整型的最大值

字符类型char也可以设置为signedunsignedchar有可能是signed char,也可能是unsigned char,这一点与int不同。

signed char c;//范围-128到127
unsigned char c;//范围0到255

若要查看不同数据类型的取值范围——运用工具Everything
limits.h这个头文件中说明了整型类型的取值范围。
float.h这个头文件中说明了浮点型类型的取值范围。

十一、变量

1.变量的创建

数据类型是用来创建变量的。C语言中把经常变化的值称为变量,不变的值称为常量
变量创建的语法:

data_type name;//data_type:数据类型     name:变量名


1.变量名要有意义
2.变量名只能由字母、数字、下划线组成且数字不能是开头
3.变量名不能是关键字

例如:

int age;//整型变量
char ch;//字符变量
double weight;//浮点型变量

变量在创建的时候给一个初始值,就叫初始化,例如:

int age=18;
char ch='z';
double weight=50.0;
unsigned int height = 168;

2.变量的分类

全局变量:在大括号外部定义的变量就是全局变量。全局变量使用范围广,在整个工程中都能使用。
局部变量:在大括号内部定义的变量就是局部变量。局部变量使用范围较局限,只能在自己所在的局部范围内使用。

#include <stdio.h>
int a = 10;//全局变量
int main()
{
	printf("a=%d\n", a);
	int b = 20;//局部变量
	printf("b=%d\n", b);
	return 0;
}
#include <stdio.h>
int a = 10;
int main()
{
	int b = 20;
	{
		int c = 100;
		printf("a=%d b=%d c=%d\n", a, b, c);
	}
	printf("a=%d b=%d \n", a, b);
    return 0;
}

若代码是下面示例中的,就会发生错误:

#include <stdio.h>
int a = 10;
int main()
{
	int b = 20;
	{
		int c = 100;
		printf("a=%d b=%d c=%d\n", a, b, c);
	}
	printf("a=%d b=%d c=%d\n", a, b,c);
    return 0;
}

在这里插入图片描述

全局变量和局部变量同名时,局部变量优先使用。

#include <stdio.h>
int n = 100;
int main()
{
	int n = 1000;
	printf("%d\n", n);
	return 0;
}

在这里插入图片描述
全局变量和局部变量在内存(电脑上有内存,内存是用来存放数据的,创建变量的本质就是在内存中申请了一块空间。)中存储在哪⾥呢?
⼀般我们在学习C/C++语⾔的时候,我们会关注
内存中的三个区域:栈区、堆区、静态区。

  1. 局部变量是放在内存的栈区
  2. 全局变量是放在内存的静态区
  3. 堆区是⽤来动态内存管理的(后期会介绍)
    其实内存区域的划分会更加细致,以后在操作系
    统的相关知识的时候会介绍。
    在这里插入图片描述

十二、操作符/运算符

操作符也被叫做运算符,翻译不同,但意思是一样的。

1.算术操作符:+、-、*、/、%

这些算术操作符也被叫做双目操作符。双目操作符:有两个操作数的操作符,例如:34+55, 34为左操作数,55为右操作数。

(1)+-

+-用来完成加法和减法。

#include <stdio.h>
int main()
{
	printf("%d\n", 13 + 3 + 1);//17
	int x = 13;
	int y = 3;
	int z = 1;
	int a = 13 + 4;
	printf("%d\n", a);//17
	printf("%d\n", x + y);//16
	printf("%d\n", x + 4);//17
	printf("%d\n", x - y);//10
	printf("%d\n", a - 34);//-17
	return 0;
}

(2)*

*用来完成乘法。

#include <stdio.h>
int main()
{
	int num = 5;
	printf("%d\n", num * num);//25
	printf("%d\n", 3 * 5);//15
    return 0;
}

(3)/

/用来完成除法。
除号的两端如果是整数,执⾏的是整数除法,得到的结果也是整数。如果希望得到浮点数的结果,两个运算数必须⾄少有⼀个浮点数。

#include <stdio.h>
int main()
{
	int a = 6 / 4;
	float b = 6 / 4; 
	float c = 6.0 / 4;
	float d = 6 / 4.0;
    printf("b=%f a=%d\n",b,a);
	printf("d=%f c=%lf\n",d,c);
    return 0;
}

在这里插入图片描述
上示例中,尽管变量bfloat,但是6/4的结果不是1.5,原因在于C语言中的整数除法是整除,只会返回整数部分,丢弃小数部分。

再看一个例子:

#include <stdio.h>
int main()
{
	int score = 20;
	printf("score=%d\n", (score/ 100) * 100);
	printf("score=%.0f\n", (score / 100.0) * 100);
	printf("score=%d\n", (score / 100.0) * 100);//类型结果与占位符不匹配,所以为0
	return 0;
}

在这里插入图片描述
再来一个示例:

#include <stdio.h>
int main()
{
	float score = 5;
	score = (score / 20.0f) * 100;
	printf("%f\n", score);//25.000000
	return 0;
}

(4)%

%用来完成求模(余),即返回两个整数相除的余数。该运算符只能用于整数,不能用于浮点数。

#include <stdio.h>
int main()
{
	int a = 17 % 13;
	int b = 17.0 % 13;
	printf("%d\n", a);//4
	printf("%d\n", b);//err
	return 0;
}

负数求模的规则是,结果的正负号由第⼀个运算数的正负号决定。

#include <stdio.h>
int main()
{
	int a = -11 % 7;
	int b = 11 % -7;
	int c = -11 % -7;
	printf("%d\n", a);//-4
	printf("%d\n", b);//4
	printf("%d\n", c);//-4
	printf("%d\n", -11 % 7);//-4
	printf("%d\n", -11 % -7);//-4
	printf("%d\n", 11 % -7);//4
	return 0;
}

2.赋值操作符:=和复合赋值

赋值操作符也是双目操作符。
赋值:在变量创建的时候给⼀个初始值叫初始化,在变量创建好后,再给⼀个值,这叫赋值。

(1)赋值操作符=

#include <stdio.h>
int main()
{
    int a = 10;//初始化
	a = 20;//赋值
	return 0;
}

赋值操作符也可以连续赋值,但写出的代码不容易理解,建议还是拆开来写。

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int c = 0;
	printf("c=%d\n", c = b = a + 20);//c=30。连续赋值,从右到左依次赋值。
	return 0;
}
#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int c = 0;
	printf("b=%d\n", b = a + 20);//b=30
	printf("c=%d\n", c = b);//c=30
	return 0;
}

(2)复合赋值操作符:+=-=*=/=%=

还有一些复合赋值操作符后面会讲解:>>=<<=&=|=^=
在写代码时,我们经常可能对⼀个数进行自增、自减等操作,例如:

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

在这里插入图片描述
其实有更简便的写法:

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

(3)单目操作符:++--+(正号)、-(负号)

单目操作符:只有一个操作数的操作符。

a.++--

++是一种自增的操作符,分为前置++和后置++;--是一种自减的操作符,分为前置- -和后置- -。
前置++:操作符++在操作数前面,计算口诀为先+1,后使用。

#include <stdio.h>
int main()
{
	int a = 5;
	int b = ++a;
	printf("a=%d b=%d\n", a, b);
	return 0;
}

在这里插入图片描述
再来一个示例,理解更深刻一些:

#include <stdio.h>
int main()
{
	int a = 5;
	printf("a=%d\n", ++a);
	printf("a=%d\n", a);
	return 0;
}

在这里插入图片描述

后置++:操作符++在操作数后面,计算口诀为先使用,后+1。

#include <stdio.h>
int main()
{
	int a = 5;
	int b = a++;
	printf("a=%d b=%d\n", a, b);
	return 0;
}

在这里插入图片描述
**前置- -后置- -**同理,不过是把+1换成了-1。
前置- -:先-1,后使用。

#include <stdio.h>
int main()
{
	int a = 5;
	int b = --a;
	printf("a=%d b=%d\n", a, b);
	return 0;
}

在这里插入图片描述
后置- -:先使用,后-1。

#include <stdio.h>
int main()
{
	int a = 5;
	int b = a--;
	printf("a=%d b=%d\n", a, b);
	return 0;
}

在这里插入图片描述

b.+(正号)和-(负号)

运算符+对正负值没有影响,是⼀个完全可以省略的运算符,但是写了也不会报错。

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

在这里插入图片描述
运算符-⽤来改变⼀个值的正负号,负数的前面加上-会得到正数,正数的前面加上-会得到负数。

#include <stdio.h>
int main()
{
	int a = 5;
	int b = -5;
	printf("a=%d b=%d\n", -a,-b);
	return 0;
}

在这里插入图片描述

(4)强制类型转换操作符

语法:

(数据类型)

例如:

int main()
{
	int a = 3.14//a是int类型,3.14是double类型,两边类型不一样,编译器会报警告。至于3.14为什么是double类型而不是float类型,后面的占位符中会讲解。
    return 0;
}

为了消除这个警告,可以使用强制类型转换:

int main()
{
	int a =(int)3.14;
//将3.14强制类型转换为int类型,3.14只取整数部分。
	return 0;
}

使用强制类型转换都是万不得已的时候用,如果不用强制类型转换就能实现代码,那自然是更好的。

十三、printf()函数和scanf()函数的介绍

printf()函数和scanf()函数都是在标准库的头⽂件stdio.h定义的。使⽤这两个函数之前,必须在源码⽂件头部引⼊这个头⽂件。参数与参数之间用逗号隔开:printf(参数1,参数2,......,参数n)scanf(参数1,参数2,......,参数n)

1.printf()函数

(1)基本用法

printf = print(打印) format(格式化),表示按照格式打印信息到屏幕上:

#include <stdio.h>
int main()
{
	printf("hello world");//输出:hello world
	return 0;
}

printf()运行结束后,光标就停留在输出结束的地方,不会自动换行。为了让光标移到下一行的开头,在输出文本的结尾添加一个换行符\n

#include <stdio.h>
int main()
{
	printf("hello world\n");
	return 0;
}

若文本内部有换行,可以通过添加换行符来实现:

#include <stdio.h>
int main()
{
	printf("hello\nworld\n");
	
	printf("hello\n");
	printf("world\n");
	
	printf("hello");
	printf("\n");
	printf("world");
	return 0;
}

(2)占位符

占位符:占位符所在位置被替换成其他数据。
占位符的第一个字符一律为百分号%,第二个字符表示占位符的类型。替换的参数与被替换的占位符的数据类型要对应上。例:

#include <stdio.h>
int main()
{
	printf("There are %d apples.\n", 3);//输出:There are 3 apples.
	return 0;
}

上述示例中,参数3就替换掉了占位符%d
%s表示替换的是字符串:

#include <stdio.h>
int main()
{
	printf("%s will come tonight.\n", "JJlin");//输出:JJlin will come tonight.
	return 0;
}

printf()输出文本里可以有多个占位符,参数与占位符是一 一对应的关系 ,printf()若有n个占位符,那么参数就有n+1个:

#include <stdio.h>
int main()
{
	printf("%s says it is %d o'clock.\n", "Jun",17);//输出:Jun says it is 17 o'clock.
	return 0;
}

如果参数个数少于对应的占位符,printf()会输出内存中的任意值:

#include <stdio.h>
int main()
{
	printf("%s says it is %d o'clock.\n", "Jun");//输出:Jun says it is 1311835392 o'clock.
	return 0;
}

(3)常见的占位符

%c :字符。//char
%d:有符号的十进制整数。//int
%f:小数(包含float类型和double类型)//float-%f ,double-%lf
补充:float和double类型打印的时候小数点后都默认打印六位。
浮点数范围小,精度要求低:float;浮点数范围大,精度要求高:double。
直接写出的字面浮点数会被编译器直接识别为double类型(0.0默认是double类型),浮点数后加个f为float类型(0.0f是float类型):

#include <stdio.h>

int main()
{
	3.14;//double
	3.22f;//float
	return 0;
}

%hd:十进制short int类型。
%hu:unsigned short int类型。
%ld:十进制long int类型。
%lu:unsigned long int类型。
%Lf:long double类型浮点数。
%p:指针(用来打印地址)。
%s:字符串。
%u:无符号整数类型。//unsigned int
%x:十六进制整数。
%zdsize_t类型。

(4)占位符的输出格式

a.限定最小宽度占位符

printf() 函数限定占位符的最小宽度。若参数宽度不超过限定宽度,则默认右对齐全部输出,宽度不够空格补齐:

#include <stdio.h>
int main()
{
	printf("%6d\n", 123);//输出:”   123“
	return 0;
}

若想左对齐输出,则在占位符的%后面加一个符号-,同理,空格补齐:

#include <stdio.h>
int main()
{
	printf("%-6d", 123);//输出:”123   “ 
	return 0;
}

按照实际内容输出有两种情况:1.若参数宽度大于该限定宽度,则按照实际情况输出。2.不限定占位符的宽度。例:

#include <stdio.h>
int main()
{
	printf("%d\n", 123);//输出:“123”
	
	printf("%5d\n", 1654651);//输出:“1654651”
	return 0;
}

对于小数,这个占位符会限定所有数字的最小宽度,一个小数点也占一个宽度:

#include <stdio.h>
int main()
{
	printf("%12f\n", 123.45);//输出:“  123.450000”
	return 0;
}
b.总是带有正负号占位符

printf()默认对负数输出-号,对正数不会输出+号:

#include <stdio.h>
int main()
{
	int a = +10;
	int b = -10;
	printf("a=%d\nb=%d\n", a,b);//输出:a=10 b=-10
	return 0;
}

占位符的%后面加个+可以确保输出的数值总是带有正负号的。

#include <stdio.h>
int main()
{
	int a = +10;
	int b = -10;
	printf("a=%+d\nb=%+d\n", a, b);//输出:a=+10 b=-10
	return 0;
}
c.限定小数位数占位符

举例来说,希望保留小数点后两位,占位符就写成%.2f:
(补充一点,保留时遵循四舍五入)

#include <stdio.h>
int main()
{
    printf("%.2f\n",3.1415);//输出:3.14
    return 0;
}

若保留小数点后三位,占位符写成%.3f:

#include <stdio.h>
int main()
{
	printf("%.3f\n", 3.1415);//输出:3.142
	return 0;
}
d.限定小数位数占位符与限定宽度占位符的结合使用

示例1:

#include <stdio.h>
int main()
{
	printf("%7.2f\n", 3.145);//输出:“   3.15”
	return 0;
}

示例2:

#include <stdio.h>
int main()
{
	printf("%7.2f\n", 314159.265);//输出:“314159.27”
    return 0;
}

最小宽度和小数位数这两个限定值都可以用*代替,通过printf()的参数传入:

#include <stdio.h>
int main()
{
	printf("%*.*f\n", 7, 2, 3.145);//输出:“   3.15”
	return 0;
}
e.输出部分字符串占位符

占位符%s⽤来输出字符串,默认是全部输出。若想输出字符串的前几个字符,用%.[m]s ,其中[m]代表⼀个数字,表⽰要输出的⻓度。

#include <stdio.h>
int main()
{
   printf("%.6s\n", "hello world");//输出“hello ”
   return 0;
}

上述示例中,%.6s 表示输出字符串“hello world”的前6个字符,即“hello ”。

2.scanf()函数

(1)基本用法

使用前,在scanf()函数的.c文件的第一行加上#define _CRT_SECURE_NO_WARNINGS 1
注意:只能是在第一行!

#define _CRT_SECURE_NO_WARNINGS 1

但是,每次新建.c文件时都要写上这一句代码会稍微麻烦点,也有一劳永逸的解决办法:在VS上新建.c/.cpp文件的时候,其实拷贝的是newc++file.cpp这个文件,那么在这个文件中加上上述代码即可,以后新建的.c/.cpp文件中都会包含这句代码。

具体操作过程如下:在everything工具中搜索newc++file.cpp,右击打开路径。
在这里插入图片描述
找到该文件后,右击选择在记事本中编辑,最后把#define _CRT_SECURE_NO_WARNINGS 1拷贝到记事本中保存即可。或者把该文件拷贝到桌面上,在记事本编辑保存后再拷贝回路径中。
在这里插入图片描述

scanf()函数用于读取用户通过键盘输入的数据,输入后,按下回车,会将数据存入变量中。

#include <stdio.h>
int main()
{
	int i = 0;
	scanf("%d", &i);
	return 0;
}

注意:变量前必须加上取地址符号&(除了指针变量,例如字符串变量),因为变量传递的不是值,而是地址,即将变量的地址指向用户输入的数据。

下面是一次性输入多个数据的例子:

#include <stdio.h>
int main()
{
	int j,i;
	float y, x;
	scanf("%d%d%f%f", &j, &i, &y, &x);
	printf("j=%d,i=%d,y=%f,x=%f\n", j, i, y, x);
    return 0;
}

scanf()处理数值占位符时,会⾃动过滤空⽩字符,包括空格、制表符、换⾏符等。所以,⽤⼾输⼊的数据之间,有⼀个或多个空格不影响scanf()解读数据,补充一点,数据之间不要没有空格,不然识别不出。例如,上述代码,用户输入两个整数为20和23,两个小数为45.5和4.3e12(科学计数法的浮点数格式,等同于4.3*10的12次方),但是20和23之间没有用空格间隔开,则输出内容为:

2023 45.5 4.3e12
j=2023,i=45,y=0.500000,x=4299999936512.000000

用户使用回车键,将输入分成几行,也不影响解读:

20
23
45.5
4.3e12
j=20,i=23,y=45.500000,x=4299999936512.000000

再给出一个示例,加深对scanf()处理数值占位符时,会自动过滤空白字符的理解:

#include <stdio.h>
int main()
{
	int x;
	float y;
	scanf("%d", &x);
	printf("x=%d\n", x);
	scanf("%f", &y);
	printf("y=%f\n", y);
	return 0;
}
    -12.45e12$
x=-12
y=449999994880.000000

上述代码还可写成:

#include <stdio.h>
int main()
{
	int x;
	float y;
	scanf("%d%f", &x, &y);
	printf("x=%d\ny=%f\n", x, y);
	return 0;
}

(2)scanf()函数的返回值

scanf() 的返回值是⼀个整数,表示成功读取的变量个数。
如果没有读取任何项,或者匹配失败,则返回0。
如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量EOF(-1)。
EOF - end of file 文件结束标志
下面给出一个示例,演示scanf()函数的返回值的几种情况:

#include <stdio.h>
int main()
{
	int a=0;
	int b=0;
	float f=0.0f;
	int r = scanf("%d%d%f", &a, &b, &f);
	printf("a=%d,b=%d,f=%f\n", a, b, f);
	printf("r=%d\n", r);
	return 0;
}

a:成功读取所有变量

20 23 4.5
a=20,b=23,f=4.500000
r=3

b:匹配失败

#
a=0,b=0,f=0.000000
r=0

c:输入数值后,再输入两次ctrl+z,提前结束输入

20 21
^Z
^Z
a=20,b=21,f=0.000000
r=2
20
^Z
^Z
a=20,b=0,f=0.000000
r=1

d:在VS环境中什么都不输入,直接输入三次ctrl+z,输出的r=-1,也就是EOF。

^Z
^Z
^Z
a=0,b=0,f=0.000000
r=-1

(3)占位符

scanf()函数常用的占位符与printf()函数的基本一致。
%[]:在方括号中指定一组匹配的字符,例如%[0-9],遇到不在集合之中的字符,匹配将会停止。

占位符中,除了%c都会自动忽略开头的空白字符。
演示占位符%d%f,会忽略开头的空白字符:

#include <stdio.h>
int main()
{
	int a=0;
	float b = 0.0f;
	scanf("%d %f", &a, &b);
	printf("a=%d\nb=%f\n", a, b);
	return 0;
}
     20 4.5
a=20
b=4.500000

演示占位符%c,不会忽略开头的空白字符:

#include <stdio.h>
int main()
{
	char c1 = 0;
	char c2 = 0;
	char c3 = 0;
	scanf("%c%c%c", &c1, &c2, &c3);
	printf("%c %c %c\n", c1, c2, c3);
	return 0;
}
abc
a b c
a b c
a   b
 abc
  a b

如果要强制跳过字符前的空白字符,可以在%c前加一个空格,表示跳过零个或多个空白字符:

#include <stdio.h>
int main()
{
	char c1 = 0;
	char c2 = 0;
	char c3 = 0;
	scanf(" %c%c%c", &c1, &c2, &c3);
	printf("%c %c %c\n", c1, c2, c3);
	return 0;
}
   abc
a b c

下面要特别说⼀下占位符%s,它其实不能简单地等同于字符串。它的规则是,从当前第⼀个非空白字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止。
因为%s不会包含空白字符,所以无法用来读取多个单词,除非多个%s⼀起使用:

#include <stdio.h>
int main()
{
	char name1[11] = { 0 };
	char name2[20] = { 0 };
	scanf("%s %s", name1,name2);
	printf("%s %s\n", name1,name2);
	return 0;
}
seventeen  bushiseventy
seventeen bushiseventy

另外,scanf()遇到占位符%s,会在字符串变量末尾存储一个空字符\0

scanf()将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串时,很可能会超过数组的边界。为了防止这种情况,使用占位符%s时,应该指定读入字符串的最长长度,即写成%[m]s,其中的[m]是⼀个整数,表示读取字符串的最大长度,后面的字符将被丢弃。

#include <stdio.h>
int main()
{
	char name[11] = {0};
	scanf("%10s", name);//数组名name就是地址
	printf("%s\n", name);
	return 0;
}
seventeenseventeen
seventeens

(4)赋值忽略符

有时,用户的输入可能不符合预定的格式。

#include <stdio.h>
int main()
{
	int year = 0;
	int month = 0;
	int day = 0;
	scanf("%d-%d-%d", &year, &month, &day);
	printf("%d-%d-%d\n", year, month, day);
	return 0;
}

按照预定输入格式输入,scanf()解析数据成功:

2024-10-3
2024-10-3

不按照预定输入格式输入,scanf()解析数据失败:

2024 10 3
2024-0-0

为了防止这种解析失败的情况,可以在占位符的%后面加一个赋值忽略符*。该占位符就不会返回值,解析后将被丢弃。
演示%*d

#include <stdio.h>
int main()
{
	int year = 0;
	int month = 0;
	int day = 0;
	scanf("%d%*d%d%*d%d", &year, &month, &day);
	printf("%d-%d-%d\n", year, month, day);
	return 0;
}
2024 4 10 5 3
2024-10-3

演示%*c

#include <stdio.h>
int main()
{
	int year = 0;
	int month = 0;
	int day = 0;
	scanf("%d%*c%d%*c%d", &year, &month, &day);
	printf("%d-%d-%d\n", year, month, day);
	return 0;
}
2024 10 3
2024-10-3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值