C语言数据类型一文详解

Posted 攻城狮白玉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言数据类型一文详解相关的知识,希望对你有一定的参考价值。

目录

前言

一、基本数据类型

1.1 整数类型

1.1.1 整型int

1.1.2 短整型short

1.1.3 长整型long

1.2 浮点型

1.3 字符型char

1.4 无符号型unsigned

1.5 小结

二、构造类型

2.1 数组

2.1.1 声明(定义)数组

2.1.2 初始化数组

2.1.3 元素的访问和修改

2.2 结构体

2.2.1 定义结构体

2.2.2 初始化结构体

2.2.3 小结

三、指针类型

3.1 指针的声明和初始化

3.2 空指针和野指针

3.3 小结

四、空类型void

4.1 小结

五、总结

写在最后


前言

学习一门编程语言,要掌握的基础肯定离不开数据类型。因为数据类型是用来约束数据的解释。通俗一点来说,数据类型决定了这个变量在程序中占的内存大小。而变量名是我们的程序对于可操作的存储空间的一个别名。

C语言的数据类型大致可以分类四大类:

  • 基本数据类型
  • 构造类型
  • 指针类型
  • 空类型

环境:Win10

IDE是:dev C++

一、基本数据类型

1.1 整数类型

整数类型里包含了整型int、短整型short、长整型long

1.1.1 整型int

整型的关键字是int,定义一个整型变量时,只需要用int来修饰即可。

int i_baiyu;

int占4个字节,一个字节(Byte)=8位(bit),所以int型变量是32位的。

int数的值范围是 -2,147,483,648 到 2,147,483,647,如果不考虑正负,数值范围则是0到4,294,967,295

上面几个很大的数值是这么得到的,-(2^32)/2= -2,147,483,648,(2^32)/2-1=2,147,483,647。

(2^32-1)=4,294,967,295

1.1.2 短整型short

短整型的关键字是short,占2个字节,数据范围是-(2^8)/2=-32,768 到 (2^8)/2-1=32,767

1.1.3 长整型long

长整型的关键字是long,占4个字节,范围是 -2,147,483,648 到 2,147,483,647,如果不考虑正负,数值范围则是0到4,294,967,295

1.2 浮点型

浮点型又分单精度浮点型float和双精度浮点型double.

两者的都可以用来存放小数,区别在于双精度浮点型可以精确的小数位比单精度浮点型的多。

float占4个字节,数值范围是1.2E-38 到 3.4E+38,精确到小数点后六位

double占8个字节,数值范围是2.3E-308 到 1.7E+308,精确到小数点后15位

1.3 字符型char

前面的整型和浮点型都是用于存放数字。字符型,用于存放字符。

字符型的关键字是char,声明的变量占1个字节,数据范围是-128~127或者0~255。

1.4 无符号型unsigned

其实编译器默认在我们声明上面的变量时,就缺省加上了signed这个关键字。当我们的变量需要变成无符号数时,需要用到unsigned进行修饰。

无符号型:类型说明符为unsigned。unsigned可以搭配前面的int、short、long一起使用,用unsigned修饰后的数字,就是不带负号了,也就是不能存放负数。

  • 无符号基本型:类型说明符为unsigned int或unsigned。
  • 无符号短整型:类型说明符为unsigned short。
  • 无符号长整型:类型说明符为unsigned long。

注:不能定义unsigned float和unsigned double类型。否则会报错。

下面通过代码来直观的感受一下各个数据类型所占的字节大小。sizeof是C语言内置的一个函数,用于查看变量所占的空间大小。

