欢迎光临
我们一直在努力

C语言数据类型和变量

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中专门引入了布尔类型,是专门表示真假的。

_Bool//也可以是bool

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

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

//代码演示,_Bool也等价于bool
_Bool flag = true;
if (flag)
printf("i like C\\n");

1.5 各种数据类型的长度

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

1.5.1 sizeof操作符

        sizeof是一个关键字,也是一个操作符。是专门用来计算sizeof的操作符或操作数的类型所占空间大小的,单位是字节。sizeof操作符的操作数可以是类型,也可以是表达式或变量。

sizeof(类型);
sizeof 表达式;

        sizeof的操作数如果不是类型,是表达式,则可以省略后面的括号,且该表达式是不真实参与运算的,根据表达式的类型来确定大小。sizeof的计算结果是size_t类型的(这里你可以先理解为整型int)。

        sizeof运算符的返回值,C语言只规定是无符号整数,并没有规定具体的类型,而是留给系统具体决定。sizeof最终返回什么类型。不同系统中,返回值类型有可能不同。针对这种现象,C语言提供解决方案:创造一个类型别名size_t,用来统一表示sizeof的返回值类型。

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 数据类型长度

int main()
{
printf("%zd\\n", sizeof(char));//1字节
printf("%zd\\n", sizeof(bool));//1字节
printf("%zd\\n", sizeof(short));//2字节
printf("%zd\\n", sizeof(int));//4字节
printf("%zd\\n", sizeof(long));//4字节
printf("%zd\\n", sizeof(long long));//8字节
printf("%zd\\n", sizeof(float));//4字节
printf("%zd\\n", sizeof(double));//8字节
printf("%zd\\n", sizeof(long double));//8字节
return 0;
}

1.5.3 sizeof中表达式不计算

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


2. signed 和 unsigned

        C语言用signed和unsigned关键字修饰字符型和整型类型。signed关键字表示一个类型带有正负号,包含负值。unsigned关键字表示该类型不带有正负号,不包含负值,只能表示0和正整数。对于int整型类型,默认是带正负号的,也就是说int 相当于 signed int。由于这是默认情况,所以signed关键字一般省略不写,当然写上也是对的。

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

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

unsigned int a;

        整型变量声明为unsigned的好处是:同样长度的内存能够表示的最大整数值,增加了一倍。比如16位的unsigned short的取值范围是-32768~32767,最大是32767;而unsigned short的取值范围是0~65535,最大值增加到了65535。

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

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

        这里值得注意的是,char和int类型有一点不同:C语言规定char类型默认是否带正负号,由当前系统决定。char有可能是unsigned char ,也有可能是signed char。而int默认就是signed int。


3.变量

        之前我们知道了数据类型。那么类型是用来干嘛的?类型是用来创建变量的。那么什么又是变量呢?C语言中把经常变化的值称为变量;一直不变的值称为常量。

/*
变量创建的语法形式是这样的:
data_type name;
| |
| |
数据类型 变量名
*/
int age; //整型变量
char ch; //字符变量
double weight; //浮点型变量

        变量在创建的时候给初始值,称为初始化。

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

3.1 变量的分类及存储

        变量分为全局变量和局部变量:

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

#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++语言的时候,我们主要关注内存中的3个区域:栈区、堆区、静态区。1,局部变量存放在内存的栈区。2,全局变量存放在内存的静态区。3,堆区是用来动态管理内存的。

                                                


4. 算数操作符:+、-、*、/、%

        在写代码的过程中,难免会涉及到算数运算。C语言中为了方便运算,提供了一系列操作符。其中有一组操作符称为算数操作符。为:+、-、*、/、%(取余),这些操作符都是双目操作符(位于操作符两端的就是它们的操作数)。

//加法、减法
#include <stdio.h>
int main()
{
int x = 4 + 22;//4 和22为操作数,+为操作符
int y = 61 – 23;
printf("%d\\n", x);
printf("%d\\n", y);
return 0;
}

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

        其中的+、-、*和小学数学中学到的一样,这里不多赘述。需要注意的是/(除法),除号的两端如果是整数,执⾏的是整数除法,得到的结果也是整数。

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

        上面示例中,尽管变量x的类型是float浮点型,但是6/4的结果是1.0,而不是1.5。原因在于C语言中的整数除法是整除,只会返回整数部分,丢弃小数部分。如果希望得到浮点数的结果,俩个运算数必须至少一个是浮点数,这时C语言就会进行浮点数除法。

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

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

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

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

