第2讲:C语言数据类型和变量

第2讲:C语言数据类型和变量

  • 目录
  • 1.数据类型介绍
    • 1.1字符型
    • 1.2整型
    • 1.3浮点型
    • 1.4 布尔类型
    • 1.5 各种数据类型的长度
      • 1.5.1 sizeof 操作符
      • 1.5.2 数据类型长度
      • 1.5.3 sizeof 中表达式不计算
  • 2.signed 和 unsigned
  • 3.数据类型的取值范围
  • 4. 变量
    • 4.1 变量的创建
    • 4.2 变量的分类
  • 5. 算术操作符:+、-、*、/、%
    • 5.1 + 和 -
    • 5.2 *
    • 5.3 /
    • 5.4 %
  • 6. 赋值操作符:= 和复合赋值
    • 6.1 连续赋值
    • 6.2 复合赋值符
  • 7. 单目操作符:++、--、+、-
    • 7.1 ++和--
      • 7.1.1 前置++
      • 7.1.2 后置++
      • 7.1.3 前置--
      • 7.1.4 后置--
      • 7.2 + 和 -
  • 8. 强制类型转换
  • 9. scanf和printf介绍
    • 9.1 printf
      • 9.1.1 基本用法
      • 9.1.2 占位符
      • 9.1.3 占位符列举
      • 9.1.4 输出格式
        • 9.1.4.1 限定宽度
        • 9.1.4.2 总是显示正负号
        • 9.1.4.3 限定数位数小
        • 9.1.4.4 输出部分字符串
    • 9.2 scanf
      • 9.2.1 基本用法
  • 不属于浮点数的有效字符,所以会停在这⾥。
      • 9.2.2 scanf的返回值
      • 9.2.2 scanf的返回值
      • 9.2.4 赋值忽略符

目录

1.数据类型介绍

C语言提供了丰富的数据类型来描述生活中的各种数据。
使用整型类型来描述整数,使用字符类型来描述字符,使用浮点型类型来描述小数。
所谓“类型”,就是相似的数据所拥有的共同特征,编译器只有知道了数据的类型,才知道怎么操作数据。
下面盘点⼀下C语言提供的各种数据类型.
在这里插入图片描述

1.1字符型


char //character
[signed] char //有符号的
unsigned char //⽆符号的

1.2整型

//短整型
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]

1.3浮点型

float
double
long double

1.4 布尔类型

C 语言原来并没有为布尔值单独设置⼀个类型,而是使用整数 0 表示假,非零值表示真。
在 C99 中也引入了 布尔类型 ,是专门表示真假的。

1 _Bool

布尔类型的使用得包含头文件 <stdbool.h>
布尔类型变量的取值是:true 或 false

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

代码演示:

_Bool flag = true;
if (flag)printf("i like C\n");

1.5 各种数据类型的长度

每⼀种数据类型都有自己的长度,使用不同的数据类型,能够创建出长度不同的变量,变量长度的不同,存储的数据范围就有所差异。

1.5.1 sizeof 操作符

sizeof 是⼀个关键字,也是操作符,专门是用来计算sizeof的操作符数的类型长度的,单位是字节。
sizeof 操作符的操作数可以是类型,也可是变量或者表达式


sizeof( 类型 )
sizeof 表达式

sizeof 的操作数如果不是类型,是表达式的时候,可以省略掉后边的括号的。
sizeof 后边的表达式是不真实参与运算的,根据表达式的类型来得出大小。
sizeof 的计算结果是 size_t 类型的。

注意:sizeof 运算符的返回值,C 语言只规定是无符号整数,并没有规定具体的类型,而是留给系统自己去决定, sizeof 到底返回什么类型。不同的系统中,返回值的类型有可能是unsigned int ,也有可能是 unsigned long ,甚至是 unsigned long long 对应的 printf() 占位符分别是 %u 、 %lu 和 %llu 。这样不利于程序的可移植性。
C 语言提供了⼀个解决方法,创造了⼀个类型别名 size_t ,用来统⼀表示 sizeof 的返回值类型。对应当前系统的 sizeof 的返回值类型,可能是 unsigned int ,也可能是unsigned long long 。
比如:

#include <stdio.h>
int main()
{int a = 10;printf("%zd\n", sizeof(a));printf("%zd\n", sizeof a);//a是变量的名字,可以省略掉sizeof后边的()printf("%zd\n", sizeof(int));printf("%zd\n", sizeof(3 + 3.5));return 0;
}

1.5.2 数据类型长度

#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;
}

在VS2022 X64配置下的输出:

1
1
2
4
4
8
4
8
8

1.5.3 sizeof 中表达式不计算

