C++ 第一周

第一章 开始学习 C++   

  如果已经使用过C语言进行编程,则看到  cout  函数时可能会小吃一惊。事实上,C++能够使用 printf(),scanf ()和其他所有标准C输入和输出函数,只需要包含常规C语言的 stdio.h 文件。

      接下来看一个简单的 C++ 程序

// myfirst.cpp -- displays a message

#include<iostream>                           // a PREPROCESSOR directive
int main()                                   // funtion header
{
	using namespace std;
	cout << "Come up and C++ me some time.";
	cout << endl;
	return 0;     //terminate main()
}

      示例包含下述元素:

(1) 注释,由前缀 // 标识

(2) 预处理器编译指令 #include

(3) 函数头 int main ()

(4) 编译指令 using namespace

(5) 函数题,用 {  }   括起

(6) 使用 C++ 的cout 工具 显示消息的语句

(7) 结束 main()函数的 return 语句

main () 函数 :   

 int main ()                   // 函数头
 {                         // 函数体

      statement;  
      return 0 ;
 }

       这几行代码构成了函数定义(function definition),函数头对函数与程序其他部分之间的接口进行了总结。所有的语句都以    ;    结束

       常规的独立程序都要包含一个 main()函数 ,但存在一些例外情况,如机器人中的控制器芯片可能不需要main()。

       

     

C++ 预处理器和iostream 头文件

      预处理器,即它处理名称以 # 开头的编译指令,不必执行任何特殊操作来调用该预处理器,它在编译程序会自动运行。

      预处理器将 iostream 文件的内容添加到程序中。这是一种典型的预处理器操作:在源程序代码被编译之前,替换或添加文本

      iostream 中的 io  指的是输入(进入程序的信息)和输出(从程序发送出的信息),实际上,iostream 文件的内容将取代程序中的代码行 #include<iostream>  原始文件没有被修改,而是将源代码文件 和 iostream 组合成复合文件,编译的下阶段将使用该文件。

     像 iostream 这样的文件叫头文件(包含文件)。

using namespace std ;

     这是一种偷懒的做法,在大型项目中是一个潜在问题。

     该编译指令使得 std 名称空间中的所有名称都可以使用。若没有该编译指令,例如在使用cout 和 endl 时,需要这么写:

using std :: cout;

using std :: endl;

      让程序能够访问名称空间 std 的方法有多种,这是最主要的四种:

(1)将 using namespace std ;放在函数定义之前,让文件中所有的函数能够使用名称空间 std中所有的元素。

(2)将 using namespace std ;放在特定的函数定义中,让该函数能够使用名称空间 std 中的所有元素。

(3)在特定的函数中使用类似 using std :: cout 这样的编译指令,而不是 using namespace std ;  ,让该函数能够使用指定的元素,如 cout 。

(4)完全不使用编译指令 using 。

使用 cout 进行 C++ 输出  (cout是一个 流的对象)

cout << "Come up and C++ me some time.";

// 双括号括起的部分是要打印的消息。双括号括起的一系列字符叫做字符串。
// << 符号表示将该语句发送给cout ;该符号指出了信息流动的路径。

使用 cin 进行 C++ 输入 (cin 也是一个 流的对象)

看一个示例:

// inout and output
#include<iostream>

int main()
{
	using namespace std;
	
	int carrots;
	
	cin >> carrots;
	carrots+=2000;
	cout << "Happy new " << carrots << "year !" << endl;
	return 0;
}



使用 cout 进行拼接

cout << "Happy new " << carrots << "year !" << endl;
// 也可以这么写
cout << "Happy new "
     << carrots
     << "year !"
     << endl;

声明语句与变量,和C语言相同,略。

类简介

       类是用户定义的一种数据类型。要定义类,需要描述它能够表示什么信息可对数据执行哪些操作。

       类之于对象 就像 类型之于变量。 也就是说,类描述的是数据格式及其用法,而对象则是根据数据格式规范创建实体。

       现在来看 cout ,它是一个 ostream 类对象。 ostream类定义描述了ostream对象表示的数据以及可以对它执行的操作,如将数字或字符串插入到输出流当中。同样,cin 是一个 istream 类对象。

