C语言数据类型、变量和常用操作符 -- C语言数据类型,变量创建、分类以及初始化,常见运算符,强制类型转换,printf 函数,scanf 函数

目录

1. 数据类型介绍

1.1 各种数据类型的长度

1.1.1 sizeof 操作符

1.1.2 数据类型长度

1.1.3 sizeof 中表达式不计算

2. signed 和 unsigned

3. 变量

3.1 变量的创建

3.2 变量的分类

4. 算数操作符

5. 赋值操作符

5.1 赋值运算符 =

5.2 复合赋值运算符

6. 单目操作符 

6.1 前置 ++/-- 和后置 ++/--

 6.2 + 和 -

7. 强制类型转换

8. scanf 和 printf 介绍

8.1 printf

8.1.1 占位符 

8.1.2 占位符表

8.1.3 printf 输出格式

8.1.3.1 限制宽度

8.1.3.2 总显示正负号

8.1.3.3 限定小数位数

8.1.3.4 输出部分字符串

8.2 scanf

8.2.1 scanf 的基本介绍

8.2.2 scanf 的返回值

8.2.3 scanf 的安全性

8.2.4 赋值忽略符


1. 数据类型介绍

        C语⾔提供了丰富的数据类型来描述⽣活中的各种数据。使⽤整型类型来描述整数,使⽤字符类型来描述字符,使⽤浮点型类型来描述⼩数

        数据类型:相似的数据所拥有的共同特征

// 1. 字符型 -- 长度为 1 字节
char
[signed] char    //有符号的
unsigned char    //⽆符号的

// 2. 整型
// 2.1 短整型 -- 长度为 2 字节
short [int]
[signed] short [int]
unsigned short [int]
// 2.2 整型 -- 长度为 4 字节
int
[signed] int
unsigned int
// 2.3 ⻓整型 -- 长度为 4 字节
// C语言规定 long 的长度 >= int,对于不同的编译器长度不同,vs 使用的编译器为 4 字节。
long [int]
[signed] long [int]
unsigned long [int]
// 2.4 更长的整型 -- 长度为 8 字节
// C99 中引⼊
long long [int]
[signed] long long [int]
unsigned long long [int]

// 3. 浮点型
float -- 长度为 4 字节
double -- 长度为 8 字节
long double    -- 规定 long double 的长度 >= double,不同编译器长度不同,vs 下为 8 字节 // C99 引入

// 4. 布尔类型 -- 长度为 1 字节
// C 语⾔原来并没有为布尔值单独设置⼀个类型,⽽是使⽤整数 0 表⽰假,⾮零值表⽰真。
// 在 C99 中也引⼊了 布尔类型 ,是专⻔表⽰真假的。布尔类型的使⽤得包含头⽂件 <stdbool.h>。
// 布尔类型变量的取值是: true 或者 false .
_Bool -- 长度为 1 字节

1.1 各种数据类型的长度

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

1.1.1 sizeof 操作符

        sizeof 是⼀个关键字,也是操作符,sizeof 用于计算类型表达式以及变量的长度,单位是字节

sizeof( 类型 )
sizeof 表达式

         (1)sizeof 的操作数是表达式或者变量的时候,可以省略掉后边的括号。sizeof 的操作数是类型时必须加上 "()"

        (2)sizeof 后面的表达式不真实参与运算,只是根据表达式的类型得出大小。

        (3)sizeof 的计算结果类型为 size_t 类型C 语言规定 sizeof 运算符的返回值是无符号整数,并没有规定具体的类型,而是留给系统自己去决定。不同的系统中,返回值的类型不同,有可能是 unsigned int,也可能是 unsigned long,甚至是 unsigned long long,打印的时候占位符分别是 %u、%lu 和 %llu,这样不利于移植。C语言创造一个类型别名为 size_t 的类型,这个类型会根据系统的变化而变化,统一使用 %zd 占位符。

1.1.2 数据类型长度

#include <stdio.h>