//测试:sizeof中表达式不计算
#include <stdio.h>
int main()
{short s = 2;int b = 10;printf("%d\n", sizeof(s = b+1));printf("s = %d\n", s);return 0;
}

sizeof 在代码进行编译的时候,就根据表达式的类型确定了,类型的常用,而表达式的执行却要在程序运行期间才能执行,在编译期间已经将sizeof处理掉了,所以在运行期间就不会执行表达式了。

2.signed 和 unsigned

C 语言使用 signed 和 unsigned 关键字修饰 字符型和整型类型的。
signed 关键字,表示⼀个类型带有正负号,包含负值;
unsigned 关键字,表示该类型不带有正负号,只能表示零和正整数。
对于 int 类型,默认是带有正负号的,也就是说 int 等同于 signed int 。
由于这是默认情况,关键字 signed一般都省略不写,但是写了也不算错。

1 signed int a;
2 // 等同于int a;

int 类型也可以不带正负号,只表示非负整数。这时就必须使用关键字 unsigned 声明变量。

unsigned int a;

整数变量声明为 unsigned 的好处是,同样长度的内存能够表示的最大整数值,增大了⼀倍。
比如,16位的 signed short int 的取值范围是:-32768~32767,最大是32767;
而unsigned short int 的取值范围是:0~65535,最大值增大到了65,535。
32位的 signed int 的取值范围可以参看 limits.h 中给出的定义。

下面的定义是VS2022环境中,limits.h中相关定义。

1.#define SHRT_MIN (-32768) //有符号16位整型的最⼩值
2 #define SHRT_MAX 32767 //有符号16位整型的最⼤值
3 #define USHRT_MAX 0xffff //⽆符号16位整型的最⼤值
4 #define INT_MIN (-2147483647 - 1) //有符号整型的最⼩值
5 #define INT_MAX 2147483647 //有符号整型的最⼤值

unsigned int 里面的 int 可以省略,所以上面的变量声明也可以写成下面这样。

 unsigned a;

字符类型 char 也可以设置 signed 和 unsigned 。


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

注意,C 语言规定 char 类型默认是否带有正负号,由当前系统决定。
这就是说, char 不等同于 signed char ,它有可能是 signed char ,也有可能是
unsigned char 。
这⼀点与 int 不同, int 就是等同于 signed int 。

3.数据类型的取值范围

上述的数据类型很多,尤其数整型类型就有short、int、long、long long 四种,为什么呢?
其实每⼀种数据类型有自己的取值范围,也就是存储的数值的最大值和最小值的区间,有了丰富的类型,我们就可以在适当的场景下去选择适合的类型。如果要查看当前系统上不同数据类型的极限值:
limits.h 文件中说明了整型类型的取值范围。
float.h 这个头文件中说明浮点型类型的取值范围。
为了代码的可移植性,需要知道某种整数类型的极限值时,应该尽量使用这些常量。
• SCHAR_MIN , SCHAR_MAX :signed char 的最小值和最大值。
• SHRT_MIN , SHRT_MAX :short 的最小值和最大值。
• INT_MIN , INT_MAX :int 的最小值和最大值。
• LONG_MIN , LONG_MAX :long 的最小值和最大值。
• LLONG_MIN , LLONG_MAX :long long 的最小值和最大值。
• UCHAR_MAX :unsigned char 的最大。
• USHRT_MAX :unsigned short 的最大值。
• UINT_MAX :unsigned int 的最大值。
• ULONG_MAX :unsigned long 的最大值。
• ULLONG_MAX :unsigned long long 的最大值。

4. 变量

4.1 变量的创建

了解清楚了类型,我们使用类型做什么呢?类型是用来创建变量的。
什么是变量呢?C语言中把经常变化的值称为变量,不变的值称为常量。
变量创建的语法形式是这样的:

data_type name;| || |
数据类型 变量名
int age; //整型变量
char ch; //字符变量
double weight; //浮点型变量

变量在创建的时候就给⼀个初始值,就叫初始化。

int age = 18;
char ch = 'w';
double weight = 48.0;
unsigned int height = 100;

4.2 变量的分类

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

#include <stdio.h>
int global = 2023;//全局变量
int main()
{int local = 2018;//局部变量printf("%d\n", local);printf("%d\n", global);return 0;
}

如果局部和全局变量,名字相同呢?

#include <stdio.h>
int n = 1000;
int main()
{int n = 10;printf("%d\n" n);//打印的结果是多少呢?return 0;
}

其实当局部变量和全局变量同名的时候,局部变量优先使用

全局变量和局部变量在内存中存储在哪里呢?
⼀般我们在学习C/C++语⾔的时候,我们会关注
内存中的三个区域:栈区、堆区、静态区。

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

