[C++] C++基础(二) C++中的数据处理

本文深入探讨C++中的数据处理,涵盖了基本数据类型,包括整型、浮点型和布尔型的细节。介绍了无符号类型、sizeof运算符、climits头文件以及整型字面量的使用。此外,还讲解了数据初始化、const限定符、auto关键字和类型转换。在复合类型方面,详细阐述了数组、字符串、结构体、联合体和枚举的创建、初始化和操作,以及C++11的新特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.基本数据类型

整型

整型数据包括以下几类char、short、int、long、long long五种,每种根据有无符号又可以分为两种,因此共有11种(加上wchar_t)。

在c++中,每种类型的长度都不定,但提供了一个确保了最小长度的标准,如:

  • short:至少16位长;
  • int:至少和short一样;
  • long:至少32位长;
  • long long:至少64位长;
无符号类型和有符号类型

默认情况下,数据类型表示有符号类型,可以存储负值。如一般情况下,short类型为2个字节16位,其取值范围为-32768~+32767,则无符号short的范围为0~65535.使用unsigned关键字来声明无符号类型:

unsigned short i = 3;

因此,只有确保数值中不会出现负值时才可使用无符号类型。

如果一个变量超过了其类型所能表示的范围,其值将为范围另一端的取值:

#include <iostream>
#define ZERO 0
#include <climits>