#include <stdio.h>
int main()
{
printf("%d\\n", 11 % -5); // 结果为:1,第一个运算数(%左边的数)是正数
printf("%d\\n",-11 % -5); // -1,第一个运算数是负数
printf("%d\\n",-11 % 5); // -1
return 0;
}


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

        在变量创建的时候给初始值称为初始化,在变量创建好后再给一个值,称为赋值。

int main()
{
int a = 100;//变量初始化
int b;
b = 200;//变量赋值
return 0;
}

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

5.1 连续赋值

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

int a = 3;//变量初始化
int b = 5;
int c = 0;
c = b = a+3;//连续赋值,从右向左依次赋值的。

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

int a = 3;
int b = 5;
int c = 0;
b = a+3;
c = b;

        这样在代码调试的时候,每一次赋值的细节都是可以方便观察的。

5.2 复合赋值符

        在写代码过程中,我们可能经常对一个数进行自增自减操作,C语言提供了更加便捷的方法:

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

//C提供更加便携的方法
int a = 10;
a += 3;
a -= 2;

/*C语言提供的复合赋值符有:
+= -=
*= /= %=
//下⾯的操作符后期讲解
>>= <<=
&= |= ^=
*/


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

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

6.1++和–

        ++是一种自增操作符,分为前置++和后置++;–是一种自减操作符,也分为前置–和后置–。

6.1.1前置++和后置++

int main()
{
int a = 10;//变量初始化
int b = ++a;//++的操作数是a,是放在a的前⾯的,就是前置++
printf("a=%d b=%d\\n",a , b);
return 0;
}

        前置++:先+1(先自增),后使用。上述代码中a原来是10,前置++a变量先自增+1为11,后使用(将自增后的a变量的值赋给b变量,b变量得到的是自增后的a变量的值,即11),所以计算后,a,b都是11。相当于:

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


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

        后置++:先使用,后+1(自增)。上述代码,a原来是10,先使用(将a变量原先的值赋给b变量,b变量得到的是原来的a变量的值,为10),后a变量自增+1为11。计算后,a变量值为11,b变量值为10。相当于:

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

前置++和后置++的区别一定要牢记!这俩者之间除了有先后次序(先使用还是先自增)的不同,还是有相同之处的,那就是不论前置++还是后置++,其操作数(++左边或右边的变量名)最后都自增+1。

6.1.2前置–和后置–

        如果你看懂了前置++和后置++,那么前置–和后置–对你也不是难事。只不过自增+1变成了自减-1。

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

        前置–:先自减-1,后使用。上述代码中a变量最初是10,先自减-1变为9,再使用(将自减后a变量的值赋给b变量,b变量得到的值为9),最后,a,b变量都是9。

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

       后置–:先使用,后自减-1。上述代码中a变量最初是10,先使用(将a变量最初的值10赋给b变量,b变量得到的值为10),后a变量自减-1为9。最后a,b变量的值为9,10。

6.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); //这⾥的b是10


7.强制类型转换

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

(类型)
int a = 3.14;
//a的是int类型, 3.14是double类型,两边的类型不⼀致,编译器会报警告
//为了消除这个警告,我们可以使⽤强制类型转换:
int a = (int)3.14;//意思是将3.14强制类型转换为int类型,这种强制类型转换只取整数部分
/*俗话说,强扭的⽠不甜,我们使⽤强制类型转换都是万不得已的时候使⽤,如果不需要强制类型转化就能实现代码,这样⾃然更好的。*/


8.scanf()函数和printf()函数介绍

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

8.1printf()函数

        printf()函数的作用是是将参数文本输出到屏幕。它名字中最后一个字母f(format)代表格式化,表示可以定制输出文本的格式。

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

        上述代码中的printf()语句会在显示屏上输出“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;
}

8.1.1占位符

        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(表示带入的是字符串)、%c(表示带入的是单个字符)。

#include <stdio.h>
int main()
{
printf("%s will come tonight\\n", "zhangsan");//%s表示带入的是字符串,则第二个参数为字符串
printf("%c will come tonight\\n", 'a');//%c表示带入的是单个字符,则第二个参数为字符
return 0;
}

        输出文本里还可以使用多个占位符:

#include <stdio.h>
int main()
{
printf("%s says it is %d o'clock\\n", "lisi", 21);
return 0;
}
/*
常用占位符列举
%c :字符。
%d :⼗进制整数。// int
%f :⼩数(包含 float 类型和 double 类型)。//float %f double – %lf
%hd :⼗进制 short int 类型。
%hu :unsigned short int 类型。
%ld :⼗进制 long int 类型。
%lu :unsigned long int 类型。
%Lf :long double 类型浮点数。
%p :指针(⽤来打印地址)。
%s :字符串。
%u :⽆符号整数(unsigned int)。
%x :⼗六进制整数。
%zd : size_t 类型。
*/

        上述代码示例中,输出文本%s says it is %d o'clock\\n中有俩个占位符%s和%d。分别对应printf()函数的第二个参数"lisi"和第三个参数21。执行输出后为lisi says it is 21 o'clock。

 printf()函数的参数与占位符是一一对应的关系,如果有n个占位符,printf()函数的参数就应该有n + 1个(输出文本也要占一个参数位置,通常是第一个参数位置。后面的n个参数都是占位符所要替换的值)。如果参数个数少于对应的占位符,printf()函数可能会输出内存中的任意值。

8.1.2输出格式

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

8.1.2.1限定宽度

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

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

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

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

        对于小数。这个限定符会限制所有数字的最小显示宽度。

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

        上述示例中,%12f表示输出的浮点数最少要占据12位,由于float单精度浮点型小数的默认显示精度是小数点后6位,所以123.45输出结果的头部会添加俩个空格使其刚好占据12位(.也占一位)。

8.1.2.2总是显示正负号

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

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

8.1.2.3限定小数位数

        输出小数时,有时候需要限定小数的位数。float单精度浮点型默认保留小数点后6位,那么我们希望只保留小数点后2位,占位符可以写成%.2f,若要保留小数点后3位,可以写成%.3f。

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

        这种写法可以与限定宽度占位符结合使用。

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

        上述示例中,%6.2f表示输出字符串最小宽度为6位,小数位数为2位。所以输出字符串的头部有2个空格。

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

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

8.1.2.4输出部分字符串

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

// 输出 hello
#include <stdio.h>
int main()
{
printf("%.5s\\n", "hello world");//占位符%.5s表示输出字符串hello world的前5个字符,即hello
return 0;
}

8.2scanf()函数

        当我们有了变量,我们需要给变量所在内存空间赋值就可以使用scanf()函数,如果需要将变量所在内存空间中的值输出在显示屏上,就需要printf()函数。

#include <stdio.h>

int main()
{
int score = 0;
printf("请输⼊成绩:");
scanf("%d", &score);
printf("成绩是:%d\\n", score);
return 0;
}

        scanf()函数用于读取用户的键盘输入。程序运行到该语句时会停下来,等待用户从键盘输入。用户输入数据,并按下回车键enter后,scanf()函数就会处理用户的输入,将其存入变量所在的内存空间(如果不理解内存空间,可以先理解scanf()函数就是将水(数据)存入水瓶(内存空间),printf()函数就是将水(数据)从水瓶(内存空间)中取出来)。

        scanf()函数的语法和printf()函数类似:

scanf("%d", &i);

        scanf()函数的第一个参数是一个格式字符串,里面会放置占位符(和printf()函数中的占位符作用类似),告诉编译器如何解读用户的输入,需要提取的数据是什么类型。这是因为C语言的数据都是有类型的,scanf()函数必须提前知道用户输入的数据类型,才能处理数据。scanf()函数的其余参数就是存放用户输入的变量,格式字符串(第一个参数)里面有多少个占位符,就有多少个变量。

        上述示例中,scanf()函数的第一个参数格式化字符串中的占位符为%d,表示用户输入的应该是一个整型,第二个参数&i表示,将用户从键盘输入的整数存入变量i所在的内存空间中。

这里值得注意的是,在scanf()函数中,用户输入的变量前面必须加上&取地址运算符(指针变量除外),因为scanf()函数传递的不是值,而是地址。也就是说变量i所在的内存空间地址指向用户输入的值(就是说名字为i的空矿泉水瓶(内存空间)一会要存放用户输入的“水”(键盘上输入的数据)),如果是指针变量(比如字符串变量),那就不用加&取地址运算符了,因为指针变量所在内存空间中存放的不是整型或者浮点型数据,而是其他内存空间的地址(相当于你家的门牌号)。

