C语言第一章数据类型和变量(上)

一.数据类型的介绍

1.数据类型的背景

正如大家所熟知的,编程是用来解决生活中实际问题的。在日常生活中,有许多种类的数据。比如一个常见的实际问题:高三18班期末考试需要统计分数,那么其中就有许多变量:姓名,分数,科目名,排名等等······计算机语言为了解释这类型的问题,便创造出了数据类型,用于创建不同类型的变量从而接收这些不同种类的数值。

像上述例子中的姓名和科目名就是一种字符的数据变量,用char可以定义字符型的变量,例如:王华,李明 或者 语文,英语等;分数是浮点型的数据变量,double可以定义浮点型的变量,例如:522.5或者478.99等;排名是一种整型的数据变量,int可以定义整型变量,例如:237和432等。所以C语言提供了丰富的数据类型用来创建不同种类的变量,从而存储不同种类的数据。

2.数据类型的盘点

数据结类型分为内置类型和自定义类型。其中内置类型分为 字符型,整型,浮点型,布尔类型;自定义类型分为 数组,结构体类型,枚举类型,联合体类型。

内置类型:C语言本身就具有的数据类型

自定义类型:自己创造出的数据类型(后期博客展现)

3.初识内置类型

(1)字符类型

字符类型,它的英语发单词是character,所以也叫char类型。

(2)整型类型

整型类型分为四种,分别为短整型short ,整型int ,长整型long ,更长的整型long long 。

上述的短整型,长整型,更长的整型表示其实应该是short int, long int, long long int。只不过上面表示的形式为简写形式也最为常见

(3)浮点型类型

浮点型类型分为三种,分别为单精度浮点型float,双精度浮点型double,更高精度浮点型long double。

浮点型的解释:因为生活中小数的小数点可以随便移动,例如:3.14=31.4*10^(-1)。所以生活中的小数就是浮点数。

(4)布尔类型

C语言中原来并没有为布尔值(表示真假的变量)单独设置类型,而是使用整数0表示假,非零表示真。在C99中专门引入了布尔类型,专门表示真假。它可以用_Bool表示。

布尔类型的使用需要包含头文件<stdbool.h>

布尔类型变量的取值是true或者false。

C语言中布尔类型的定义:

cpp 复制代码
#define bool _Bool
#define false 0
#define true 1

代码演示:

cpp 复制代码
#include <stdio.h>
#include <stdbool.h>
int main()
{
_Bool flag =false;
if(flag)
printf("你好!");
else
printf("Hello");
return 0;
}

代码解释:

定义一个布尔类型的变量,名为flag,并且赋值为false。当flag为真则打印:你好!,否则打印Hello!。

运行结果为:Hello!

4.各种数据类型的长度

(1)背景:

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

(2)sizeof 操作符

sizeof是C语言中的关键字,也是一种操作符。它是用来计算sizeof的操作数的类型长度的,单位是字节。sizeof操作符的操作数可以是数据类型,也可以是变量或者表达式。但是sizeof中表达式不计算!!!

sizeof (类型)

sizeof(表达式)

sizeof(数据类型)

字节:计算机中内存的单位
bit:比特位 8字节=1比特位(一个二进制位的存储需要一个bit的空间)

Byte:字节 1 KB=1024 Byte

KB 1MB=1024KB

MB 1GB=1024MB

GB 1TB=1024GB

TB 1PB=1024TB

PB .......

...

(3)运用sizeof计算各数据类型的大小

cpp 复制代码
#include<stdio.h>
int main()
{
printf("%zd\n", sizeof (char)):
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;
}

代码运行的结果为:1 2 4 4 8 4 8 8

①疑问一

为什么 long / long double 的数据类型的大小和 int / double 数据类型的大小相同?

原因是:C语言标准规定 sizeof( long )>=sizeof ( int )

sizeof ( long double )>=sizeof ( double )

②疑问二

为什么用sizeof关键字时侯,需要用到%zd而不是%d?