int main()
{
	printf("_Bool的长度:%zd 字节\n", sizeof(_Bool));
	printf("char的长度:%zd 字节\n", sizeof(char));
	printf("short的长度:%zd 字节\n", sizeof(short));
	printf("int的长度:%zd 字节\n", sizeof(int));
	printf("long的长度:%zd 字节\n", sizeof(long));
	printf("long long的长度:%zd 字节\n", sizeof(long long));
	printf("float的长度:%zd 字节\n", sizeof(float));
	printf("double的长度:%zd 字节\n", sizeof(double));
	printf("long double的长度:%zd 字节\n", sizeof(long double));

	return 0;
}

1.1.3 sizeof 中表达式不计算

#include <stdio.h>

int main()
{
	short s = 5;
	int b = 10;
	printf("%zd\n", sizeof(s = b + 1));	// sizeof 内的表达式不计算
	printf("s = %d\n", s);
	return 0;
	return 0;
}

        sizeof 在代码进行编译的时候就根据表达式的类型确定了,所以在允许期间就不会执行表达式了。 

2. signed 和 unsigned

        C语言使用 signed 和 unsigned 关键字修饰字符型和整型

        signed 关键字,表⽰⼀个类型带有正负号,包含负值; 

        unsigned 关键字,表⽰该类型不带有正负号,只能表⽰零和正整数

        对于 int 类型,默认是带有正负号的,也就是说 int 等同于 signed int char 类型默认是否带有正负号由编译器决定,它有可能是 signed char ,也有可能是 unsigned char。

        整数变量声明为 unsigned 的好处是同样⻓度的内存能够表⽰的最⼤整数值,增⼤了⼀倍。16位的 signed short int 的取值范围是:-32768~32767,最⼤是32767;⽽ unsigned short int 的取值范围是:0~65535,最⼤值增⼤到了65535。

        limits.h 文件中说明了字符型和整型的取值范围。float.h 中说明了浮点数类型的取值范围

        unsigned int 中的 int 可以忽略,可以使用下列进行变量的声明。

unsigned a;

3. 变量

3.1 变量的创建

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

unsigned int age;    // age 是一个 unsigned int 类型的变量
char ch;    //  ch 是一个 char 的变量

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

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

3.2 变量的分类

        (1)全局变量:在大括号外部定义的变量就是全局变量。全局变量的使用范围广,整个工程中想使用都是有办法使用的。

        (2)局部变量:在大括号内部定义的变量就是局部变量。局部变量的使用范围比较局限,只能在自己所在的局部范围内进行使用。

#include <stdio.h>

int global = 2025;//全局变量
int main()
{
	int local = 2018;//局部变量
	printf("local: %d\n", local);
	printf("global: %d\n", global);
	return 0;
}

        当全局变量和局部变量名相同的时候,采用就近原则进行使用

#include <stdio.h>

int n = 100;

int main()
{
	{
		int n = 10;
		printf("%d\n", n);	// 局部变量
	}
	printf("%d\n", n);	// 全局变量
	return 0;
}

        知识点1:

                一个全局变量不初始化,默认值为 0,一个局部变量不初始化,默认值是随机值。所以在创建变量的时候,尽量进行初始化,避免出现随机值的干扰。

        在 C/C++ 中,一般会关注内存中的三个区域:栈区、堆区、静态区

        局部变量存放在栈区;全局变量存放在静态区,堆区又来动态内存管理(暂不介绍)。

4. 算数操作符

         C语⾔中为了⽅便运算,提供了⼀系列操作符,也叫做运算符,其中有⼀组操作符叫:算术操作符,分别是: + - * / % ,这些操作符都是双目操作符

#include <stdio.h>

int main()
{
	int x = 4 + 16;
	int y = 60 - 20;
	int num = 5;
	printf("%d\n", x);
	printf("%d\n", y);
	printf("%d\n", num * num);
	return 0;
}

        其中的 +  - * 和数学上是一样的。+  - * 叫做操作符,符号两边的数字叫做操作数,这种有两个操作数的操作符叫做双目操作符

