【C数据(一)】数据类型和变量你真的理解了吗?来看看这篇

简介: 【C数据(一)】数据类型和变量你真的理解了吗?来看看这篇

前言

一、数据类型

C语言主要的数据类型和变量的数据类型有:

  1. 基本数据类型:
  • 整数类型:
  • char:字符类型,占1字节
  • short:短整型,占2字节
  • int:整型,占4字节
  • long:长整型,占4或8字节
  • long long:更长的整型,占8字节
  • 浮点数类型:
  • float:单精度浮点数,占4字节
  • double:双精度浮点数,占8字节
  • 其他类型:
  • void:无类型
  • bool:布尔类型C语言没有内置布尔类型bool,需要包含<stdbool.h>头文件
  1. 变量的数据类型:
  • 自动变量:定义在函数或代码块内的变量,生命周期在函数或代码块结束后结束。
  • 静态变量:使用static声明的变量,生命周期持续整个程序执行期间。
  • 寄存器变量:使用register声明,让变量存储在CPU寄存器中加快访问速度。外部变量:使用extern声明的变量定义在其他源文件中
  • 指针变量:用于存储地址的值。
  • 数组变量:用于存储多个同类型数据元素。
  • 结构体变量:用于存储不同类型数据元素的集合。
  • 联合体变量:用于存储占用相同内存空间的不同类型数据。
  • 枚举变量:用于定义一组相关常量的值。
#include <stdio.h>
#include <stdbool.h>
int main() 
{
  // 基本数据类型
  char ch = 'a'; // 字符类型
  short num = 10; // 短整型
  int age = 25; // 整型 
  long long bigNum = 1000000000; // 长长整型

  // 浮点数类型
  float price = 19.99; // 单精度浮点 
  double weight = 75.123; // 双精度浮点

  // 其他类型
  void func(); // 无类型
  bool isMale = true; // 布尔类型

  // 变量的数据类型
  static int count = 0; // 静态变量
  register int loop = 0; // 寄存器变量

  int* pNum = &age; // 指针变量
  int arr[10]; // 数组变量

  struct Student 
  {
    char name[20];
    int id;
  } stu; // 结构体变量

  union Data 
  {
    int x;
    char c;
  } data; // 联合体变量

  enum Color { RED, GREEN, BLUE }; // 枚举变量

  printf("char: %c, short: %d, int: %d\n", ch, num, age);
  return 0;
}

1.1字符型

char
 [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中也引⼊了布尔类型,是专⻔表⽰真假的。

布尔类型的使⽤得包含头⽂件 <stdbool.h>

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

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

用代码展示

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

二、各种数据类型的⻓度

2.1 sizeof操作符

C语言中的sizeof操作符用来计算数据类型或表达式所占用的内存字节数。

sizeof主要有以下几种用法:

  1. 计算数据类型大小
sizeof(类型名)
• 1

例如:

sizeof(int) // 4 
sizeof(char) // 1
  1. 计算数组元素个数
sizeof(数组名) / sizeof(数组元素类型)
• 1

例如:

  1. 计算结构体大小
sizeof(结构体名)
• 1

例如:

  1. 计算表达式大小
sizeof(表达式)
• 1

例如:

C语言标准只规定sizeof运算符返回一个无符号整数,但并没有明确指定返回值的具体类型

这就可能导致程序的可移植性问题:

  • 不同系统下,sizeof返回值类型可能不同,使用不当类型的格式化输出可能会出错,返回值的类型有可能是unsigned int ,也有可能是 unsigned long ,甚⾄是 unsigned long long ,对应的 printf() 占位符分别是 %u 、 %lu 和 %llu。


  需要存储sizeof结果的变量也需要使用正确的类型,否则可能会溢出或截断。

C语言提供了size_t类型来解决这个问题:

  • size_t是一个类型别名,它会被定义为当前系统下sizeof返回值的正确类型,可能是unsigned intunsigned long等。
  • 程序使用size_t来存储和操作sizeof结果,就可以保证类型安全且可移植。
  • 格式化输出时使用%zd,它会自动匹配size_t类型
#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(6 + 8.8));
 return 0;
}

2.2 数据类型⻓度

您总结得很好,我重新梳理一下C语言主要数据类型的长度:

  • char: 1字节
  • hort: 2字节

int: 32/64位系统通常为4字节

long: 4字节

long long: 8字节

float: 4字节

double: 8字节