在这里插入图片描述

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

在写代码时候,⼀定会涉及到计算。
C语言中为了方便运算,提供了⼀系列操作符,其中有⼀组操作符叫:算术操作符。分别是: + - *
/ % ,这些操作符都是双目操作符。
注:操作符也被叫做:运算符,是不同的翻译,意思是⼀样的。

5.1 + 和 -

  • + 和 -用来完成加法和减法。
    
  •  +和 - 都是有2个操作数的,位于操作符两端的就是它们的操作数,这种操作符也叫双目操作符。
    
#include <stdio.h>
int main()
{int x = 4 + 22;int y = 61 - 23;printf("%d\n", x);printf("%d\n", y);return 0;
}

5.2 *

运算符 * 用来完成乘法。

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

5.3 /

运算符 / 用来完成除法。
除号的两端如果是整数,执行的是整数除法,得到的结果也是整数。

#include <stdio.h>
int main()
{float x = 6 / 4;int y = 6 / 4;printf("%f\n", x); // 输出 1.000000printf("%d\n", y); // 输出 1return 0;
}

上面示例中,尽管变量 x 的类型是 float (浮点数),但是 6 / 4 得到的结果是 1.0 ,而不是1.5 。原因就在于 C 语言里面的整数除法是整除,只会返回整数部分,丢弃小数部分。

如果希望得到浮点数的结果,两个运算数必须至少有⼀个浮点数,这时 C 语言就会进行浮点数除法。

#include <stdio.h>
int main()
{float x = 6.0 / 4; // 或者写成 6 / 4.0printf("%f\n", x); // 输出 1.500000return 0;
}

上面示例中, 6.0 / 4 表示进行浮点数除法,得到的结果就是 1.5 。

再看⼀个例子:

#include <stdio.h>
int main()
{int score = 5;score = (score / 20) * 100;return 0;
}

上⾯的代码,你可能觉得经过运算, score 会等于 25 ,但是实际上 score 等于 0 。这是因为score / 20 是整除,会得到⼀个整数值 0 ,所以乘以 100 后得到的也是 0 。
为了得到预想的结果,可以将除数 20 改成 20.0 ,让整除变成浮点数除法。

#include <stdio.h>
int main()
{int score = 5;score = (score / 20.0) * 100;return 0;
}

5.4 %

运算符 % 表示求模运算,即返回两个整数相除的余值。这个运算符只能用于整数,不能用于浮点数。

#include <stdio.h>
int main()
{int x = 6 % 4; // 2return 0;
}

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

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

上面示例中,第⼀个运算数的正负号( 11 或 -11 )决定了结果的正负号。

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

在变量创建的时候给⼀个初始值叫初始化,在变量创建好后,再给⼀个值,这叫赋值。

int a = 100;//初始化
a = 200;//赋值,这⾥使⽤的就是赋值操作符

赋值操作符 = 是⼀个随时可以给变量赋值的操作符。

6.1 连续赋值

赋值操作符也可以连续赋值,如:

1 int a = 3;
2 int b = 5;
3 int c = 0;
4 c = b = a+3;//连续赋值,从右向左依次赋值的。

C语言虽然支持这种连续赋值,但是写出的代码不容易理解,建议还是拆开来写,这样方便观察代码的执行细节。

1 int a = 3;
2 int b = 5;
3 int c = 0;
4 b = a+3;
5 c = b;

这样写,在调试的是,每⼀次赋值的细节都是可以很方便的观察的。

6.2 复合赋值符

在写代码时,我们经常可能对⼀个数进行增、自减的操作,如下代码:

1 int a = 10;
2 a = a+3;
3 a = a-2;

这样代码C语言给提供了更加方便的写法:

1 int a = 10;
2 a += 3;
3 a -= 2;

C语言中提供了复合赋值符,方便我们编写代码,这些赋值符有:

+= -=
*= /= %=
//下⾯的操作符后期讲解
>>= <<=
&= |= ^=

7. 单目操作符:++、–、+、-

前面介绍的操作符都是双目操作符,有2个操作数的。C语言中还有⼀些操作符只有⼀个操作数,被称
为单目操作符。 ++、–、+(正)、-(负) 就是单目操作符的。

7.1 ++和–

++是⼀种自增的操作符,又分为前置++和后置++,- - 是⼀种自减的操作符,也分为前置- -和后置- -.

7.1.1 前置++

int a = 10;
int b = ++a;//++的操作数是a,是放在a的前⾯的,就是前置++
printf("a=%d b=%d\n",a , b);

计算口诀:先+1,后使用;
a原来是10,先+1,后a变成了11,再使用就是赋值给b,b得到的也是11,所以计算技术后,a和b都是11,相当于这样的代码