int main()
{
        using namespace std;
        short sam = SHRT_MAX;
        unsigned short sue = sam;
    
        cout << "Sam has " <<sam<<" dollars,sue has "<<sue<<" dollars"<<endl;
        cout <<"Add 1 to each account."<<endl<<"Now ";
        sam = sam +1; 
        sue = sue +1; 
        cout << "Sam has " <<sam <<" dollars,sue has "<<sue<<" dollars"<<endl;
    
        sam = sue = ZERO;

        sam = sam -1; 
        sue = sue -1; 

        cout << "Sam has " <<sam<<" dollars,sue has "<<sue<<" dollars"<<endl;
        return 0;
}
/**
输出:
Sam has 32767 dollars,sue has 32767 dollars
Add 1 to each account.
Now Sam has -32768 dollars,sue has 32768 dollars
Sam has -1 dollars,sue has 65535 dollars
/

sizeof运算符

想知道对应整型数据在计算机中占多少个字节,可以通过sizeof运算符得到:

#include <iostream>

using namespace std;

int main()
{
        int i = 1;
        short s = 2;
        long l = 34; 
        long long ll = 43; 
    
        cout <<"int's byte:" << sizeof (int) <<endl;
        cout <<"int's byte:" << sizeof i <<endl;
        cout <<"short's byte:" << sizeof (short) <<endl;
        cout <<"long's byte:" << sizeof (long) <<endl;
        cout <<"long long's byte:" << sizeof (long long) <<endl;
        return 0;
}
/**
输出:
int's byte:4
int's byte:4
short's byte:2
long's byte:8
long long's byte:8
/
cout.put()方法

cout.put()可以用来输出字符:

#include <iostream>
using namespace std;

int main()
{
        char ch = 'M';
        cout.put(ch);
        cout << "ch:" << ch <<endl;
        return 0;
}
/**
输出:
Mch:M
/

climits头文件

climits头文件中定义了关于整型限制的信息,如:

#include <iostream>
#include <climits>

using namespace std;

int main()
{
        int s = 1;
        cout << "s:" << sizeof(s) << endl;
        int n_int = INT_MAX;
        int m_int = INT_MIN;
        short n_short = SHRT_MAX;
        short m_short = SHRT_MIN;
        long n_long = LONG_MAX;
        long m_long = LONG_MIN;
        char n_char = CHAR_MAX;
        char m_char = CHAR_MIN;
        long long n_llong = LLONG_MAX;
        long long m_llong = LLONG_MIN;
    
        cout <<"max int:" << n_int <<endl;
        cout <<"min int:" << m_int <<endl;
        cout <<"max shor" << n_short <<endl;
        cout <<"min shor" << m_short <<endl;
        cout <<"max long:" << n_long <<endl;
        cout <<"min long:" << m_long <<endl;
        cout <<"max char:" << n_char <<endl;
        cout <<"min char:" << m_char <<endl;
        cout <<"max long long:" << n_llong <<endl;
        cout <<"min long long:" << m_llong <<endl;
        return 0;
}
/**
输出:
s:4
max int:2147483647
min int:-2147483648
max shor32767
min shor-32768
max long:9223372036854775807
min long:-9223372036854775808
max char:
min char:�
max long long:9223372036854775807
min long long:-9223372036854775808

/

更多的climits中定义的符号名称请点击这里.

整型字面量

整型数据可以有三种表示法:八进制、十进制、十六进制,和java一样,八进制数据以0开头,十六机制数据使用0x开头。

默认情况下,使用cout输出时,采用十进制形式,也可以通过指定一个格式输出:

#include <iostream>

int main()
{
        using namespace std;

        int chest = 42; 
        int waist = 42; 
        int inseam = 42; 

        cout << "10进制:" << chest << endl;
        cout << hex;//指定十六进制输出
        cout << "16进制:" << waist << endl;
        cout << oct;
        cout << "8进制: " << inseam << endl;
        return 0;
}

cout<<hex等形式代码不会在屏幕上输出任何内容,只会修改cout显示整数的方式。

布尔(bool)型

布尔值只有两个:true和false:

bool isTrue = true;

任何数字也可以隐式转换为bool值,非零数表示true,0表示false。

bool start = 0;

浮点型

浮点类型可以存储小数,c++中有三中浮点类型:float、double、long double.计算机内部存储浮点类型时,将值分成两部分存储:值和缩放因子。如:

float f1 = 3.1415926;//由基准值0.31415926和缩放因子10组成
float f2 = 31.415926;//由基准值0.31415926和缩放因子100组成

通常,float为32位,double为64位,long double 为80或96等。

一般,可在float类型常量后使用f/F后缀,在double类型常量后面使用L后缀。

数据的初始化

在C++中,初始化数据有三种方式:

  • 1.传统方式:
int i = 2;
double d = 3.4L;
  • 2.C++语法方式:
int s(4);//相当于int s = 4;
  • 3.列表初始化
int s  = {12};//int s = 12;
int s = {};//int s = 0;

在c++11中,还可以省略上面的等号:

int s{23};

这种方式一般用来初始化数组和结构体。

为什么会有这么多的初始化方式呢?只不过是为了更容易学习C++而已。

const限定符

如果要定义一个只读的常量,有两种方式:#define预处理器编译指令和const限定符,前者是C中的语法,后者是C++中特有。

const int SIZE = 20;
//或者
#define SIZE 20

应在变量声明时就对const进行初始化,否则将编译失败:

const int s;//s未提供值,因此编译器将提供一个不确定值
s = 20; //s 已经被编译器赋值,因此将失败
#define预处理器编译指令

#define和#include一样,是一个预处理器编译指令,以#define SIZE 21为例,该指令告诉预处理器,在程序中查找SIZE,并将所有的SIZE替换成21。

因此,#define工作方式和文本处理器中的全局搜索并替换命令相似。
在C++中,可以使用const来创建符号常量。但是,有些头文件需要在C和C++中都可用,那么必须使用#define。

auto关键字

在初始化声明中,如果使用auto关键字,而不指定变量的类型,则编译器讲吧变量的类型设置成与初始值相同。

auto i = 3;//i为int
auto x = 1.4;//x为float
auto d = 12.dL;//d为double

但是auto关键字并非为基本类型而设计,auto多用于复杂类型。因此在基本类型使用时,尽量避免使用auto。如下示例中使用了auto:

#include <iostream>
#include <cstring>

struct student
{
        char name[20];
        int age;
        float score;
};

int main()
{
        student s1={"XiaoMing",12,67};
        student s2 = {"ZhangHua",12,89};

        student * ps = &s1;
        student all[3];
        //all[0].name = "XiaoHong";BAD,不能使用=号
        strcpy(all[0].name,"XiaoHong");
        std::cout << all->name << std::endl;
        //定义一个指针数组
        student * p_all[3] = {&s1,&s2};
        //根据p_all的类型自动推断出p_all_new的类型
        auto p_all_new = p_all;
        std::cout << (*p_all_new)->name << std::endl;   
        return 1;
}
/**
XiaoHong
XiaoMing
/

基本类型之间的类型转换

1.自动转换

  • 1.C++中允许一种类型的值赋给另一种类型。如果将较小类型的值赋给较大类型时,会占用更多字节,因此不会出现问题,反之,则会出现问题。

  • 2.在计算时,C++ 将bool、char、unsigned char、signed char 和short值转换为int,称为整型提升。

short i = 1;
short j =2;
short total = i+j;//首先将i和j转换为int,然后将结果转换为short。

关于整型提升,还有一个非常经典的例子:

#include <stdio.h>

int arr[] = {23,34,12,17,204,99,16};
#define MUM (sizeof(arr)/sizeof(arr[0]))
int main()
{
	int d = -1, x = -1;
	if(d <= MUM-2)
	{
		x = arr[d+1];
		printf("if------x: %d\n");
	} 
	printf("x: %d\n",x);
	return 0;
}

/*
运行结果:
x: -1
*/