scanf("%d%d%f%f", &i, &j, &x, &y);//⼀次将键盘输⼊读⼊多个变量

        上述示例中,scanf()函数的第一个参数格式化字符串中,%d%d%f%f,表示用户输入的数据中前2个是整型,后俩个是浮点型,比如1,2,3.14,4.56。这4个值依次放入i,j,x,y四个变量所在的内存空间中。

        scanf()函数处理数值占位符时,会自动过滤空白字符,包括空格、制表符\\t、换行符\\n等。所以,用户输入的数据之间,有一个或多个空格不影响scanf()函数解读数据。另外,用户使用回车键将输入分成几行也不影响解读。

1

2

3.14

4.56

        像上述示例,用户分成4行输入,得到的结果与一行输入是一样的。每次按下回车键以后,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;
}

8.2.1scanf()函数的返回值

int scanf ( const char * format, … );

        上述为scanf()函数的声明,scanf()函数的返回值类型是整型,返回的是一个整数。表示成功读取的变量个数。如果没有读取任何项,或者匹配失败(用户输入的数据与对应的占位符所占的数据类型不匹配,比如用户输入整型2,占位符后数据类型为%f浮点型),则返回0。如果在成功读取任何数据之前,发生了读取错误或读取到文件结尾,则返回常量EOF(-1)。(ps:EOF为end of file文件结束标志)。

#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
float f = 0.0f;
//我这里测试用例为:输入:1 2 3.14
int r = scanf("%d %d %f", &a, &b, &f);
printf("a=%d b=%d f=%f\\n", a, b, f);//输出为:a = 1 b = 2 f = 3.140000
printf("r = %d\\n", r);//r = 3
return 0;
}

 8.2.2占位符

/*
%c :字符。
%d :整数。
%f : float 类型浮点数。
%lf : double 类型浮点数。
%Lf : long double 类型浮点数。
%s :字符串。
%[] :在⽅括号中指定⼀组匹配的字符(⽐如 %[0-9] ),遇到不在集合之中的字符,匹配将会停⽌。
*/

        上述占位符中,除了%c以外,都会自动,忽略输入数据中的起手的空白字符。%c不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格(这非常重要,如能理解,会避免很多细小的错误)。

        如果要强制跳过字符前的空白字符,可以写成:

scanf(" %c",&ch);//就是%c前加上一个空格,表示跳过0个或多个空白字符。

     下面特别强调%s占位符,它不能简单的等同于字符串。它的规则是,从当前第一个非空白字符开始读起,直到遇到空白字符(空格、制表符\\t、换行符\\n等)为止。因为%s不会包含空白字符,所以无法用来读取多个单词(因为单词之间有空格,%s遇到空格会停止),除非多个%s一起使用。这也说明scanf()函数不适合读取可能包含空格的字符串,比如书名或者歌曲名。此外,scanf()函数遇到%s占位符,会在字符串变量末尾存储一个空字符\\0,这个后续数组章节会讲到。

        scanf()函数将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,存储字符串时,很可能会超过数组的边界,导致预料之外的结果。那么,为了防止这种情况,使用%s占位符时,应该指定读入字符串的最长长度,即写成%[n]s,其中[n]是一个整数,表示读取字符串的最大长度,超出最大长度的字符将被丢弃。

#include <stdio.h>
int main()
{
char name[11];
scanf("%10s", name);//name 是⼀个⻓度为11的字符数组, scanf() 的占位符 %10s表⽰最多读取⽤⼾输⼊的10个字符,后⾯的字符将被丢弃,这样就不会有数组溢出的⻛险了

return 0;
}

8.2.3赋值忽略符

        有时候,用户输入的数据可能不符合预定的格式:

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

        上述代码中,如果用户输入2026-01-01,就会正确解读出年、月、日。问题是用户可能输入其他格式,比如2026/01/01,这样scanf()函数会解析数据失败。为了避免这种情况,scanf()函数提供了赋值忽略符*,只要把*加在任何占位符的%后,该占位符就不会返回值,解析后将被丢弃。

#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就是在占位符的%后,加入了赋值忽略符*,表示这个占位符没有对应的变量,解析后不必返回。

        写到此处,差不多结束了。如果读者对本文章中的知识点有疑问,可以评论区留言,我会及时答复的,希望你读完本文章可以学到一些知识!

赞(0)
未经允许不得转载:171主机测评 » C语言数据类型和变量
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址