void*: 与系统地址长度相同,32位系统为4字节,64位系统为8字节

size_t: 与系统地址长度相同,用来表示sizeof()函数返回值的类型

X86配置下的输出:

X64配置下的输出:

2.3 sizeof中表达式不计算

sizeof运算符计算的不是表达式的值,而是类型的大小。

更准确地说,sizeof运算符返回它操作数类型的大小,单位为字节。

如果操作数是一个类型,那么它直接返回该类型的大小;

如果操作数是一个表达式,那么它返回表达式类型的大小。

举个例子:

int main()
{
  int a = 10;
  int b = 20;
  short s = 2;
  int c = 30;

  printf(" %zd\n", sizeof(int)); // 返回int类型大小,如4字节
  printf(" %zd\n", sizeof(a)); // 返回int类型大小,如4字节,和sizeof(int)相同  
  printf(" %zd\n", sizeof(a + b)); // 返回int类型大小,如4字节,计算a + b的类型是int
  printf(" %zd\n", sizeof(s = c + 1));
  printf("s = %d\n", s);

  return 0;
}

在sizeof(a + b)中:


a + b是一个表达式,计算结果是int类型


sizeof不计算a + b的实际值,而是直接返回其类型int的大小


sizeof(s = c + 1)


s = c + 1是一个赋值表达式,计算c+1的值,结果是int类型

但赋值的对象是short类型变量s

所以sizeof返回short类型的大小,即2字节

sizeof返回类型大小,不计算表达式值

  • 表达式计算和赋值可能涉及类型转换

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

三、signed 和 unsigned

signed和unsigned关键字用于指定整数类型的符号:


signed: 有符号整数类型,可以表示正数和负数。默认情况下所有整数类型(char、short、int、long)都是signed的。


unsigned: 无符号整数类型,只能表示非负整数,范围比signed类型更大。

主要区别:


存储表示:


signed类型用二进制最高位表示数值的符号,正数为0,负数为1。


unsigned类型最高位都是数值本身,不表示符号。


数值范围:


signed类型的范围依赖于其位宽,如int为-2147483648到2147483647。


unsigned类型没有符号位,所以范围比signed类型更大,如uint为0到4294967295。


运算结果:


signed类型在一些运算中可能会发生溢出。


unsigned类型不会发生溢出,超出范围直接循环回到最小值。

小例子:

#include <stdio.h>

int main()
{
  unsigned int a = 10;
  signed int b = 10;

  a -= 20;
  b -= 20;

  printf("a = %zu\n", a);
  printf("b = %zd\n", b);

  return 0;
}

第一种分析:

  • a为unsigned int,范围0-4294967295
  • a原值为10,减20后为-10
  • 但unsigned int没有负数表示,所以-10会溢出计算为最大值4294967295
  • b为signed int,范围-2147483648-2147483647
  • b原值为10,减20后为-10
  • -10正好在signed int范围内,所以结果正确输出为-10
  • 这里unsigned intsigned int在减法溢出后的表现不同:
  • unsigned int溢出后取最大正值
  • signed int保留数值的符号,输出负数

所以这个例子更清晰地展示了signed和unsigned类型在溢出情况下的区别。

二进制重新解释这道题:

题目中有两个变量:

题目中有两个变量:


unsigned int a,其范围为0-4294967295


signed int b,其范围为-2147483648-2147483647


开始时:


a = 10

b = 10


然后执行:


a -= 20

b -= 20


分析:


对于a来说,它是unsigned int类型,没有负数表示。

当a-=20时,正确的二进制计算是:

a原值: 0000 0000 0000 0000 0000 0000 0000 1010 (10)

a-=20:  0000 0000 0000 0000 0000 0000 0000 0110 (-10,但unsigned int没有负数)

1

2

由于结果-10超出了unsigned int的范围,所以根据无符号溢出规则,高位溢出位被舍弃,结果保留为最大正值:


0000 0000 0000 0000 0000 0000 0000 0110 溢出为4294967295

1

对于b来说,它是signed int类型,可以表示负数。

当b-=20时,二进制计算是:

b原值: 0000 0000 0000 0000 0000 0000 0000 1010 (10)  

b-=20: 1111 1111 1111 1111 1111 1111 1111 1010 (-10)

1

2

-10处于signed int的有效范围内,所以结果直接输出-10。


总之,通过这个例子可以清晰地看出:


unsigned int在溢出时结果取最大正值

signed int根据符号位判断正负,直接输出结果