#include <stdio.h>

int main()
{
	int x = 6;
	int y = 4;
	float f = x / y;
	int i = x / y;
	printf("%f\n", f);
	printf("%d\n", i);
	return 0;
}

        如上所示,在数学中 6 / 4 应该为 1.5,但是上述的输出为什么都是 1 呢?因为在 C语言中, 如果 / 操作符的两个操作数都是整型,则结果只会返回整数部分,如果 / 操作符的两个操作数有一个为浮点型,结果返回浮点数

#include <stdio.h>

int main()
{
	float x = 6;
	int y = 4;
	float f = x / y;
	int i = x / y;
	printf("%f\n", f);
	printf("%d\n", i);
	return 0;
}

        将上述的 x 改为 float 类型,第一个结果是 1.500000,第二个结果是 1。 原因是这时的 x / y 得到的结果类型为 float,然后float 类型的变量赋值给 int 类型,会自动截断小数部分

        常量进行运算的时候,比如写成 20 时,这时候为整数,写成 20.0 时,这时候为浮点数。

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

#include <stdio.h>

int main()
{
	int res = 6 % 4;
	printf("%d\n", res);
	return 0;
}

        负数求模的规则是,结果的正负号由第一个操作数的正负号决定。 

#include <stdio.h>

int main()
{
	printf("%d\n", 6 % 4);
	printf("%d\n", 6 % -4);
	printf("%d\n", -6 % 4);
	printf("%d\n", -6 % -4);

	return 0;
}

5. 赋值操作符

5.1 赋值运算符 =

        在变量创建的时候给一个初始值叫初始化,在变量创建好后再给一个值,叫做赋值。其中 " = " 叫做赋值运算符。

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

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

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

c = b = a+3; //连续赋值,从右向左依次赋值的。这时 c 和 b 的值都为 a + 3

5.2 复合赋值运算符

+=        -=
*=        /=        %=
//下⾯的操作符后续介绍
>>=       <<=
&=        |=        ^=

        当对一个数进行自增、自减等操作时,可以使用上述复合赋值符。 

int a = 5;
a = a + 5;  等同于 a += 5;

6. 单目操作符 

         C语⾔中只有⼀个操作数的操作符被称为单⽬操作符++、--、+(正)、-(负) 就是单⽬操作符的

6.1 前置 ++/-- 和后置 ++/--

        ++/-- 是一种自增/自减的操作符

        当使用前置++时(前置--同理),操作数是先进行自增之后,然后再带入表达式中进行运算。也就是:先 +1,后使用

#include <stdio.h>