int a = 10;
a = a+1;
b = a;
printf("a=%d b=%d\n",a , b);

7.1.2 后置++

int a = 10;
int b = a++;//++的操作数是a,是放在a的后⾯的,就是后置++
printf("a=%d b=%d\n",a , b);

计算⼝诀:先使用,后+1
a原来是10,先使用,就是先赋值给b,b得到了10,然后再+1,然后a变成了11,所以直接结束后a是11,b是10,相当于这样的代码:

int a = 10;
int b = a;
a = a+1;
printf("a=%d b=%d\n",a , b);

7.1.3 前置–

如果你听懂了前置++,那前置–是同理的,只是把加1,换成了减1;
计算口诀:先-1,后使用

int a = 10;
int b = --a;//--的操作数是a,是放在a的前⾯的,就是前置--
printf("a=%d b=%d\n",a , b);//输出的结果是9 10

7.1.4 后置–

同理后置–类似于后置++,只是把加⼀换成了减⼀
计算口诀:先使用,后-1

int a = 10;
int b = a--;//--的操作数是a,是放在a的后⾯的,就是后置--
printf("a=%d b=%d\n",a , b);//输出的结果是:9 10

7.2 + 和 -

这⾥的+是正号,-是负号,都是单目操作符。
运算符 + 对正负值没有影响,是⼀个完全可以省略的运算符,但是写了也不会报错。

int a = +10; 等价于 int a = 10;

运算符 -用来改变⼀个值的正负号,负数的前面加上 - 就会得到正数,正数的前面加上 - 会得到负数。

int a = 10;
int b = -a;
int c = -10;
printf("b=%d c=%d\n", b, c);//这⾥的b和c都是-10
int a = -10;
int b = -a;
printf("b=%d\n", b);

8. 强制类型转换

在操作符中还有⼀种特殊的操作符是强制类型转换,语法形式很简单,形式如下:

        1 (类型)

请看代码:

int a = 3.14;
//a的是int类型, 3.14是double类型,两边的类型不⼀致,编译器会报警告

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

int a = (int)3.14;//意思是将3.14强制类型转换为int类型,这种强制类型转换只取整数部分

俗话说,强扭的瓜不甜,我们使用强制类型转换都是万不得已的时候使用,如果不需要强制类型转化就能实现代码,这样自然更好的。

9. scanf和printf介绍

9.1 printf

9.1.1 基本用法

printf() 的作用是将参数文本输出到屏幕。它名字里面的 f 代表 format (格式化),表示可以定制输出文本的格式。

#include <stdio.h>
int main(void) 
{printf("Hello World");return 0;
}

上面命令会在屏幕上输出一行文字“Hello World”。
printf() 不会在行尾自动添加换行符,运行结束后,光标就停留在输出结束的地方,不会自动换行。文本的结尾,添加⼀个换行符 \n 。

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

如果文本内部有换行,也是通过插入换行符来实现,如下方代码:

#include <stdio.h>
int main(void) 
{printf("Hello\nWorld\n");printf("Hello\n");printf("World\n");return 0;
}

printf() 是在标准库的头文件 stdio.h 定义的。使用这个函数之前,必须在源码文件头部引入这个头文件。

9.1.2 占位符

printf() 可以在输出文本中指定占位符。
所谓 “占位符”,就是这个位置可以用其他值代入。

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

上面示例中, There are %d apples\n 是输出文本,里面的 %d 就是占位符,表示这个位置要用其他值来替换。占位符的第⼀个字符⼀律为百分号 % ,第二个字符表示占位符的类型 %d 表示这
里代入的值必须是⼀个整数。
printf() 的第二个参数就是替换占位符的值,上面的例子是整数 3 替换 %d 。执行后的输出结果就是 There are 3 apples 。
常用的占位符除了 %d ,还有 %s 表示代入的是字符串。

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

上面示例中, %s 表示代入的是⼀个字符串,所以 printf() 的第二个参数就必须是字符串,这个例子是 zhangsan 。执行后的输出就是 zhangsan will come tonight 。
输出文本里面可以使用多个占位符。

#include <stdio.h>
int main()
{printf("%s says it is %d o'clock\n", "lisi", 21);return 0;
}

上面示例中,输出文本 %s says it is %d o’clock 有两个占位符,第⼀个是字符串占位符 %s ,第二个是整数占位符 %d ,分别对应 printf() 的第二个参数( lisi )和第三个参数( 21 )。执行后的输出就是 lisi says it is 21 o’clock 。

printf() 参数与占位符是⼀⼀对应关系,如果有 n 个占位符, printf() 的参数就应该有 n + 1 个。如果参数个数少于对应的占位符, printf() 可能会输出内存中的任意值。