第二章 处理数据

        为把信息存储在计算机中,程序必须记录三个基本属性:

信息将存储在哪里;      

要存储什么值;

存储何种类型的信息;

变量

      整型wchar_t  ,  char  ,  short  ,  int  ,  long  和  long long 

short:至少 16 bit .

int 至少和short 一样长 .

long 至少 32 bit,且至少与 int 一样长.

long long 至少 64 bit  ,且至少与 long 一样长.

要创建无符号版本的基本整型,只需要使用关键字unsigned ,例如 :unsigned long askd

      变量使用的 bit越多,占用的内存空间就越大。运算符 sizeof 可用来显示变量的字节数。

wchar_t

        与 char 相比  8 位 char 可以表示基本字符集,wchar_t( 宽字符类型)可以表示扩展字符集。

        cin 和  cout 将输入和输出看作是 char 流,因此不适用于处理 wchar_t 类型,iostream的最新版本提供了—— wcin 和 wcout ,用于处理wchar_t  流。

        另外,,可以通过加上前缀 " L " 来指示宽字符常量和宽字符串。


// 将字母 P 的 wchar_t 版本存储到变量bob
// 并显示单词tall 的 wchar_t 版本 
wchar_t bob = L'P';
wcout << L"tall"<< endl;

浮点数 :float,double ,long double 

        与C类似,这里只介绍 E表示法  。

        如 3.45E6 表示 3450000,E6代表前面的浮点数乘以 6 个 10.   

        E 后面的数字是指数,可正可负。

bool 类型与C语言 相同,略。

初始化

      初始化将声明与赋值结合在一起。 如果不对函数内部定义的变量进行初始化,那该变量的值将是不确定的。这意味着该变量的值将是它被创建之前,相应内存单元保存的值。

      符号常量——预处理器方式

#define MAXN 100

该编译指令告诉预处理器:在程序中查找 MAXN ,并将所有的 MAXN 都替换成 100.

      预处理器会查找独立的标记(单独的单词),像 :  PPTDMAXN 不会被替换为 100.

const 限定符

       与 #define语句 相比,用 const 关键字来修改变量声明和初始化更好。

// 假设需要一个表示一年中月份数的符号常量
const int Months = 12; 

这样,Months的值就被固定了,不允许修改。

第三章 复合类型

 数组(array)

       存储多个同类型值。  C++ 数组从下标 ' 0 ' 开始编号。

有效下标值的重要性

       编译器不会检查使用的下标是否有效。例如将一个值赋给一个不存在的元素 a[ 101 ] ,可能引发一系列问题,可能破坏数据或代码,导致程序异常终止。

       初始化数组时,提供的值可以少于数组的元素数目,其他的元素将被编译器设置为0.

        

字符串

       C++ 处理字符串的方式有两种,第一种被称为C风格字符串,它具有特殊的性质:以空字符结尾,空字符被写作 \0 , 其ASCII码为0 ,用来标记字符串结尾。

char a[4] = {'a','b','c','d'}   // not a string
char b[4] = {'a','b','c','\0'}  // a string

有一种更为简便的方法:

char a[4] = "abcd"     // the \0 is understood
char b[4] = "abc"

       这种字符串被称为字符串常量或字符串面值。

注意:在确定存储字符串所需的最短数组时,别忘了给结尾的空字符留个位置。

注意:字符串常量(使用双引号)不能与字符常量(使用单引号)互换 。例如一个字符常量 ' S ' 是字符串编码的简写表示。在ASCII 系统上,' S ' ,只是83的另一种写法,因此,下面语句将83 赋给size:

char size = 'S'    // This is fine