#include<stdio.h>
int main(void) {

    char c_baiyu = 'a';//字符型数据占1个字节 
    short s_baiyu = 11;//短整型数据占2个字节 
    
    int i_baiyu = 97;//整型数据占4个字节 
    long l_baiyu = 666;//长整型数据占4个字节 
    
    float f_baiyu = 5.0;//单精度浮点型数据占4个字节 
    double d_baiyu = 2.22222;//双精度浮点型占8个字节 
    
    printf("字符型数据 c_baiyu 占 %d 个字节\\n",sizeof(c_baiyu));
    printf("短整型数据 s_baiyu 占 %d 个字节\\n",sizeof(s_baiyu));

    printf("整型数据 i_baiyu 占 %d 个字节\\n",sizeof(i_baiyu));
    printf("长整型数据 l_baiyu 占 %d 个字节\\n",sizeof(l_baiyu));
    
    printf("单精度浮点型数据 f_baiyu 占 %d 个字节\\n",sizeof(f_baiyu));
    printf("双精度浮点型数据 d_baiyu 占 %d 个字节\\n",sizeof(d_baiyu));
    
    unsigned int ui_baiyu =999;
    unsigned short us_baiyu =10;
    unsigned long ul_baiyu =456;
    
    printf("无符号整型数据 ui_baiyu 占 %d 个字节\\n",sizeof(ui_baiyu));
    printf("无符号短整型数据 us_baiyu 占 %d 个字节\\n",sizeof(us_baiyu));
    printf("无符号长整型数据 ul_baiyu 占 %d 个字节\\n",sizeof(ul_baiyu));
    
    return 0;
}

代码运行结果如下:

 

1.5 小结

C 语言里有六种基本数据类型,分别用short、int、long、char、float、double 这六个关键字表示。编译器默认在short、int、long前面是带了signed关键字。如果需要变量不带负数时,则需要用unsigned关键字进行修饰

数据类型

名称

占用内存

值范围

char

字符型

1 byte

-128 到 127 或 0 到 255

short

短整型

2 byte

-32,768 到 32,767

int

整型

4 byte

-2,147,483,648 到 2,147,483,647

long

长整型

4 byte

-2,147,483,648 到 2,147,483,647

float

单精度浮点型

4 byte

1.2E-38 到 3.4E+38

double

双精度浮点型

8 byte

2.3E-308 到 1.7E+308

unsigned int

无符号整型

4 byte

0~ 4,294,967,295

unsigned short

无符号短整型

2 byte

0~65535

unsigned long

无符号长整型

4 byte

0~ 4,294,967,295

注:一个字节(byte)=8位(bit),值范围就是2的几次方,比如char型是一个字节,也就是8位,所以char型变量的取值最大就是2^8=255

#include <stdio.h>
int main()
{
    char c_baiyu = 'a';//字符类型
    char c_baiyu_1 = 97;//字符类型也可以用ASCII码赋值
    
    printf("字符型数据 c_baiyu:%c\\n",c_baiyu) ;
    printf("字符型数据 c_baiyu_1:%c\\n",c_baiyu_1) ;
    
    short s_baiyu = 11;
    printf("短整型数据 s_baiyu:%d\\n",s_baiyu) ;
    
    int i_baiyu = 100;
    printf("整型数据 i_baiyu:%d\\n",i_baiyu) ;
    
    long l_baiyu = 666;
    printf("长整型数据 l_baiyu:%d\\n",l_baiyu) ;
    
    float f_baiyu = 1.0;
    printf("单精度浮点型数据 f_baiyu:%f\\n",f_baiyu) ;
    
    double d_baiyu = 2.22222;
    printf("双精度浮点型数据 d_baiyu:%f\\n",d_baiyu) ;
        
    return 0;
} 

二、构造类型

2.1 数组

经过前面的学习,当我们需要定义5个int变量,用来表示5个学生的学号时,我们会怎么做?

可能会按下面的操作

int baiyu_1=1, baiyu_2=2, baiyu_3=3, baiyu_4=4, baiyu_5=5;

我们会发现这样其实有点麻烦,而且这五个变量的类型都一样,作用都一样。那我们能否把这5个变量整合在一起呢?

答案是肯定的。C语言提供了【数组】这种数据结构。

数组可以看作是一系列相同类型变量的一个集合,而这个集合的名称就叫数组名。

比如上面的例子,咱们可以声明一个数组来代替

int baiyu[5] = {1,2,3,4,5};//baiyu 就是数组名,这里是声明了一个长度为5的int型数组

所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。

2.1.1 声明(定义)数组

数组跟变量一样,需要先声明(定义)再使用。

C语言中,声明一个数据的时候,需要说明【数据类型】【数组名】以及【数组长度】,格式如下:

数据类型 数组名称[ 数组长度 ];

看代码,会直观些