9.1.3 占位符列举

printf() 的占位符有许多种类,与 C 语言的数据类型相对应。下面按照字母顺序,列出常用的占位符,方便查找,具体含义在后⾯章节介绍。
• %a :十六进制浮点数,字母输出为小写。
• %A :十六进制浮点数,字母输出为大写。
• %c :字符。
• %d :十进制整数。
• %e :使用科学计数法的浮点数,指数部分的 e 为小写。
• %E :使用科学计数法的浮点数,指数部分的 E 为大写。
• %i :整数,基本等同于 %d 。
• %f :小数(包含 float 类型和 double 类型)。
• %g :6个有效数字的浮点数。整数部分⼀旦超过6位,就会自动转为科学计数法,指数部分的 e
为小写。
• %G :等同于 %g ,唯⼀的区别是指数部分的 E 为大写。
• %hd :十进制 short int 类型。
• %ho :八进制 short int 类型。
• %hx :十六进制 short int 类型。
• %hu :unsigned short int 类型。
• %ld :十进制 long int 类型。
• %lo :八进制 long int 类型。
• %lx :十六进制 long int 类型。
• %lu :unsigned long int 类型。
• %lld :十进制 long long int 类型。
• %llo :八进制 long long int 类型。
• %llx :十六进制 long long int 类型。
• %llu :unsigned long long int 类型。
• %Le :科学计数法表示的 long double 类型浮点数。
• %Lf :long double 类型浮点数。
• %n :已输出的字符串数量。该占位符本身不输出,只将值存储在指定变量之中。
• %o :八进制整数。
• %p :指针。
• %s :字符串。
• %u :无符号整数(unsigned int)。
• %x :十六进制整数。
• %zd : size_t 类型。
• %% :输出⼀个百分号。

9.1.4 输出格式

printf() 可以定制占位符的输出格式。

9.1.4.1 限定宽度

printf() 允许限定占位符的最小宽度。

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

上面示例中, %5d 表示这个占位符的宽度至少为5位。如果不满5位,对应的值的前面会添加空格。
输出的值默认是右对齐,即输出内容前面会有空格;如果希望改成左对齐,在输出内容后面添加空格,可以在占位符的 % 的后面插入⼀个 - 号。

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

上面示例中,输出内容 123 的后面添加了空格。
对于小数,这个限定符会限制所有数字的最小显示宽度。

// 输出 " 123.450000"
#include <stdio.h>
int main()
{printf("%12f\n", 123.45);return 0;
}

上面示例中, %12f 表示输出的浮点数最少要占据12位。由于小数的默认显示精度是小数点后6位,
所以 123.45 输出结果的头部会添加2个空格。

9.1.4.2 总是显示正负号

默认情况下, printf() 不对正数显示 + 号,只对负数显示- 号。如果想让正数也输出 + 号,可以在占位符的 % 后⾯加⼀个 + 。

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

上面示例中, %+d 可以确保输出的数值,总是带有正负号。

9.1.4.3 限定数位数小

输出小数时,有时希望限定小数的位数。举例来说,希望小数点后面只保留两位,占位符可以写成 %.2f 。

// 输出 Number is 0.50
#include <stdio.h>
int main()
{printf("Number is %.2f\n", 0.5);return 0;
}

上面示例中,如果希望小数点后面输出3位( 0.500 ),占位符就要写成 %.3f 。
这种写法可以与限定宽度占位符,结合使用

// 输出为 " 0.50"
#include <stdio.h>
int main()
{printf("%6.2f\n", 0.5);return 0;
}

上面示例中, %6.2f 表示输出字符串最小宽度为6,小数位数为2。所以,输出字符串的头部有两个空格。
最小宽度和小数位数这两个限定值,都可以用 * 代替,通过 printf() 的参数传入。

#include <stdio.h>
int main()
{printf("%*.*f\n", 6, 2, 0.5);return 0;
}
// 等同于printf("%6.2f\n", 0.5);

上面示例中, %*.*f 的两个星号通过 printf() 的两个参数 6 和 2 传入。

9.1.4.4 输出部分字符串

%s 占位符用来输出字符串,默认是全部输出。如果只想输出开头的部分,可以用%.[m]s 指定输出
的长度,其中 [m] 代表⼀个数字,表示所要输出的长度。

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

上面示例中,占位符 %.5s 表示只输出字符串“hello world”的前5个字符,即“hello”。

9.2 scanf

当我们有了变量,我们需要给变量输入值就可以使用 scanf 函数,如果需要将变量的值输出在屏幕上的时候可以使用prinf 函数,下面看⼀个例子:

#include <stdio.h>
int main()
{int score = 0;printf("请输⼊成绩:");scanf("%d", &score);printf("成绩是:%d\n", score);return 0;
}