sizeof的计算结果是size_t类型的数据。sizeof运算结果的返回值在C语言中被规定为无符号整数,(无符号整数也就是非负整数的意思,因为数据类型的大小一定是非负整数,所以在C语言中被规定为无符号整数)并没有规定具体的类型。而是交给系统自己决定。不同系统中返回值类型有可能是unsigned int(无符号整型),也有可能是unsigned long,甚至是unsigned long long,对应的占位符分别为%u %lu %llu。这样不利于程序的可移植性(程序的可移植性:在不同编译器中类型不同,不能随意的变换:我的代码在你的编译器上无法编译,你的代码在我的编译器上也无法编译)。

于是C语言提供了一种解决办法,创造了一个类型别名size_t的返回值类型。对应当前的系统的sizeof的返回值类型,可能是unsigned int 也有可能是unsigned long long 。

③疑问三

为什么sizeof中的表达式不计算???

cpp 复制代码
#include<stdio.h>
int main( )
{
short s=2;
int b= 10;
printf("%zd\n",sizeof(s=b+1));
printf("s=%d\n",s);
return 0;
}

代码运行的结果为:2 s=2

sizeof中如果放的表达式,那么表达式不会真实计算。而是根据表达式的类型进行推断的。比如上面的例子:b是int类型的数据,+1之后依然是int类型的数据。但是再把它赋值给short类型数据堵塞变量s中,那么最后就会是short类型的大小。又因为sizeof中的表达式不参与运算,则s的值依然是2。

拓展:对于有符号整型的打印,占位符应该为%d,对于无符号整形的打印,占位符应该是%u.

二.signed和unsigned

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

C语言中char类型默认为signed char 或者为unsigned char,是不确定的,取决于编译器的不同。(大部分情况下char=signed char)

整型变量声明为unsigned的好处是:同样的内存长度能够表示的最大整数值增加了原来的一倍。比如16位的signed short int 的取值范围是-32768~32767。32位的signed int 的取值范围可以参看limits.h给出的定义

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

cpp 复制代码
#define SHORT_MIN  (-32768)                //有符号16位整型的最小值
#define SHORT_MAX  (32767)                 //有符号16位整型的最大值
#define USHRT_MAX  0Xffff                  //无符号16位整型的最大值
#define INT_MIN    (-2147483647-1)         //有符号整型的最小值
#define INT_MAX    (2147483647)            //有符号整型的最大值

三.数据类型的取值范围

上述的数据类型很多,尤其数整型类型就有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 的最⼤值。

四.变量

1.变量的概念

什么是变量呢?

C语言中把经常变化的值叫做变量,不变的值称为常量。比如年龄就是一个变量,

2.变量的创建和初始化

变量创建的方法:数据类型 + 变量名;例如下方的变量创建:

cpp 复制代码
int  age;                //整型变量
char  ch;                //字符变量
double  weight;          //浮点型变量

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

cpp 复制代码
int  age =18;
char ch  ='w';
double weight =48.8;
unsigned int height =180;

创建一个整型变量age,将其初始化为18;创建一个字符类型变量ch,将其初始化为w······

3.变量的分类

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

在大括号内部的叫局部变量,局部变量的适用范围比较局限,只能在自己的局部范围(大括号内)内使用;全局变量是在大括号外部定义的变量,适用范围更广,整个工程都是可以使用的。

如果局部变量的变量名和全局变量的名字相同,会怎么办呢???

cpp 复制代码
int  m=1000;
int main( )
{
int m=100;
printf("%d",m);        //这里的结果会是多少呢???
return 0;
}

代码的运行结果为:100

当全局变量和局部变量在该位置都可以使用时;局部优先。

4.内存的介绍

内存分为栈区,堆区,静态区,不同的变量存储的位置不同。如图所示:

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

算数操作符也叫做双目运算符。操作符也叫做运算符。

1.加法减法运算符:+ -

加法符号和减法符号两边都是有2个操作数的,位于操作符两端的就是它们的操作数,这种操作符也叫双⽬操作符。以下是加减法运算符的运用:

cpp 复制代码
#include <stdio.h>
int main()
{
 int x = 4 + 22;
 int y = 61 - 23;
 printf("%d\n", x);
 printf("%d\n", y);
 return 0;
}

2.乘法运算符:*

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

3.除法运算符:/

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

cpp 复制代码
#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语言就会进行浮点数除法。

再看一个例子:

cpp 复制代码
#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 ,让整除变成浮点数除法。

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

4.取模运算符

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

cpp 复制代码
#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;
}

