指针和 const 限定符
double dheight = 100.5;
const double dprice = 10.5;
const double *pd = &dprice; // pd 指向的 dprice 是const 的
pd = &dheight; // pd 可以指向非const 的对象
int ierr = 0;
int *const curErr = &ierr; // 指针 curErr, 是const的
const int iMsg = 10;
const int *const pmsg = &iMsg; // 指针 和 指向的对象,都是const的
原因是: const 限定符可以放在类型前,也可以放在类型后。
就是说, const string a;
也可以写成: string const a;
typedef string * pstring;
string s("Hello");
const pstring ps = &s;
string *const ps2 = &s; // 与上式,等价
pstring const ps3 = &s; // 与上式,等价
此处,const 修饰的是 pstring 类型,也就是说,const 修饰的是指针。
typedef,不是简单的文本扩展!
因此,const pstring ps = &s; 其实等价于: string *const ps = &s;
C风格字符串
字符串字面值 的类型,是字符常量的数组。
也就是,const char 类型的数组。
C++ 从C语言 继承下来的一种通用结构就是 C风格字符串(C-style character string)
而,字符串面值,就是该类型的实例。
实际上,C风格字符串既不能归结为C语言的类型,也不能归结为C++语言的类型,
而是以空字符 null 结束的字符数组。
char ca1[] = {'C', '+', '+'};
char ca2[] = {'C', '+', '+', '\0'}; // C风格
char ca3[] = "C++"; // C风格,末尾自动加 null
const char *cp = "C++"; // C风格
char *cp1 = ca1; //
char *cp2 = ca2; // C风格
C++ 通过 (const) char * 类型的指针,来操作C风格字符串。
const char *cp = "some value";
while(*cp)
{
++cp;
}
如果 cp 指向的字符串数组没有null 字符,则,无法达到预期效果。
直到在内存中找到null 字符,循环才会终止。
strlen(s) | 返回s 长度,不包括结束符 null |
---|---|
strcmp(s1, s2) | s1=s2,返回0; s1>s2,返回正数; s1<s2,返回负数 |
strcat(s1, s2) | 将s2 连接到 s1,然后返回 s1 |
strcpy(s1, s2) | 将s2 复制给 s1,然后返回 s1 |
strncat(s1, s2, n) | 将s2 的前n个字符连接到 s1 后面,并返回 s1 |
strncpy(s1, s2, n) | 将s2 的前n个字符复制给 s1, 并返回 s1 |
注意:C风格字符串的操作容易出错。
通常使用标准库类型 string 来代替此类操作
动态数组
动态数组,不必在编译时知道其长度,可以是在运行时再确定数组长度。
每个程序,执行时都占用一块可用内存,用于存放动态分配的对象,
此内存称为:自由存储区(Free Store)或者 堆(Heap)
C++ 使用 new 和 delete 来分配和释放 自由存储区。
string *sp = new string[10];
int *ip = new int[20];
size_t n = get_size();
int *ip3 = new int[n];
string *sp2 = new string[30]();
const int *ip2 = new const int[11]();
// char arr[0] 是错误的, 然而,动态分配时,长度可以是0,并返回非0 的指针,但该指针不能解引用
char *cp = new char[0];
delete [] ip3;
使用动态数组,通常是因为,编译时无法知道数组的准确长度。如:以下场景
const char *noerr = "success";
const char *err188 = "Error Code: 188";
const char *errorText;
if(errorFound)
errorText = err188;
else
errorText = noerr;
int dimension = strlen(errorText) + 1;
char *errMsg = new char[dimension];
strncpy(errMsg, errorText, dimension);
混合使用标准库类 string 和 C风格字符串
c_str () :返回C风格字符串的表示方法
string str("Hello");
const char *cp = str.c_str(); // C 风格字符串自动转换为,指向字符数组首地址的指针
// char *cp = str.c_str(); 错误,因为c_str() 返回的是 const char 类型的数组
// char *cp = str; 错误,无法使用 string 对象来初始化 字符指针
// str.c_str() 返回的数组未必永远有效。因为 str 有可能被修改。
// 因此,最好是复制 str.c_str() 返回的数组
string s("abcdefg");
// char *a; 错误
// char *a = "x";
// 错误,"x"的内存是在栈上分配的,栈上的内存无法修改
// 返回的其实是 const char *,而不是 char *, 因此strcpy 将会无法写入,报错
char *a = new char[s.length()+1];
strcpy(a, s.c_str());
使用数组初始化 vector
const size_t array_size = 5;
int int_arr[array_size] = {88, 32, 13, 34, 65};
// 实际复制了 int_arr[1], int_arr[2], int_arr[3], int_arr[4]
vector<int> ivec(int_arr + 1, int_arr + array_size);
多维数组,即:数组的数组
int arr_first[2][3] = { {1, 2, 3}, {4, 5, 6} };
// 与上式等价
int arr_second[2][3] = {1, 2, 3, 4, 5, 6};
// 等价于:{ {1, 0, 0}, {2, 0, 0} }
int arr_third[2][3] = { {1}, {2} };
// 等价于:{ {1, 2, 0}, {0, 0, 0} }
int arr_fourth[2][3] = { 1, 2 };
// ip 是数组,长度为3,数组元素是,指向int 的指针
int *ip[3];
// ip_second 是指针,指向一个长度为3 的int 数组
int (*ip_second)[3];
typedef int int_array [3];
for(int_array *p_arr = arr_first; p_arr!=arr_first+2; ++p_arr)
for(int *p_int = *p_arr; p_int!=*p_arr+3; ++p_int)
*p_int = 100;
int c = arr_first[0][1];
..