在这里插入图片描述
那接下来我们介绍⼀下 scanf 函数。

9.2.1 基本用法

scanf() 函数用于读取用户的键盘输入。
程序运行到这个语句时,会停下来,等待用户从键盘输入。
用户输⼊数据、按下回车键后, scanf() 就会处理用户的输入,将其存入变量。
它的原型定义在头文件 stdio.h 。
scanf() 的语法跟 printf() 类似

1 scanf("%d", &i);

它的第⼀个参数是⼀个格式字符串,里面会放置占位符(与 printf() 的占位符基本⼀致),告诉编译器如何解读用户的输入,需要提取的数据是什么类型。
这是因为 C 语言的数据都是有类型的, scanf() 必须提前知道用户输入的数据类型,才能处理数据。
它的其余参数就是存放用户输入的变量,格式字符串里面有多少个占位符,就有多少个变量。
上面示例中, scanf() 的第⼀个参数 %d ,表示用过户输入的应该是⼀个整数。 %d 就是⼀个占位符, % 是占位符的标志, d 表示整数。第⼆个参数 &i 表示,将用户从键盘输入的整数存入变量i 。

注意:变量前面必须加上 & 运算符(指针变量除外),因为 scanf() 传递的不是值,而是地址,
即将变量 i 的地址指向用户输入的值。
如果这里的变量是指针变量(比如字符串变量),那就不用加 & 运算符。

下面是⼀次将键盘输入读入多个变量的例子。

1 scanf("%d%d%f%f", &i, &j, &x, &y)

上面示例中,格式字符串 %d%d%f%f ,表示用户输入的前两个是整数,后两个是浮点数,比如 1 -20 3.4 -4.0e3 。这四个值依次放入 i 、 j 、 x 、 y 四个变量。
scanf() 处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。
所以,忽悠输入的数据之间,有⼀个或多个空格不影响 scanf() 解读数据。另外,用户使用回车键,将输入分成几行,也不影响解读。

1
-20
3.4
-4.0e3

上面示例中,用户分成四行输入,得到的结果与一行输入是完全⼀样的。每次按下回车键以后,scanf() 就会开始解读,如果第一行匹配第⼀个占位符,那么下次按下回车键时,就会从第二个占位符开始解读。
scanf() 处理用户输入的原理是用户的输入先放入缓存,等到按下回车键后,按照占位符对缓存进行解读。
解读用户输入时,会从上一次解读遗留的第⼀个字符开始,直到读完缓存,或者遇到第一个不符合条件的字符为止。

#include <stdio.h>
int main()
{int x;float y;// ⽤⼾输⼊ " -13.45e12# 0"scanf("%d", &x);printf("%d\n", x);scanf("%f", &y);printf("%f\n", y);return 0;
}

上面示例中, scanf() 读取用户输入时, %d 占位符会忽略起首的空格,从 - 处开始获取数据,读取到 -13 停下来,因为后面的 . 不属于整数的有效字符。这就是说,占位符 %d 会读到 -13 。
第二次调用 scanf() 时,就会从上⼀次停止解读的地方,继续往下读取。这⼀次读取的首字符是 . ,由于对应的占位符是 %f ,会读取到 .45e12 ,这是采用科学计数法的浮点数格式。后面的# 不属于浮点数的有效字符,所以会停在这里。
由于 scanf() 可以连续处理多个占位符,所以上面的例子也可以写成下面这样。

#include <stdio.h>
int main()
{int x;float y;// ⽤⼾输⼊ " -13.45e12# 0"scanf("%d%f", &x, &y);return 0;
}

不属于浮点数的有效字符,所以会停在这⾥。

由于 scanf() 可以连续处理多个占位符,所以上面的例子也可以写成下面这样。

9.2.2 scanf的返回值

scanf() 的返回值是⼀个整数,表示成功读取的变量个数。
如果没有读取任何项,或者匹配失败,则返回 0 。如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量 EOF

#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);}

输入输出测试:
在这里插入图片描述
如果输入2个数后,按 ctrl+z ,提前结束输入:
在这里插入图片描述
在VS环境中按3次 ctrl+z ,才结束了输入,我们可以看到r是2,表示正确读取了2个数值。
如果⼀个数字都不输如,直接按3次 ctrl+z ,输出的r是-1,也就是EOF
在这里插入图片描述

9.2.2 scanf的返回值