int arr_i_baiyu[10];//声明了一个数组长度为 10 的 int 型数组 arr_i_baiyu
char arr_c_baiyu[5]; //声明了一个数组长度为 5 的 int 型数组 arr_c_baiyu
float arr_f_baiyu[7]; //声明了一个数组长度为 7 的 int 型数组 arr_f_baiyu
double arr_d_baiyu[9]; //声明了一个数组长度为 9 的 int 型数组 arr_d_baiyu

2.1.2 初始化数组

当你声明了数组之后,没有对数组进行初始化,则数组里面的元素默认为0。

在 C语言 中,您可以逐个初始化数组,也可以使用一个初始化语句,如下所示:

float arr_f_baiyu[7] = {1.1, 2.1, 3.3, 45.4, 5.6, 6.6, 7.8};

{}花括号里面的元素用【逗号】隔开,元素的个数不能超过我们在,[]中括号里面写的数字。

比如上面我们声明的arr_f_baiyu数组的长度为7,则花括号{}里面的元素个数不能超过7。

如果你一开始,没有说明数组的长度直接赋值进行初始化,则数组的长度为你元素的个数

float arr_f_baiyu[] = {1.1, 2.1, 3.3, 45.4, 5.6, 6.6, 7.8};

这里的数组初始化,跟前面的那句创建数组效果是一模一样的,都是声明了一个长度为7的数组,赋值也都一模一样。

下面举个不一样的例子,是声明并初始化了一个长度为5的double型数组

double arr_d_baiyu[] = {5.0, 4.0, 3.0, 2.0, 1.0};//这里是初始化了一个长度为5的double型数组

2.1.3 元素的访问和修改

当我们需要访问数组中的元素时,只需要引用对应的下标。

//for循环遍历数组元素
int i;
for (i=0; i<5; i++) {
    printf("arr_d_baiyu[%d]的值:%f\\n",i, arr_d_baiyu[i]);
}
double d_baiyu = arr_d_baiyu[1];//这里是把4.0赋值给 d_baiyu

当我们需要修改数组中的元素时,只需要引用对应的下标,然后重新赋值。比如咱们上面的 arr_d_baiyu 数组的第4个元素进行修改,把它修改为6.66

arr_d_baiyu[3] = 6.66;

#include<stdio.h>
int main() {
    int arr_i_baiyu[10];//声明了一个数组长度为 10 的 int 型数组 arr_i_baiyu
    char arr_c_baiyu[5]; //声明了一个数组长度为 5 的 int 型数组 arr_c_baiyu

    //声明了一个数组长度为 7 的 int 型数组 arr_f_baiyu
    float arr_f_baiyu[7] = {1.1, 2.1, 3.3, 45.4, 5.6, 6.6, 7.8};

    //这里是初始化了一个长度为5的double型数组arr_d_baiyu
    double arr_d_baiyu[] = {5.0, 4.0, 3.0, 2.0, 1.0};

    //for循环遍历数组元素
    int i;
    for (i=0; i<5; i++) {
        printf("arr_d_baiyu[%d]的值:%f\\n",i, arr_d_baiyu[i]);
    }

    double d_baiyu = arr_d_baiyu[1];//这里是把4.0赋值给 d_baiyu

    printf("d_baiyu的值:%f\\n",d_baiyu);

    printf("修改前 arr_d_baiyu[3] 的值为:%f\\n",arr_d_baiyu[3]);
    arr_d_baiyu[3] = 6.66;
    printf("修改后 arr_d_baiyu[3] 的值为:%f\\n",arr_d_baiyu[3]);
}

2.2 结构体

如果说数组是一组相同类型的数据的集合,那么结构体是一组不同类型的数据的集合。

结构体通常用来描述一个变量多方面的属性。

struct structName {

member-list;

member-list;

member-list;

……
} structVariable-list ;

struct 是声明结构体用到的关键字

structName 是结构体名称

member-list 是标准的变量定义

structVariable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量

举个例子,形象一点,咱们要描述一个人,就会说到他的年龄、姓名、身高。那么咱们可以创建一个名为People的结构体

struct People {
    int age;
    char name[100];
    double height;
};

2.2.1 定义结构体

// 定义了一个有三个成员的名为People的结构体,没有声明变量
struct People {
    int age;
    char name[100];
    double height;
};
//此处声明了一个People的结构体变量baiyu
struct People baiyu;