int main()
{
	int a = 10;
	int b = ++a;//++的操作数是a,是放在a的前⾯的,就是前置++

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

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

        后置++时(后置--同理),操作数先进行表示式中的运算,然后再进行自增操作。 也就是:先使用,后 +1

#include <stdio.h>

int main()
{
	int a = 10;
	int b = a++;//++的操作数是a,是放在a的前⾯的,就是前置++

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

 6.2 + 和 -

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

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

        运算符 - 用来改变一个值的正负号。 

#include <stdio.h>

int main()
{
	int a = 10;
	int b = -a;
	int c = -10;

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

7. 强制类型转换

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

(类型)操作数
#include <stdio.h>

int main()
{
	int a = 3.14;
	printf("%d\n", a);
    return 0;
}

        a 的类型是 int 类型,3.14 是 double 类型,两边的类型不一致,强行赋值编译器会出现报警。但是可以使用强制类型转换来将 3.14 转换成 int 类型,这种强制类型转换只取整数部分。 

#include <stdio.h>

int main()
{
	int a = (int)3.14;
	printf("%d\n", a);
}

8. scanf 和 printf 介绍

8.1 printf

        printf 函数需要包含头文件 stdio.h。

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

        printf() 不会在行尾自动添加换行符,运⾏结束后,光标就停留在输出结束的地⽅,不会⾃动换⾏。

8.1.1 占位符 

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

#include <stdio.h>

int main()
{
	printf("There are %d apples\n", 3);
	return 0;
}

         上⾯⽰例中, There are %d apples\n 是输出⽂本,里面的 %d 就是占位符,表示这个位置要⽤其他值来替换。占位符的第⼀个字符⼀律为百分号 % ,第⼆个字符表⽰占位符的类型, %d 表⽰这⾥代⼊的值必须是⼀个整数

        输出文本⾥⾯可以使⽤多个占位符

int main()
{
    printf("%s says it is %d o'clock\n", "lisi", 21);
    return 0;
}

         上⾯⽰例中,第⼀个是字符串占位符 %s ,第⼆个是整数占位符 %d ,分别对应 printf() 的第⼆个参数( lisi )和第三个参数( 21 )。执⾏后的输出就是 lisi says it is 21 o'clock 。

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

8.1.2 占位符表

占位符对应输出的数据类型
%cchar 类型字符
%d十进制 int 类型
%f小数(包含 float 和 double 类型)
%ld十进制 long int 类型
%luunsigned long int 类型
%lfdouble 类型
%Lflong double 类型
%p指针(地址)
%s字符串
%uunsigned int 类型
%x十六进制整数
%zdsize_t 类型

8.1.3 printf 输出格式

8.1.3.1 限制宽度

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

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

        如果限制了占位符的最小宽度,输出的值默认是右对齐。 如果希望改成左对齐,可以在占位符的 % 后面插入一个 - 号

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

        这个限定符也会限制小数打印的宽度,小数默认打印小数部分前六位。

#include <stdio.h>

int main()
{
	printf("%12f\n", 123.45);
	return 0;
}

8.1.3.2 总显示正负号

        默认情况下, printf() 不对正数显⽰ + 号,只对负数显⽰ - 号。如果想让正数也输出 + 号,可以在占位符的 % 后⾯加⼀个 + 。添加之后如果打印的是负数,而没有任何影响。

#include <stdio.h>

int main()
{
	printf("%+d\n", 12); // 输出 +12
	printf("%+d\n", -12); // 输出 -12
	return 0;
}

8.1.3.3 限定小数位数

        输出小数时,有时希望限定小数的位数,则可以在 % 后面 加上 .x,表示显示 x 位小数

#include <stdio.h>
int main()
{
	printf("1. Number is %f\n", 0.5);
	printf("2. Number is %.2f\n", 0.5);

	return 0;
}

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

#include <stdio.h>
int main()
{
	printf("%6.2f\n", 0.5);	// 最少显示 6 位,小数显示 2 位
	return 0;
}

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

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

8.1.3.4 输出部分字符串

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

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

8.2 scanf

8.2.1 scanf 的基本介绍

        给变量输入值可以使用 scanf 函数,如果需要将变量的值输出在屏幕上的时候可以使用 printf 函数。

        scanf() 用于读取用户的键盘输入,程序允许到这个语句的时候会停下来等待用户从键盘输入。用户输入数据并按下回车后,scanf() 才会处理用户的输入,将其存入变量

        scanf() 函数在使用的时候也需要包含头文件 <stdio.h>。

        scanf() 第一个参数是一个格式字符串,里面会放置占位符,告诉编译器如何解读用户的输入,需要提取的数据是什么类型。它的其余参数就是存放用户输入的变量的地址

#include <stdio.h>
int main()
{
	int score = 0;
	printf("请输入成绩:");
	scanf("%d", &score);    // & 是取地址运算符
	printf("成绩是:%d\n", score);
	return 0;
}

        scanf() 处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等

        scanf() 处理用户的输入的原理是,用户的输入先放入缓存中,等待按下回车键后,按照占位符对缓冲进行解读。解读用户输入时,会从上一个遗留的第一个字符开始,直到读完缓冲或者遇到第一个不符号条件的字符为止

#include <stdio.h>

int main()
{
	int i = 0, j = 0;
	float x = 0.0f, y = 0.0f;

	scanf("%d%d%f%f", &i, &j, &x, &y);    // 占位符是粘在一起的,在输入的时候数据之间使用空格隔开,这样在解读的时候就可以分开进行解读。
	printf("i = %d\n", i);
	printf("j = %d\n", j);
	printf("x = %f\n", x);
	printf("y = %f\n", y);
}

        %c 占位符,不会自动忽略起始的空白字符。 %c 作为占位符是,总是返回当前要解析位置的第一个字符,无论该字符是否为空格。

#include <stdio.h>
int main()
{
	char c = '0';

	scanf("%c", &c);
	printf("%cxxxx", c);

	return 0;
}

        如上图,当输入 "    abc" 时,这时候 %c 读取到的是第一个空白字符(空格)。

        如上图,连续输入两个换行符(回车),%c 读取到第一个空白字符(换行符),第二个换行符是通知 scanf 对读到的数据进行解析,通过 printf 可以看到,打印的结果是一个空行和 xxxx,而这个空行就是 %c 占位符读到的换行符。 

        在占位符 %c 前面加上一个空格,这样就可以使 %c 占位符忽略所有空格和换行符

       占位符 %s 从当前第一个非空白字符开始读,直到遇到空白字符(空格、换行符顿号制表符)为止。scanf() 遇到 %s 占位符,会在字符串变量末尾存储⼀个空字符 \0。

#include <stdio.h>
int main()
{
	char arr[10] = { 0 };

	scanf("%s", arr);
	printf("%s", arr);

	return 0;
}

8.2.2 scanf 的返回值

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

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	int c = 0;

	int ret = scanf("%d %d %d", &a, &b, &c);
	printf("r = %d\n", ret);
	printf("a=%d b=%d c=%d\n", a, b, c);
	return 0;
}

        如上图,是 scanf 正常读取的情况,返回值为读取到的变量个数。 

        如上图,当输入两个数字,再输入 Ctrl + z 然后回车表示提前结束,这个时候也是返回读取到的变量个数。 

         如上图,匹配失败没有读取当任何数据的时候,返回 0。

        如上图,在 vs 环境中按 3 次连续输入三个 ctrl + z 和回车,这时候结束程序表示读取出错,返回 EOF。

        可以利用 scanf 返回值的特性来进行循环读取数据进行处理

#include <stdio.h>
int main()
{
	int x = 0, y = 0;

	while (scanf("%d %d", &x, &y) == 2)
	{
		printf("输入的两个值相加的结果为:%d\n", x + y);
	}

	return 0;
}

8.2.3 scanf 的安全性

        scanf() 是一个不安全的函数,就以下列这个例子来说明:

#include <stdio.h>

int main()
{
	char arr[6] = { 0 };
	scanf("%s", arr);    // 数组名就是数组的地址,所以这里不需要 &
	printf("%s", arr);
	return 0;
}

         上述代码中,通过 scanf 向一个数组输入字符,当输入的字符大小没有超过数组大小时,执行的结果是正常的。

        当输入的字符数量大于数组大小的时候,字符会被正常写入,但是程序会崩溃。原因是,scanf 不管给的变量大小是多大,都会先将输入的数据写入变量中,当输入的数据长度超过数组大小时,会导致内存越界访问,进而导致程序崩溃

        为了防止这种情况,可以将占位符 %s 写成 %[m]s,表示最长只能读取 m 个字符

8.2.4 赋值忽略符

        有时候输入的格式和 scanf 第一个参数格式化字符串的格式不同,就会导致匹配失败的情况。

#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 的格式进行输入是不会出错的。 

        如上图,当 scanf 中有格式控制的时候,空白字符不会被忽略,这时候不按照 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);
	printf("%d %d %d\n", year, month, day);
	return 0;
}

        如上所示,%*c 这个占位符没有对应的变量,解析后被丢弃。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值