scanf() 常用的占位符如下,与 printf() 的占位符基本一致。
• %c :字符。
• %d :整数。
• %f : float 类型浮点数。
• %lf : double 类型浮点数。
• %Lf : long double 类型浮点数。
• %s :字符串。
• %[] :在方括号中指定⼀组匹配的字符(比如 %[0-9] ),遇到不在集合之中的字符,匹配将会
停止。
上面所有占位符之中,除了 %c 以外,都会自动忽略起首的空白字符。 %c 不忽略空白字符,总是返
回当前第⼀个字符,无论该字符是否为空格。
如果要强制跳过字符前的空败字符,可以写成 scanf(" %c", &ch) ,即 %c 前加上⼀个空格,表
示跳过零个或多个空白字符。
下面要特别说一下占位符 %s ,它其实不能简单地等同于字符串。它的规则是,从当前第⼀个非空白
字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止。
因为 %s 不会包含空白字符,所以无法用来读取多个单词,除非多个 %s ⼀起使用。这也意味着,
scanf() 不适合读取可能包含空格的字符串,比如书名或歌曲名。另外, scanf() 遇到 %s 占位
符,会在字符串变量末尾存储一个空字符 \0 。
scanf() 将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串时,很可能会超过数组的边界,导致预想不到的结果。为了防止这种情况,使用 %s 占位符时,应该指定读如字符串的最长长度,即写成 %[m]s ,其中的 [m] 是⼀个整数,表示读取字符串的最大长度,后面的字符将被丢弃。

#include <stdio.h>
int main()
{char name[11];scanf("%10s", name);return 0;
}

上面示例中, name 是⼀个长度为11的字符数组, scanf() 的占位符 %10s 表示最多读取用户输入
的10个字符,后面的字符将被丢弃,这样就不会有数组溢出的风险了。

9.2.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;
}

上面示例中,如果用户输入2020-01-01 ,就会正确解读出年、月、日。问题是用户可能输入其他
格式,比如 2020/01/01 ,这种情况下, scanf() 解析数据就会失败。
为了避免这种情况, scanf() 提供了⼀个赋值忽略符(assignment suppression character) * 。
只要把 * 加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃。

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

上面示例中, %*c 就是在占位符的百分号后面,加入了赋值忽略符 * ,表示这个占位符没有对应的
变量,解读后不必返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/698739.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

opencv判断二值的情况

目的 先说说理论&#xff1a; 什么叫图像的二值化&#xff1f;二值化就是让图像的像素点矩阵中的每个像素点的灰度值为0&#xff08;黑色&#xff09;或者255&#xff08;白色&#xff09;&#xff0c;也就是让整个图像呈现只有黑和白的效果。在灰度化的图像中灰度值的范围为0…

kafka为什么性能这么高?

Kafka系统架构 Kafka是一个分布式流处理平台&#xff0c;具有高性能和可伸缩性的特点。它使用了一些关键的设计原则和技术&#xff0c;以实现其高性能。 上图是Kafka的架构图&#xff0c;Producer生产消息&#xff0c;以Partition的维度&#xff0c;按照一定的路由策略&#x…

C++力扣题目 392--判断子序列 115--不同的子序列 583--两个字符串的删除操作 72--编辑操作

392.判断子序列 力扣题目链接(opens new window) 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;&quo…

【讨论】Web端测试和App端测试的不同,如何说得更有新意?

Web 端测试和 App 端测试是针对不同平台的上的应用进行测试&#xff0c;Web应用和App端的应用实现方式不同&#xff0c;测试时的侧重点也不一样。 Web端应用和App端应用的区别&#xff1a; 平台兼容性 安装方式 功能和性能 用户体验 更新和维护 测试侧重点有何不同 平台…

HGAME week2 web