四、数据类型的取值范围

C语言主要的数据类型和其取值范围如下:


用二进制来解释C语言主要数据类型的取值范围:

它的高位为符号位:0表示正数,1表示负数。


char

1字节,表示为8位二进制

高位为符号位,0表示正数,1表示负数

所以取值范围是:0xxx xxxx ~ 0111 1111,即0~ 127为正数,-128 ~ -1为负数

unsigned char

也是1字节8位二进制

但没有符号位,所以全为数据位

取值范围是:0000 0000 ~ 1111 1111,即0~255

short

2字节,表示为16位二进制

高位为符号位,0表示正数,1表示负数

所以取值范围是:0xxx xxxx xxxx xxxx ~ 0111 1111 1111 1111,即0~ 32767为正数,-32768~ -1为负数 (这里的"xxx"代表低15位可以是0或者1,也就是数据位。)

unsigned short

也是2字节16位二进制

没有符号位,所以全为数据位

取值范围是:0000 0000 0000 0000 ~ 1111 1111 1111 1111,即0~65535


相关文章
|
7月前
|
存储 Java 数据库
第二章 变量、数据类型和运算符
第二章 变量、数据类型和运算符
|
3月前
|
存储 C# 索引
C# 一分钟浅谈:变量与数据类型简介
【9月更文挑战第1天】在 C# 编程中,了解变量与数据类型至关重要。本文详细介绍了 C# 中的值类型(如整数、浮点数、布尔值等)和引用类型(如类、接口、数组、字符串)。通过示例代码展示了变量的声明与使用方法,并针对数据类型转换错误、变量未初始化及数值溢出等常见问题提供了解决方案。正确选择数据类型不仅能提升程序性能,还可避免潜在错误,有助于编写高质量代码。
136 47
|
2月前
|
存储 程序员 Python
Python编程入门:探索变量和数据类型
【10月更文挑战第8天】本文是针对初学者的Python编程入门指南,重点介绍Python中变量的定义和使用以及不同的数据类型。我们将通过实例来理解基本概念,并展示如何在Python程序中应用这些知识。文章旨在帮助初学者建立扎实的基础,使他们能够更自信地编写Python代码。
|
3月前
|
C语言
C语言程序设计核心详解 第二章:数据与数据类型 4种常量详解 常见表达式详解
本文详细介绍了C语言中的数据与数据类型,包括常量、变量、表达式和函数等内容。常量分为整型、实型、字符型和字符串常量,其中整型常量有十进制、八进制和十六进制三种形式;实型常量包括小数和指数形式;字符型常量涵盖常规字符、转义字符及八进制、十六进制形式;字符串常量由双引号括起。变量遵循先定义后使用的规则,并需遵守命名规范。函数分为标准函数和自定义函数,如`sqrt()`和`abs()`。表达式涉及算术、赋值、自增自减和逗号运算符等,需注意运算符的优先级和结合性。文章还介绍了强制类型转换及隐式转换的概念。
|
6月前
|
存储 C++ 容器
C++一分钟之-变量与数据类型入门
【6月更文挑战第18天】**C++编程基础:变量与数据类型概览** 了解变量(存储数据的容器)和数据类型是编程入门的关键。声明变量如`int age = 25;`,注意初始化和类型匹配。基本数据类型包括整型(int等)、浮点型(float、double)、字符型(char)和布尔型(bool)。理解类型范围和精度,使用字面量后缀增强可读性。深入学习数组、指针、结构体和类,以及动态内存管理,避免数组越界和内存泄漏。不断实践以巩固理论知识。
45 1
|
7月前
|
存储 C++
第一章:C++中的注释、变量和数据类型、运算符
第一章:C++中的注释、变量和数据类型、运算符
49 0
|
存储 编译器 C#
C# 变量数据类型的使用和案例(基础篇)
C# 变量数据类型的使用和案例(基础篇)
|
存储 编译器 C语言
C语言数据类型类型及语句(各种详细的细节以及基础+持续更新中
C语言数据类型类型及语句(各种详细的细节以及基础+持续更新中
234 0
C语言数据类型类型及语句(各种详细的细节以及基础+持续更新中
|
存储 C++ Windows
第二章:数据类型
第二章:数据类型
65 0
|
存储 Oracle Java
第二章、 数据类型与变量
JavaSE:基本数据类型的讲解和解析,便于已学同学进行复习或刚开始学习Java的学生进行理解。
51 0