" S " 不是字符常量,它表示的是两个字符(字符S和 \0 )组成的字符串。更糟糕的是,"S" 实际上表示的是字符串所在内存地址 ,下面语句试图将内存地址赋值给size:

char size = "S"    // illegal type mismatch

       由于地址是一种独立的类型,因此C++ 编译器不允许这种不合理的做法。

在数组中使用字符串

先看一个示例:

// storing strings in an array
#include<iostream>
#include<cstring>
int main()
{
	using namespace std;
	const int Size = 15;
	char name1[Size];
	char name2[Size] = "C++owboy";
	
	cout << "Howby! I am" << name2;
	cout << "! What is your name?\n";
	cin >> name1;
	cout << "Well, "<<name1 << ",your name has ";
	cout << strlen(name1) << " letter and is stored" <<endl;
	cout << "in an array of " << sizeof(name1) << " bytes"<< endl;
	cout << "Your initial is " << name1[0] << "." << endl;
	name2[3] = '\0' ; 
	cout << "Here are the first 3 characters of my name: " ;
	cout << name2 << endl;
	return 0;
}

      当输入 Tony时 :

Howby! I amC++owboy! What is your name?
Tony
Well, Tony,your name has 4 letter and is stored
in an array of 15 bytes
Your initial is T.
Here are the first 3 characters of my name: C++

       首先,sizeof 运算符指出整个数组的长度 : 15 字节    ; 但strlen() 函数返回的是存储在数组中的字符串的长度,而不是数组本身的长度。另外 strlen()只计算可见的字符,即不会把空字符计算在内。

       因此,对于存储字符串,数组的长度不能少于 strlen()+1.

       由于 cin 使用空白(空格,制表符和换行符)来确定字符串的结束位置 ,所以cin 每次只能获取用户输入的一个单词。所以这有时候会很麻烦。 而iostream 中的类提供了一些面向行的类成员函数 :getline () 和 get () .   这两个函数都读取一行输入,直到到达换行符。 随后 getline()将换行符丢弃,而 get()保留了它。

       要调用这两个函数 ,可以使用 cin.getline()  和  cin.get() .

另外,连续使用cin.get()时会发生以下情况:

#include<iostream>
#include<cstring>
int main()
{
	using namespace std;
	const int Size = 10;
    char bro[Size];
    char ther[Size];
    cin.get(bro,Size);
    cin.get(ther,Size);
    cout << bro << endl;
    cout << ther << endl;
	return 0;
}

      你会发现第二个字符串数组没办法输入,这是因为在输入第一个字符串数组后,换行符被保留,而执行第二个get()时,该函数读取到上一次的换行符,认为读取结束,于是在我们看来是直接跳过了第二次输入。

        可以这么修改:

 cin.get(bro,Size);
 cin.get();          //在中间加一个get()将换行符读取掉。
 cin.get(ther,Size);


//可以这样
 cin.get(bro,Size).get();          
 cin.get(ther,Size);

空行和其他问题:

       当 getline() 或 get() 读取空行时,将发生什么? 最初的做法是,下一条输入语句将在前一条 getline() 或 get() 结束读取的位置开始读取 ;现在的做法是,当 get() 读取空行后将设置失效位。 

这意味着接下来的输入将被阻断,但可以用下面的命令来恢复输入:

cin.clear();

另一个潜在的问题是:输入的字符串可能比分配的空间长。如果输入行包含的字符数比指定的多,则 getline()和get()将把余下的字符留在输入队列中而getline()还会设置失效位,并关闭后面的输入。

       

  

        C++ 的第二种处理字符串的方式是基于string类库的方法。要使用string 类,必须包含头文件string 。

        在很多方面,使用string 对象的方式与使用字符数组相同。两者的主要区别 :可以将string 对象声明为简单变量,而不是数组:

string str1;
string str2 = "Hello my son";

       类设计让程序能够自动处理string大小。所以使用string对象更加方便,更加安全。从理论上说:可以将 char 数组视为一组用于存储一个字符串的 char 存储单元 ,而string 类变量是一个表示字符串的实体。

       另外,在使用string类时,某些操作比使用数组时更简单。例如:可以将一个string对象赋给另一个string对象,但数组做不到。

       string 类简化了字符串合并操作,可以直接使用运算符 +  将两个string对象合并起来,话可以使用运算符 +=  将字符串附加到string对象的末尾。

#include<iostream>
#include<cstring>
int main() {
	using namespace std;
	string str1;
	string str2 = "Hello my son";
	string str3;
	
	str1 = str2;
	str3 = str1 +str2;
	cout << str1 << endl;
	cout << str3 
	return 0;
}

string 类的其他操作: 头文件cstring 提供常用的字符串处理函数。

结构

        C++ 中支持将结构成员指定为string 对象。另外,还可以使用赋值运算符 = 将结构赋给另一个同类型的结构,这样结构中的每个成员都将被设置为另一个结构中相应成员的值,即使成员是数组(前面说过数组之间不能直接赋值,但放在结构中就可以了,这里的数组是结构成员)。

#include<iostream>
struct sztu{
	char data[10];
	int wuhu;
};
int main() {
	using namespace std;
    sztu computer=
	{
		"Big data",
		192,
		};
	sztu science;
	cout << "computer: "<< computer.data << " is "
	    << computer.wuhu << endl;
	science = computer;
	cout << "science: "<< science.data << " is "
	    << science.wuhu << endl;
	return 0;
}
//computer: Big data is 192
//science: Big data is 192

结构数组 : 元素为结构的数组。 

       例如: 

struct sztu{
	char data[10];
	int wuhu;
};
sztu ACM [100];
// 像ACM.data 这样的表达是无效的

共用体(union)

        这是一种跟结构很类似的数据格式,但它的特点在于只能同时存储其中的一种类型。让不同的类型在不同时间进行。用途:当数据项使用两种或以上的格式(但不会同时使用)时,可节省内存空间。

union sztu{
	char data[10];
	int wuhu;
};

     当共用体无名称时,称为匿名共用体(anonymous union),其成员的地址相同,所以每次只有一个成员是当前成员。

指针

声明和初始化指针:

#include<iostream>

int main() {
	using namespace std;
    int higgens = 5;
    int *pt = &higgens;
    
    cout << "Value of higgens = " << higgens
         << "; Address of higgens = " << &higgens << endl;
    cout << "Value of *pt = " << *pt
         << "; Value of pt = " << pt << endl;
	return 0;
}

注意:一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的,适当的地址。

       指针和数字:指针不是整型,虽然计算机通常把地址当作整数来处理,但指针与数字是截然不同的类型,将两个地址加减乘除没有任何意义。因此,不能简单地将整数赋给指针,要将数字值当作地址来使用,应通过类型转换将数字转换为适当的地址类型:

int *pt;
pt = 0xB8000000;   //这是错的

int *pt;
pt = (int *) 0xB8000000;  //type now match

使用 new 来分配内存

         指针真正的用武之地在于,在运行阶段分配未命名的内存以存储值。这时只能通过指针间接访问内存。C语言中,用库函数malloc()来分配内存;在C++ 中仍然可以这样做,但C++ 还有更优项—— new运算符。

int *pn = new int ;
//new int 告诉程序,需要适合存储 int 的内存。
//new运算符根据类型来确定需要多少字节的内存。
//然后它找到这样的内存,并返回其地址。 
//接下来将地址赋给pn,pn是被声明为指向 int 的指针。
//现在,pn是地址,*pn是存储在那里值。 

 使用 delete 释放内存

这与C语言中的malloc() 和 free()相同,但格式有所不同。

int *pn = new int ;
 // 中间省略...
delete pn
// delete 后面要加上指向由new分配内存块的指针 

       delete 释放了pn指向的内存块,但delete 不会删除指针pn本身。也就是说,可以将pn重新指向另一个新分配的内存块。一定要配对地使用new 和 delete ,否则会发生内存泄漏。另外,不要释放已经释放的内存块,这样的结果是不确定的;且不能使用delete 来释放声明变量所获得的内存。