1.What the cow say? 测试发现可以反引号命令执行 ls /f* tac /f*/f* 2.myflask import pickle import base64 from flask import Flask, session, request, send_file from datetime import datetime from pytz import timezonecurrentDateAndTime datetime.now(timezone(…

【Java】类与对象(实验二)

目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 掌握类的定义与对象的创建。理解构造方法和this关键字的用法。掌握对象对于属性及方法的引用。 二、实验内容 1、编写一个Java程序&#xff0c;定义一个表示学生的类Student&#xff0c;该类包括: (1)这个类的…

HarmonyOS—使用低代码开发应用或服务

使用低代码开发应用或服务有以下两种开发方式&#xff1a; 创建一个支持低代码开发的新工程&#xff0c;开发应用或服务的UI界面。在已有工程中&#xff0c;创建Visual文件来开发应用或服务的UI界面。 ArkTS工程和JS工程使用低代码的步骤相同&#xff0c;接下来以JS工程为例分…

VantUI组件的安装和使用

Vant UI 是一款轻量、可靠的移动端 Vue 组件库&#xff0c;适用于构建高性能的移动端页面。它提供了丰富的组件&#xff0c;如按钮、输入框、弹窗、轮播等&#xff0c;并且具有灵活的配置和扩展性。Vant UI 的设计风格简洁&#xff0c;易于上手&#xff0c;能够满足大部分移动端…

exe4j将java项目打包为exe包(无需每台机器上安装jdk)

这里写目录标题 背景过程打jar包1、修改pom文件2、maven命令打jar包 下载exe4j工具1.首先去官网下载 exe相关配置1、填写密钥2、选择jar包格式3、设置名称以及输出exe位置4、设置图标及设置操作系统版本5、设置要导入的jar包&#xff0c;以及启动类6、设置jdk版本范围7、设置jd…

【2024软件测试面试必会技能】Appium自动化(6):原生app元素定位方法

元素定位方法介绍及应用&#xff1a; Appium方法定位原生app元素: 通过appium inspector工具&#xff0c;可以获取元素的相关信息&#xff1b;在appium中提供了一系列的元素定位API&#xff0c;通过在这些API中输入指定的元素信息&#xff0c;就能完成元素定位&#xff0c;定…

C# cass10 面积计算

运行环境Visual Studio 2022 c# cad2016 cass10 通过面积计算得到扩展数据&#xff0c;宗地面积 &#xff0c;房屋占地面积&#xff0c;房屋使用面积 一、主要步骤 获取当前AutoCAD应用中的活动文档、数据库和编辑器对象。创建一个选择过滤器&#xff0c;限制用户只能选择&q…

究竟做老隋分享的temu蓝海项目怎么样?这些要点要关注

近年来&#xff0c;跨境电商成为了一股热潮&#xff0c;许多企业纷纷投身其中&#xff0c;希望能够分得一杯羹。其中&#xff0c;Temu项目备受关注。本文将从可靠性角度分析Temu蓝海项目&#xff0c;帮助您了解其优势和潜在风险。 一、 Temu项目的背景与可靠性 Temu是由拼多多推…

Codeforces Round 494 (Div. 3)

目录 A. Polycarps Pockets B. Binary String Constructing C. Intense Heat D. Coins and Queries E. Tree Constructing F. Abbreviation A. Polycarps Pockets 记录数量可以直接开一个桶即可然后求最大值 void solve(){cin>>n;vector<int> ton(105);int …

【进程概念】

目录 什么是在计算机运行的程序这么多运行的程序计算机是如何管理的先描述再组织 什么是在计算机运行的程序 对于一个在磁盘可执行的二进制文件&#xff0c;也可叫做可执行程序。对于一个可执行的程序&#xff0c;程序有自己的代码和数据。一旦运行起来&#xff0c;就会在计算…

Error: A JNI error has occurred, please check your installation and try again

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

【Redis服务搭建】

目录 Redis的修改配置启动以及参数调优Redis的常用基本操作Redis运维监控命令Redis的配置的动态更新和写入Redis的多用户管理Redis的慢日志Redis禁用危险命令和压测工具Redis持久化存储1.Redis的RDB持久化存储2.Redis的AOF持久化存储 Redis的主从复制redis的哨兵实现主从自动切…

深入探索Linux:ACL权限、特殊位与隐藏属性的奥秘

前言&#xff1a; 在Linux系统中&#xff0c;文件和目录的权限管理是一项至关重要的任务。它决定了哪些用户或用户组可以对文件或目录执行读、写或执行等操作。传统的Linux权限模型基于用户、组和其他的概念&#xff0c;但随着时间的推移&#xff0c;这种模型在某些情况下显得…

RISC-V知识总结 —— 指令集

资源1: RISC-V China – RISC-V International 资源2: RISC-V International – RISC-V: The Open Standard RISC Instruction Set Architecture 资源3: RV32I, RV64I Instructions — riscv-isa-pages documentation 1. 指令集架构的类型 在讨论RISC-V或任何处理器架构时&…

OpenLayers多要素旋转平移缩放及olext深度定制化

目录 1.前言2.olext官方示例3.重写Transform.js4.自定义样式5.自定义选中机制6.拓展思考6.1包围框的角度问题6.2不选中要素如何平移 7总结 1.前言 首先OpenLayers本身是支持旋转、平移、缩放的。olext 只是在 OpenLayers 的基础上又做了一层封装&#xff0c;使得看起来比较好看…

函数栈帧的创建及销毁(超详解)

目录 1.预备知识 1.1内存区的划分 1.2认识相关寄存器和汇编指令 1.2.1寄存器 1.2.2相关汇编指令 2.测试前 2.1测试代码及环境 2.2 main函数也是被其他函数调用的 3.函数栈帧的创建 4.进入函数内部 5.形参与实参 6.call/jump add函数 7.函数栈帧的销毁 7.1保存…