取余运算符的正负与前面操作数的正负相同!!!

六.赋值操作符

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

cpp 复制代码
int a = 100;//初始化 
 a = 200;//赋值,

这里不要将赋值和初始化搞混了,两者存在本质的区别!!!

1.连续赋值

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

cpp 复制代码
int a = 3;
int b = 5;
int c = 0;
c = b = a+3;//连续赋值,从右向左依次赋值的

最后一句代码就是连续赋值,这种代码不方便理解,建议拆开来写。就像下面那样写:

cpp 复制代码
int a = 3;
int b = 5;
int c = 0;
b = a+3;
c = b;

2.复合操作符

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

cpp 复制代码
int a = 10;
a = a+3;
a = a-2;

将a+3的值赋值给a;

将a-2的值赋值给a;

这种代码的写法C语言提供了一种更简便的方法:

cpp 复制代码
int a = 10;
a += 3;
a -= 2;

七.单目操作符

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

1.++和--

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

(1) 前置++

cpp 复制代码
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,相当于这样的代码:

cpp 复制代码
int a = 10;
a = a+1;
b = a;
printf("a=%d b=%d\n",a , b);

(2)后置++

cpp 复制代码
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,相当于这样的代码:

cpp 复制代码
int a = 10;
int b = a;
a = a+1;
printf("a=%d b=%d\n",a , b);

(3)前置--

如果前置++搞明白了,前置--和前置++是相同的道理。

计算口诀:先-1,后使用。

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

(4)后置--

后置--类似于后置++,两者有着相同的计算原理。

计算口诀:先使用,后-1。

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

2.+和-

这里的+和-都是符号为正负的意思,是单目操作符。(操作数只有一个)

(1)+

运算符+对原变量的正负没有影响,该运算符是一个完全可以忽略的运算符,写了也没有错误。注意:这里的+是正负的意思,而不是加的意思。

cpp 复制代码
int a = +10; 
int a = 10;

上面两行代码是等价的!!!

(2)-

  • 是用来改变一个值的正负的操作符,负数的前面加上 -, 就会把这个操作数变成正数,正数的前⾯加上 - ,就会把该操作数变为负数。
cpp 复制代码
int a = -10;
int b = -a;
printf("b=%d\n", b);

八.强制类型转换

1.概念:

强制类型转换,就是在编程过程中,需要把一种数据类型强制转换成另外一种数据类型,这种操作就叫做强制类型转换。

2.语法形式

(需要转换的数据类型)左边的蓝色字体就是强制类型转换的语法形式。

3.代码演示

cpp 复制代码
int a = 3.14;
//a的是int类型, 3.14是double类型,两边的类型不⼀致,编译器会报警告
int a = (int)3.14;
//意思是将3.14强制类型转换为int类型,这种强制类型转换只取整数部分

上述代码运行之后,a就会变成3!!!

4.注意事项
俗话说,强扭的瓜不甜,使用强制类型转换是万不得已的时候才会使用,如果不需要强制类型转化
就能实现代码,尽量不要使用。

相关推荐
爱掉发的小李39 分钟前
前端开发中的输出问题
开发语言·前端·javascript
学不动CV了40 分钟前
ARM单片机OTA解析(一)
c语言·arm开发·stm32·单片机·嵌入式硬件·51单片机
zyx没烦恼1 小时前
五种IO模型
开发语言·c++
Q_Q5110082851 小时前
python的婚纱影楼管理系统
开发语言·spring boot·python·django·flask·node.js·php
EutoCool1 小时前
Qt窗口:菜单栏
开发语言·c++·嵌入式硬件·qt·前端框架
nightunderblackcat2 小时前
新手向:使用Python将多种图像格式统一转换为JPG
开发语言·python
我爱Jack2 小时前
深入解析 LinkedList
java·开发语言
engchina2 小时前
Python PDF处理库深度对比:PyMuPDF、pypdfium2、pdfplumber、pdfminer的关系与区别
开发语言·python·pdf
拓端研究室3 小时前
专题:2025供应链数智化与效率提升报告|附100+份报告PDF、原数据表汇总下载
开发语言·php
一百天成为python专家3 小时前
python库之jieba 库
开发语言·人工智能·python·深度学习·机器学习·pycharm·python3.11