(对空指针使用delete是安全的)

int *pn = new int ;    // right
delete pn;             //right
delete pn;             // wrong
int wuhu = 520;         
int * pt = &bro;
delete pt;             // not allowed
 

使用 new 来创建动态数组

       在编译时给数组分配内存被称为静态联编(static binding),不管数组会不会被使用,它都一直占用着一段内存。

       使用new 以动态联编的形式创建的数组称为动态数组。直接上简单例子

int *pa = new int [10];
// new运算符返回第一个元素的地址 
//释放
delete [] pa; 
// [] 告诉程序,释放整个数组,而不仅仅时指针指向的元素。 

       由于指针pa指向数组的第一个元素,所以需要跟踪内存块中的元素个数,程序会自动完成,但这个信息是不公用的,所以不能使用 sizeof 运算符来确定动态数组中包含的字节数。

那么如何访问后面的元素呢?

       只要把指针当作数组名使用即可。对于第一个元素,使用pa[ 0 ] , 而不是 *pa  ,后面以此类推

#include<iostream>
int main()
{
	using namespace std;
	double * px = new double [3];
	px[0] = 3.14;
	px[1] = 5.20;
	px[2] = 0.618;
	cout << "px[1] is " << px[1] << ".\n";
	px=px+1;
	cout << "Now px[0] is " << px[0] << ".\n";
	cout << "px[1] is " << px[1] << ".\n";
	px=px-1;
	delete [] px;
	return 0;
}

注意:将指针变量加1后,其增加的值等于指向的类型占用的字节数。

另外:*( px+1 ) 和px[ 1 ] 是等价的。

 

使用 new 创建动态结构

         将 new 用于结构由两步组成 :创建结构和访问其成员

要创建结构,需要同时使用结构类型和new。例如,要创建一个未命名的sztu 类型,并将其地址赋给指针:

sztu *pt = new sztu;

         比较棘手的一步是访问结构成员,创建动态结构时,不能将成员运算符句点用于结构名,因为这种结构没有名称,只知道它的地址。C++ 专门为这种情况提供了一个运算符:-> .

例如,pt 指向sztu结构,那么 pt -> data 指向结构成员data;。

         另一种访问结构成员的方法时是,如果pt是指向结构的指针,那么*pt 就是结构本身。所以

( * pt ) . data 是可行的。

下面看一个示例:

#include<iostream>
struct sztu
{
     char name[20];
	 double data;	
};
int main()
{
	using namespace std;
    sztu * p = new sztu;
    cin.get(p->name,20);
    cin >> (*p).data;
    
    cout << "The name is "<< p->name <<endl;
    cout << "The data is "<< p->data <<endl;
    delete (p);
	return 0;
}

 

数组的替代品

模板类 vector

       模板类vector 类似于string 类,也是一种动态数组。可以在运行阶段设置 vector 对象的长度,可在末尾附加新数据,还可以在中间插入新数据。使用 vector时 ,new 和 delete 的操作自动完成。

       首先,要使用vector 对象,必须包含头文件 vector ,其次,vector 包含在名称空间 std中。

示例:

//不完整的代码段 
#include<iostream>
#include<vector>
int main()
{
	using namespace std;
    vector<int> vi;        //create a zero-size array of int
    int n;
    cin >> n;
    vector<double> vd(n);  // create a array of n doubles
	return 0;
}

模板类array

        array对象与数组的区别在于 它更方便更安全(我也不知道为啥)。

        array创建语法与vector 稍有不同:

//不完整的代码段 
#include<iostream>
#include<array>
int main()
{
	using namespace std;
    array<int,10> ai;        
    array<double,2> ad = {3.14,0.618}; 
	return 0;
}
//array<typeNAME,n> arr; 其中, n 不能是变量 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DDsoup

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值