(1)传统的数组实现方式
见另一篇博客传统数组
(2)自动分配数组
(1)一维数组(malloc/delete)
#include <iostream>
#include<iterator>
#include<list>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
using namespace std;
int main(void)
{
cout<<"使用malloc实现动态分配的数组空间"<<endl;
int *p1 = (int *)malloc(sizeof(int)*10);
for(int i=0; i<10; i++) {
*(p1+i) = i+10;
}
for(int i=0; i<10; i++) {
cout << *(p1+i);
}
cout << endl;
free(p1);
cout<<"\n使用new实现动态分配的数组空间"<<endl;
int *p2 = new int[10];
for(int i=0; i<10; i++) {
*(p1+i) = i+20;
}
for(int i=0; i<10; i++) {
cout << *(p1+i);
}
cout << endl;
delete p2;
return 0;
}
(2)多维数组
#include <iostream>
#include<iterator>
#include<list>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
using namespace std;
int main(void)
{
cout<<"使用malloc开辟e二维数组"<<endl;
int **p1 = (int **)malloc(sizeof(int *)*5);
for(int i=0; i<5; i++) {
*(p1+i) = (int *)malloc(sizeof(int)*5);
}
for(int i=0; i<5; i++) {
for(int j=0; j<5; j++) {
p1[i][j] = i+j;
}
}
for(int i=0; i<5; i++) {
for(int j=0; j<5; j++) {
cout<< *(*(p1+i)+j)<<" ";
}
cout<<endl;
}
for(int i=0; i<5; i++) {
free(*(p1+i));
}
free(p1);
cout<<"\n使用new关键字动态开辟二位数组"<<endl;
int **p2 = new int*[5];
for(int i=0; i<5; i++) {
*(p2+i) = new int[5];
}
for(int i=0; i<5; i++) {
for(int j=0; j<5; j++) {
p2[i][j] = i+j;
}
}
for(int i=0; i<5; i++) {
for(int j=0; j<5; j++) {
cout<< *(*(p2+i)+j)<<" ";
}
cout<<endl;
}
for(int i=0; i<5; i++) {
delete(*(p2+i));
}
delete p2;
return 0;
}
(3)使用动态分配方式实现数组时需要注意
(1)动态分配实现多维数组时,利用的是多级指针来实现的,而传统的
多维数组是靠数组指针这种特殊形式的指针实现的,但是让它
们在多维构建的逻辑上都是一样。
(2)传统方式实现的多位数组本质还是一维数组,元素全部都是连续的
但是动态分配空间不是的,它是由指针数组组织起来的,所有
的一维数组的空间不一定是连续的。
(3)动态方式实现多维数组时,由于单维数组间的空间并不连续,因此
在释放内存空间时一定要小心,不要导致内存泄漏。需要分批
释放空间,就像上面的例子所示。
(4)传统的多位数组中*的作用与动态分配的多维数组访问时*的含义是不同
的,比如如二维数组*访问形式:
传统方式:*(*(buf+i)+j) = 5; buf[i][j]
其中的*(buf+i)中的*实际上是强制转换的功能,强制的
将数组指针类型转换为数组元素指针类型。
动态分配方式:*(*(p+i)+j) = 5; buf[i][j]
其中的*(p+i)中*其实时寻找空间操作,或者也称为解引用
操作。
(5)动态分配的数组不能初始化,只能使用赋值的方式给值。
(6)传统方式实现的数组,特别是多维数组会大量涉及数组指针的概念
动态的方式实现的数组则大量涉及多级指针的概念。
(4)什么时候使用自动内存分配的方式实现数组
当需要程序运行后,动态确定数组的大小的时候,这个时候就是必须使用这种方式。
(3)C++提供数组类封装的方式式。
c++中还有一种数组类封装的实现方式,就对传统和动态分配这两种方式进行了类封装,类名为array,有些编译器不支持这样的实现方式。
使用
(1)一维
array<int,5> myarray={1,2,3,4,5};
(2)二维
array<array<int,2>,3 > myarray2D={1,2,3,4,5,6};
(4)c++中数组实现方式总结
(1)传统方式
自定义固定长度数组时,常用这种方式
(2)动态分配方式
需要在程序运行时具体决定元素个数时使用这种方式,C++中的STL vector
容器就是使用的动态分配数组的方式封装实现的。
(3)array类封装方式
array对数组进行了类封装,至于它的具体实现方式要看定义类对象的
方式。如果是通过new关键字实现的,就是使用动态分配的方式。
否者就是使用传统的方式实现。
在java中,java摈弃了c++个各种各样复炸的数组实现方式,只保留了Array类封装
样式的数组,在java中由于类对象空间全部都是开辟于动态分配区(堆),因此本质上
java的数组全部采用动态空间分配方式,单维数组空间之间不连续。
(3)字符串(特殊的字符数组)
(1)C样式字符串
(1)数组形式
(2)指针形式
(2)C++提供的string形式
(1)声明
//string str1 = "hello world";
//string str1("hello wolrd");
string *str1 = new string("hello world");
如果不初始化字符串就是空字符串。
(2)string对[]/=/==/+进行了重载
(1)可以使用[]访问字符串字符
(2)可以使用=直接相互间赋值
(3)可以使用==比较两个字符串对象是否相等,但是如果是指针形式的对象,不能使用==判断
string *str1 = new string("hello world");
string *str2 = new string("hello world");
string str3("hello world");
string str4("hello world");
str1[0] = '$';
string str;
if(str3 == str4) {
str = "==";
} else {
str = "!=";
}
cout << str << endl;
(4)字符串可以使用+进行连接,但是要求第一个必须是string类型的字符串
不能使用字符串字面量(常量字符串,任何形式的C类型的字符串),因为
只有string重载了+运算符
string str1 = "hello!, ";
string str = str1+"world"+" is "+ "world";
注意:
string *str1 = new string("hello!, ");
char *str2= " wwww ";
string str = *str1+"world"+ str2 + " is "+ "world";
cout << str << endl;
(5)+=的使用
(1)左边的第一个必须是string类型字符串
(2)右边的string类型变量必须先声明后使用
string *str1 = new string("hello!, ");
string str;
// = *str1 + "world"+" is "+ "world";
str += *str1 + "world"+" is "+ "world";
cout << str << endl;
(6)使用>>向string操作数中输入字符串时,无法输入带有空格的字符串
(1)使用getline(cin, str);函数,就可以输入带有空格的字符串,
默认结尾符是回车。
(2)使用第三参数输入指定结尾符的字符串
getline(cin, str,'#');//输入#结尾的字符串
(3)访问字符串的字符
由于string对[]进行了重载,因此,可以使用[]访问字符串中的元素,既可以作为左值使用
也可以作为右值使用。
string str;
getline(cin, str);
for(int i=0; i<str.length(); i++) {
str[i] = std::toupper(str[i]);
}
cout<< str << endl;
(4)常见操作字符串的一些string的成员函数的回顾
(1)substr():提取子字符串
(1)只有一个参数时:指定索引位置
如果指定的索引位置超出范围,会抛出超出范围的异常。
(2)两个参数时:第一个参数指定索引位置,第二个参数指定提取的字符串长度
(1)如果指定的索引位置超出范围,会抛出超出范围的异常。
(2)如果指定的长度超过范围,自动提取到字符串结束为止即可。
(2)字符串比较
(1)c字符串的比较
(1)比较的函数:使用strcmp或者strncmp函数进行比较
(1)strcmp函数:比较两个字符串是否完全相等
char *p = "hello";
char buf[] = {"hellw"};
int ret = strcmp(p, buf);
(2)strncmp函数:比较两个字符串前n个字符是否相等
char *p = "hello";
char buf[] = {"hellw"};
int ret = strncmp(p, buf, 4);
(3)函数返回值:如果两个字符串相等,返回0,如果第一个参数指向的字符串小于第二个参数指向的字符串,
返回一个小于0的数,否则就返回一个大于0的数。
(2)字符串比较的规则(以strcmp为例)
将两个字符串的字符逐个今次那个比较,知道找到不同的字符或者到达字符串的末尾,如果找到不同字符,就
根据器asscii值进行比较(函数返回asscii差值),如果两个字符串找到最后发现长度不相等,就返回长度差值。
(2)使用重载后的比较运算符 ==/!=/<=/>=进行比较
(1)比较的方法与strcmp同
(2)对string对象进行比较,或者将string对象与c样式的字符串进行比较
string str1 = "hello";
string str2 = "he";
string str;
if(str1 < "dsdf") {
str = "small";
} else {
str = "lage";
}
cout<< str << endl;
(3)使用compare成员函数进行比较
(1)比较的方法与strcmp同
(2)对string对象进行比较,或者将string对象与c样式的字符串进行比较
(3)compare不同的重载版本
(1)word.compare(string str);:比较word与str是否完全相等
(2)word.compare(int index, int num, string str1);:比较word中从index开始向后num个字符与str1是否完全相等。
(3)word.compare(int index1, int num1, string str1, int dex2, int num2);:比较word与str1的子字符串是否相等。
(4)使用substr实现子字符串的比较
if(word.substr(2,4)==word.substr(3,5));
(3)搜索字符串
(1)搜索成员函数find:返回索引
(2)的不同重载版本
(1)word.find(char c):在word中搜索字符,成功返回索引,失败返回string::npos(4294967295)表示非法字符位置。
(2)word.find(string/char * str):
(3)word.find(string/char * str, int i):从word的i位置开始找。
(2)word.find(string/char * str, int i, int n):从word的i位置开始找str中前n个字符。
(3)逆向搜索函数rfind,用法同find
(4)在字符串中搜索字符集中的字符
(1)涉及函数
(1)word.find_first_of(string/char str);:从word头开始索引,第一次出现str中字符的位置
(2)word.find_first_not_of(string/char str);:从word头开始索引,第一次出现非str中字符的位置
(3)word.find_last_of(string/char str);:从word尾部开始索引,第一次出现str中字符的位置
(4)word.find_last_not_of(string/char str);:从word尾部开始索引,第一次出现非str中字符的位置
(2)使用例子:将字符串拆分成子字符串
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string str = "sdfa sdaf,sdffsdf,fsdf/fsdf";
int start = 0;
int end = 0;
string s = " ,/";
start = str.find_first_not_of(s);
while(start != string::npos) {
end = str.find_first_of(s, start+1);
if(end == string::npos)
end = str.length();
cout << str.substr(start, end-start) << endl;
start = str.find_first_not_of(s, end+1);
}
return 0;
}
(4)修改字符串
(1)插入字符串
(1)涉及成员函数:insert
(2)不同重载版本
(1)word.inset(int i, string/char *str):将字符串插入word的i之前
(2)word.inset(int i, string/char *str, int n):将字符串插入str中前n个字符word的i之前
(2)word.inset(int i, string/char *str, int j, int n):将字符串插入str中j位置开始的n个字符word的i之前
(3)测试例子
(2)字符串的替换
(1)涉及成员函数:replace
(2)涉及不同的重载版本
(1)word.replace(int i, int n, string/char * str);:将word中的i位置开始的n个字符,用str替换
(2)word.replace(int i, int n, string/char * str,int n1);:将word中的i位置开始的n个字符,用str中的前n1个替换
(3)word.replace(int i, int n, string/char * str,int i1, int n1);:将word中的i位置开始的n个字符,用str中i1位置开始的n1个字符替换。
(3)用例
(3)删除字符
(1)涉及成员函数erase
(2)重载版本
(1)word.erase(int i, int n);:将word中的i位置开始的n个字符删除
(3)用例
(5)字符串数组
(1)c样式的字符串数组
(2)c样式字符串数组
char *p[] = {"hello", "world", "is", "buitful"};
(3)string样式字符串
string p[] = {"hello", "world", "is", "buitful"};
(4)二者的区别
c样式的字符串数组中,字符串是常量,存放在常量区,内容不能被更改,否者会导致段错误。
string样式字符串,字符串在string类中,是以字符串数组的形式存放的,内容是可以修改的。
(5)用例
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
#if 0
char *p[] = {"hello", " world", " is", " buitful"};
p[0][1] = 'w';
#endif
string p[] = {"hello", " world", " is", " buitful"};
p[0][1] = 'w';
cout << p[0] << endl;
return 0;
}
网友评论