之所以结果如此,是因为sizeof返回值类型为unsigned int,if语句在int 和unsigned int之间测试相等,于是d被提升为unsigned int,-1转换成unsigned int的结果将是一个无穷大的正整数。
要修正这个问题,必须进行强制类型转换:

if(d <= (int)(MUM-2))

2.强制转换

简单的强制类型转换格式如下:

typeName (value)
(typeName) value 

此外,C++ 中还引入了四个强制类型转换运算符。这里暂不总结。

2.复合类型

数组

1.数组的声明格式:
typeName arrayName[arraySize];

从以上格式看出,数组声明时需要指出以下三点:

  • 1.存储在每个元素中的值的类型;
  • 2.数组名;
  • 3.数组中的元素。
    如:
int size[20];
float conn[10];

数组之所以是复杂类型数据,是因为它是由基本类型所创建的。

2.数组的初始化

数组的初始化有以下规则:

  • 1只能在定义时进行初始化,并且不能讲一个数据赋值给另一个数组:
int card[4] = {1,2,3,4};//ok
int hand[4];//ok
hand[4] = {4,2,3,5};//bad
hand = card;//bad

不过,可以通过下标分别给数组中的值赋值。

  • 2.如果要对数组中的一部分元素进行初始化,则编译器将把其他元素默认初始为默认值:
int size[20] = {1,2,3}//其余元素全为0
  • 3.如果初始化时方括号内为空,则编译器将进行元素个数的计算:
short total[] = {1,2,3,4};

不过这是一种非常糟糕的做法。

c++11中的列表初始化

c++11中的列表初始化方式,作为一种通用的初始化方式,适用于所有类型。

  • 1.可省略等号:
int size[4]{1,2,3,4};
  • 2.大括号内可以不包含任何东西,所有元素默认将为0:
int size[20] {};
  • 3.列表初始化禁止缩窄转换:
long point[] = {23,24,25.5};//bad
char str[] = {'M','N',456};//bad,int转char为缩窄转换

字符串

1.C风格字符串

C风格字符串是特殊的char数组,以空字符\0结尾,如:

char lower[8] = {'a','b','c','d','e','f','g'};
char upper[8] = {'A','B','C','D','E','F','G','\0'};

lower是普通的char数组,而upper是一个字符串。

由于字符串是特殊的char数组,因此,在定义字符串时,可以直接这样定义:

char upper[8] = "ABCDEFG";

用引号括起的字符串隐式地包含空字符,因此不需要显示包含它。

标准头文件cstring中提供了许多与字符串相关的函数声明。如strlen()获取字符串长度。。。。。

字符串的输入

字符串的输入,不能使用简单的cin来进行了,如:

#include <iostream>

int main()
{
        using namespace std;
        const int SIZE = 20; 
        char name[SIZE];
        char dessert[SIZE];
    
        cout << "Enter your name:" << endl;
        cin >> name;
        cout << "Enter your favorite dessert:" << endl;
        cin >> dessert;
        cout << "I have some delicious " << dessert;
        cout << " for you, " << name << endl;
        return 0;
}

以上示例运行时,会有这样的问题:

  • 1.如果输入字符串过长,则char数组中无法存储而程序崩溃;
  • 2.cin >> 使用空白符来确定字符串的结束位置,因此每次只会读取一个单词。

针对这两种情况,istream类中提供了get()方法和getline()方法,以行为单位读取字符串。

1.getline()方法

getline()方法读取整行,它通过换行符来确定行尾,但不保存换行符,而是将换行符用空字符来替换。

#include <iostream>

int main()
{
        using namespace std;
        const int SIZE = 20; 
        char name[SIZE];
        char dessert[SIZE];
    
        cout << "Enter your name:" << endl;
        cin.getline(name,SIZE);
        cout << "Enter your favorite dessert:" << endl;
        cin.getline(dessert,SIZE);
        cout << "I have some delicious " << dessert;
        cout << " for you, " << name << endl;
        return 0;
}

2.get()方法

get()getline()类似,也是以行为单位读取字符串,不同之处在于,get()不会丢弃换行符,而是会保留在输入队列中,因此,一般连续调用两次该方法,以清除输入队列中的换行符:

#include <iostream>

int main()
{
        using namespace std;
        const int SIZE = 20; 
        char name[SIZE];
        char dessert[SIZE];
    
        cout << "Enter your name:" << endl;
        cin.get(name,SIZE).get();
        cout << "Enter your favorite dessert:" << endl;
        cin.get(dessert,SIZE).get();
        cout << "I have some delicious " << dessert;
        cout << " for you, " << name << endl;
        return 0;
}