/*** 定义了一个有三个成员的名为PeopleInfo 的结构体,同时声明了结构体变量zhh***/
struct PeopleInfo {
    int age;
    char name[100];
    double height;
}zhh;

2.2.2 初始化结构体

和其它类型变量一样,对结构体变量可以在定义时指定初始值。

// 定义了一个有三个成员的名为People的结构体,没有声明变量
struct People {
    int age;
    char name[100];
    double height;
};

//此处声明了一个People的结构体变量zhh_baiyu 并赋了初始值
struct People zhh_baiyu = {15,"zhh_baiyu",1.90};

也可以在声明变量之后赋初始值

//此处声明了一个People的结构体变量 baiyu
struct People baiyu;
//对baiyu的结构体成员进行赋值
baiyu.age = 18;
baiyu.name = "baiyu";
baiyu.height = 1.85;

引用结构体成员的时候,使用成员访问运算符【.】一个句号。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个句号

#include<stdio.h>
int main() {
    // 定义了一个有三个成员的名为People的结构体,没有声明变量
    struct People {
            int age;
            char name[100];
            double height;
    };
    //此处声明了一个People的结构体变量 baiyu
    struct People baiyu;
    //对baiyu的结构体成员进行赋值
    baiyu.age = 18;
    strcpy(baiyu.name , "baiyu");
    baiyu.height = 1.85;

    //输出结构体变量 baiyu 的信息 
    printf("%s的age为:%d, height为:%f\\n",baiyu.name,baiyu.age,baiyu.height) ;

    //此处声明了一个People的结构体变量zhh_baiyu 并赋了初始值
    struct People zhh_baiyu = {15,"zhh_baiyu",1.90};
    //输出结构体变量 zhh_baiyu 的信息 
    printf("%s的age为:%d, height为:%f\\n",zhh_baiyu.name,zhh_baiyu.age,zhh_baiyu.height) ;
    /*
    定义了一个有三个成员的名为 PeopleInfo 的结构体,
    同时声明了结构体变量zhh 并且为zhh这个变量赋值初始化
    */
    struct PeopleInfo {
            int age;
            char name[100];
            double height;
    } zhh = {17,"zhh",1.89};
    
    //输出结构体变量 zhh 的信息 
    printf("%s的age为:%d, height为:%f\\n",zhh.name,zhh.age,zhh.height) ;

}

2.2.3 小结

数组跟结构体都是属于构造类型的数据。都由多个元素or成员组成。区别在于,数组是一系列相同数据类型的元素的集合。而结构体则是由不同数据类型的成员构成。结构体的成员数据类型可以是基本数据类型、也可以是构造类型的数据类型,也就是说,结构体成员的数据类型也可以是数组或者结构体。

三、指针类型

3.1 指针的声明和初始化

指针是一种特殊的变量类型。

每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。而指针则是指向了这个变量所在的内存地址。

这样子可能不太好理解,咱们举个例子

比如:baiyu是住在贝克街221号B,那么baiyu(变量)所住的地方(内存),而门牌号(指针)贝克街221号B(内存地址)

指针就是相当于咱们的门牌号,指向的是内存所在的地址。指针变量是用来存放内存地址的变量。

指针变量的声明格式如下:

数据类型 *指针变量名

这里的数据类型跟咱们前面提到的数据类型是一致的,也就是int、char、double、float这些

int    *i_baiyu_p;    /* 一个整型的指针 */
double *d_baiyu_p;    /* 一个 double 型的指针 */
float  *f_baiyu_p;    /* 一个浮点型的指针 */
char   *c_baiyu_p;    /* 一个字符型的指针 */

下面咱们通过一个编程的例子来更加形象的理解指针变量与普通变量的关系。

  1. 定义一个int型变量i_baiyu,并且赋值为666
  2. 定义一个指针变量i_baiyu_p、把变量i_baiyu地址赋值给指针。(这里通过取地址符&把变量i_baiyu的地址取出。)
  3. 访问指针变量i_baiyu_p中可用地址的值,通过取值运算符*将指针变量里地址对应的变量值取出。(这里的*并不是乘号,而是取值运算符来返回位于操作数所指定地址的变量的值。)
#include<stdio.h> 
int main(){
    int i_baiyu = 666;// 定义了一个int型变量i_baiyu ,并且赋值为666
    //声明了一个指针变量i_baiyu_p,并且把变量i_baiyu的地址赋值给指针 
    int *i_baiyu_p = &i_baiyu; // &是取地址符
    printf("i_baiyu的值为:%d \\n",i_baiyu);
    printf("i_baiyu的地址为:0x%X \\n",&i_baiyu);
    printf("i_baiyu_p的值为:0x%X \\n",i_baiyu_p);
    printf("i_baiyu_p指向的值为:%d \\n",*i_baiyu_p);//指针变量前面的*是取值运算符
    return 0;
}

 

3.2 空指针和野指针

在指针变量声明的时候,如果没有确切的地址可以赋值,最好给指针变量赋值一个初始值为NULL。被赋为 NULL 值的指针被称为空指针

#include<stdio.h>
int main() {
    int i_baiyu = 666;// 定义了一个int型变量i_baiyu ,并且赋值为666
    //声明了一个指针变量i_baiyu_p,并且置为空指针 
    int *i_baiyu_p = NULL;
    i_baiyu_p = &i_baiyu;//把变量i_baiyu的地址赋值给指针i_baiyu_p
    printf("i_baiyu的值为:%d \\n",i_baiyu);
    printf("i_baiyu的地址为:0x%X \\n",&i_baiyu);
    printf("i_baiyu_p的值为:0x%X \\n",i_baiyu_p);
    printf("i_baiyu_p指向的值为:%d \\n",*i_baiyu_p);
}

野指针是指那些我们不知道地址是指向哪里的指针变量。

因为如果我们在指针变量声明的时候,没有给指针进行明确的赋值,或者置为空指针时,指针变量指向的位置是不可知的(随机的、不正确的、没有明确限制的)。这样的指针被称为野指针。此时我们对于指针进行解引用就是去访问了一个不确定的地址,所以结果是不可知的。

野指针出现的另外一种情况是当我们对于一个指针在进行free或delete操作后并未赋值为 NULL 的,可能该指针会被认为是合法的。进行调用从而出现一些未可知的结果。

3.3 小结

每一个变量都有一个内存位置,每一个内存位置都定义了可使用【&】运算符访问的地址,它表示了在内存中的一个地址。访问指针变量中可用地址的值,通过取值运算符【*】将指针变量里地址对应的变量值取出这个操作也被叫做解引用。

四、空类型void

一种特殊的返回类型,表示为空,没有可用的值。

void常用在程序编写中对定义函数的参数类型、返回值、函数中指针类型进行声明

  • 函数返回值为空
  • 函数参数为空——当我们不需要任何返回值时,可以在函数的参数列表里写上void,参数列表什么都不写时,缺省为void
  • 指针指向 void——void* :则为“无类型指针”,可以指向任何类型的数据。

也可以用于表示空

#include<stdio.h> 
//当主函数为void类型时,可以没有返回值,也就是不用return
void main(void){ //参数列表为空时,可以写上void,也可以缺省不写 
    int i_baiyu = 666;
    printf("i_baiyu的值为:%d \\n",i_baiyu);
}

4.1 小结

序号

类型与描述

1

函数返回为空

C 中有各种函数都不返回值,或者您可以说它们返回空。不返回值的函数的返回类型为空。例如 void exit (int status);

2

函数参数为空

C 中有各种函数不接受任何参数。不带参数的函数可以接受一个 void。例如 int main(void);

3

指针指向 void

类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size ); 返回指向 void 的指针,可以转换为任何数据类型。

五、总结

本文详细介绍了C语言的各种数据类型,也附带了代码例程。不过也有一些数据类型没有介绍到的,比如枚举类型enum,共用体union类型。

写在最后

如果觉得有用的话,请一键三连,你的支持就是我写下去的动力~

如果觉得本文还有不足,或者有不清楚的地方,欢迎评论区留言,或者私信交流~

以上是关于C语言数据类型一文详解的主要内容,如果未能解决你的问题,请参考以下文章

C语言函数详解(入门到进阶)

C语言小妹不懂指针和数组的关系?那就安排指针数组关系详解

C语言typedef详解

一文详解 RNN 及股票预测实战(Python)!

一文教你如何用C代码解析一段网络数据包?含代码

一文教你如何用C代码解析一段网络数据包?含代码