如果读取空行,get()读取空行后将设置一个失效位,并阻断接下来的输入;

如果读取字符过长,两者都会将多余的字符留在输入队列中,getline()还会设置一个失效位,并阻断接下来的输入;

两者相比而言,getline()简单容易使用,get()则使得检查错误更简单一些。

3.混合输入数字和字符串

看看如下示例:

#include <iostream>

using namespace std;

int main()
{
        cout << "What year was your house built?" << endl;
        int year;
        cin >> year;
        cout << "What is its street address?" << endl;
        char address[80];
        cin.getline(address,80);
        cout << "your built:" << year << endl;
        cout << "Address:" << address << endl;


        char dog[8] = {'a','b','c','d','e','f','g'};
        char cat[8] = {'A','B','C','D','E','F','G','\0'};
    
        cout << "dog:" <<dog << endl;
        cout << "cat:" << cat << endl;
        return 0;
}

运行该示例时,当输入数字后,就立即结束了。这是因为当cin读取年份时,将回车留在在输入队列中了,而后cin.getline()时读取到回车,以为是个空行,将空字符串赋值给了address数组。
解决方法就是通过get()清除换行符:

(cin >> year).get();

(预留头文件cstring、climit的使用)

2.string类

在c++中,除了可以使用C风格字符串以外,可以使用string类对象来存储字符串,使用时它要比C风格字符串简单得多。

使用string类,首先需要导入string头文件,此外,string类定义在std名称空间中,因此必须提供using声明或编译指令,或者直接使用std::string来引用它,如:

#include <string>
std::string str1 = "C++ String";

C风格字符串的使用方式完全符合string类,如以下示例中:

#include <iostream>
#include <string>

int main()
{
        char charr1[20];
        char charr2[20] = "Doctor";
        std::string str1;
        std::string str2 = "Teacher";

        std::cout << "Enter a job:" << std::endl;
        std::cin >> charr1;
    
        std::cout << "Enter another job:" << std::endl;
        std::cin >> str1;
    
        std::cout << "Here are all job:";
        std::cout << charr1 << " " << charr2 << " " << str1 << " " << str2 << std::endl; 
        return 0;
}

此外,相比C风格字符串,string类中提供了许多操作字符串的函数,使用起来更简单,下面就来看看这些优势。

string类和C风格字符串优势
  • 1.赋值

C风格字符串赋值时,不能将一个数组赋值给另一个数据,必须使用cstring头文件中的函数:

char charr1[20];
char charr2[20] = "Hello world";

charr1 = charr2;//BAD
strcpy(charr1,charr2);//ok

string类中则可以将一个string对象赋值给另一个:

std::string str1;
std::string str2 = "Hello world";
str1 = str2;
  • 2.追加
    C风格字符串中追加字符时,需要使用cstring中的方法:
char charr2[20] = "Hello world";
strcat(charr2," welcom");//ok,但有溢出风险

string类中可以通过+=进行追加:

std::string str2 = "Hello world";
str2 += " welcom";

char数组的大小是固定的,而string大小可以自动调整。

  • 3.拼接

同理,在拼接C风格字符串时:

strcpy(charr3,charr1);
strcat(charr3,charr2);

在string类中,直接使用+进行拼接:

std::str3 = str1 + str2;
  • 4.获取长度

在C风格字符串中, 获取长度使用cstring头文件中的strlen()函数:

int len = strlen(charr1);

在string类中,通过string类的size()方法:

int len = str1.size();
string类的IO

string类可以使用cin、cout进行输入输出,除此之外,在string类中还提供了专门的用于IO操作的getline()方法,第一个参数为istream类对象,第二个参数为string类对象,使用见如下示例:

#include <iostream>
#include <string>
#include <cstring>

int main()
{
        char charr[20];
        std::string str;

        std::cout << "Length of charr before input:" << strlen(charr) << std::endl;
        std::cout << "Length of str berfore input:" << str.size() << std::endl;
        std::cout << "Enter a line of text:" << std::endl;
        std::cin.getline(charr,20);
        std::cout << "you enterd: " << charr << std::endl;
        std::cout << "enter another line of text: " << std::endl;
        std::getline(std::cin,str);
        std::cout << "you enterd:" << str << std::endl;
        std::cout << "Length of charr after input:" << strlen(charr) << std::endl;
        std::cout << "Length of str after input:" << str.size() << std::endl;

        return 0;
}
其他形式的字符串

除了char类型外,还有wchar_t,char16_t,char32_t等,这些类型也可以用来创建C风格字符串。对于这些类型的字符串,c++分别使用L、u、U作为前缀:

wchar_t charr1[20] = L"Hello world";
char16_t charr2[20] = u"Hello world";
char32_t charr3[20] = U"Hello world";

结构体

结构体是一种比数组更加灵活的数据类型,数组只能存储同一类型的数据,而结构体中则可以存储不同类型的数据,结构体通过关键字struct来创建。

1.结构体定义
struct player
{
    char name[20];
    float score;
    float assist;
};

定义结构一般在函数外部,称为外部声明。

c++不提倡使用外部变量,但提倡使用外部声明。

c++中允许在类中嵌套结构体声明。

2.创建结构体类型的变量

定义结构之后,就可以像基本数据类型一样,创建该结构类型的变量了:

struct player jordan;
player kobe;

上示例中说明,和C语言不同的是,struct关键字可以省略。

或者还可以在定义结构类型时直接声明:

struct player
{
    char name[20];
    float score;
    float assist;
} kobe,james;
3.获取结构成员

当定义一个结构变量后,通过.可以获取其成员:

float x = kobe.score;
4.结构的初始化
  • 1.一般初始化

这种初始化方式为经常采用的方式:

player curry =
    {
        "shotting",
        25.8,
        8.7
    };
  • 2.C++ 11列表初始化

列表初始化通用于所有类型,struct也同样适用:

player lakers {"kobe",28.8,8.8};//可以省略等号
player lakers {};//所有成员将被设置为0,lakers.name的每个字节将设置为0
  • 3.可以将一个结构类型数据赋值给另一个同类型结构数据:
player bulls;
player lakers {"kobe",28.8,8.8};
bulls = lakers;
5.结构数组

可以创建元素为结构的数组,其创建方式和普通数组创建方式完全一样,如:

#include <iostream>

struct inflatable 
{
        char name[20];
        float volume;
        double price;
};

int main()
{
        using namespace std;
    
        inflatable guest[2] =
        {
                {"Tom",0.5,2000},
                {"Jeck",1.3,45.8}
        };

        cout << "guest: " << guest[0].name << " and " << guest[1].name << endl;
     
        return 0;
}

联合体

联合体也叫做共用体,他能够存储不同类型的数据,但只能同时存储其中的一种,所以共用体的长度为其最大成员的长度,共用体和结构体的句法相似:

union player
{
    int age;
    float score;
};
用途

共用体的用途之一是,当数据项使用多种格式表示时,可节省空间。比如学生成绩可以用分数和ABCD来表示:

#include <iostream>
#include <string>

struct student
{
        std::string name;
        int age;
        union grade_u
        {
                int grade_num;
                char grade_c;
        } grade;
};

int main()
{
        student stu1 = {"XiaoMing",12};
        student stu2 {"XiaoHong",13};
    

        std::cout << "Enter" << stu1.name << "'s grade with number:" << std::endl;
        std::cin >> stu1.grade.grade_num;
        std::cout << "Enter" << stu2.name << "'s grade with level:" << std::endl;
        std::cin >> stu2.grade.grade_c;

        std::cout << stu1.name << "'s grade is " << stu1.grade.grade_num << " points" << std::endl;
        std::cout << stu2.name << "'s grade is " << stu2.grade.grade_c << " level" << std::endl;
        return 0;
}

匿名共用体

匿名共用体没有名称,其成员将成为位于相同地址处的变量,当然,每次只有一个成员是当前的成员。

枚举

枚举是c++提供的一种创建常量的方式,可以替代const.

1.创建方式

创建一个枚举类型,用enum关键字,格式如下:

enum e_type {RED,BLUE,YELLOW,BLACK};

以上示例中,e_type称为枚举,RED等称为枚举量,对应的整数值为0-3,后面的枚举量总是比前面的值大1,也可以指定枚举量的值:

enum color {RED,BLUE=3,YELLOW,BLACK};//值分别为0,3,4,5
2.注意事项
  • 首先,枚举变量值受到限制,如color变量,只能有四个值;
  • 其次,枚举可以转换为int类型,但int类型不能转换为枚举:
color c1 = RED;
int i = RED;//OK
color c2 = i;//BAD

也不能使用算术运算符:

color c2 = RED + BLUE;//BAD,运算时,枚举将会被转换成整数。
  • 最后,可以创建多个值相同的枚举量:
enum color {red,blue = 0, yello,black = 1};
3.用途

枚举一般用来代替const,因此可不创建枚举变量,直接使用枚举量:

enum {RED,BLUE,GREEN,YELLOW};
std::cout << RED << " ," << BLUE << std::endl;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值