全部博文(21)
分类: C/C++
2012-12-13 20:48:05
1.使用字符串的字面值来初始化创建的新数组时,将在新的数组中加入空字符.
2.引用与指针的区别:
①引用总是指向某个对象:定义没有初始化的引用是错误的.
②给引用赋值修改的是该引用所关联的值,而并不是使引用与另一对象相关联
3.在C 中,强制要求指向const对象的指针也要有const特性,另外,不能使用void*指针保存const对象的地址,而必须使用const void*类型的指针保存const对象的地址
4.typedef string* pstring; const pstring cstr;相当于string* const cstr;
5.操作C风格的字符串标准函数
①strlen(s) 返回s的长度,不包括null(与sizeof不同)
②strcmp(s1,s2) 返回比较结果.相等返回0,s1>s2返回正数,否则返回负数
③strcpy(s1,s2) 将s2复制给s1,返回s1
④strcat(s1,s2) 将s2连接到s1后,返回s1
⑤strncpy(s1,s2) 将s2的前n个字符复制给s1, 返回s1
⑥strncat(s1,s2) 将s2的前n个字符连接到s1后,返回s1
注意:由于牵涉到null的问题,所以我们在C 中应该尽量使用string 类型
4.1 数组
数组是同一类数据的集合。数组的特点是 以顺序结构结构存储,一点定义就无法更改数组大小。
数组定义很简单:
int a[2] ; // 定义了一个能容纳两个int类型数据的数组
const int sz = 2 ;
myclass ls[sz] ;
定义数组的时候系统可能会自动初始化数组的每个项目,但也可以显示提供值。
int a[3] {1,2,3} ;
可以既指定数组大小又提供初始化列表,此时列表内元素数不能大于维数; 如果列表提供元素小于维数则从数组第一个元素开始显示初始化,没有提供的数组元素会自动初始化。
自动初始化遵从下面规则:
对内置类型来说:
int a[2] ; // 表示要自动初始化。如果a是全局定义的则每一项都初始化为0,否则会分配随机数,表示未初始化
也可以显示给值例如:
int a[] {1,2,3} ; // 显示初始化时候可以不必提供数组大小,系统会自动推断大小
对于类类型来说:
myclass ls[2] ; // 无论在是全局定义还非全部定义都会调用类型的默认构造函数,如果类没有默认构造函数则编译出错
char类型数组比较特殊:
char a[]{'a', 'b', 'c'} ; // 标准定义
char b[]{'a', 'b', 'c', '\0'} ; // 一个C风格的字符串,等价于 char b[] = "abc" 二者的字符数组大小都是4
上面两种定义方式唯一不同的就是最后一个字符是否是 '\0' (结束符)如果是则表明定义了一个C风格的字符串。
要注意:虽然char b[] = "abc" 内容只有三个字符,由于这种定义是C风格字符串的定义法所以系统会自动在对应的字符数组后面加上 '\0'
在指定大小定义C风格字符串时要注意前后长度匹配 char b[3] = "abc" 会产生错误,需要存放四个字符大小。
和其他类型定义不同,数组定义是没有类似 int a[](b) 这种定义方式的,因为数组不支持复制操作。
数组最常用的操作办法是小标操作 a[0] 表示第一个项,它是左值操作。
表示数组下标和数组大小的数据类型和bitset一样是size_t 但是数组只有下标操作,没有取大小等其他操作。
4.2 指针的引进
指针一般是对对象的存放地址的直接指向,一般定义形式为:
int *cur ; // 定义了一个未初始针未初始化指针值是个随机数
int *cur = 0 ; // 可以给指针赋予初始0值表示该指针没有指向任何对象,不应对其有任何操作 。这个赋值表达式中0值是有约束的,必须是字面常量或者编译时常量值0
int *cur = 121 ; // 也可以给指针赋予一个整数常量,但最好不要这么做。因为该常量表示内存地址而我们并不十分清楚这个地址中存放了什么数据。一单指针做了某些操作就可能破坏这些数据,对一个未知的内存做指针指向是危险的(未初始化指针情况也类似)
应该在定义是就给予其初始化工作,避免出现野指针:
int a = 123 ;
int *cur = &a ;
有一类比较灵活的指针 *void 可以指向任何类型的变量;
int a = 123 ;
string b = "abc" ;
void p1 = &a ;
void p2 = &b ;
这类指针表示指向某个内存地址的数据,但不清楚改数据类型。void指针操作有限。由于不知道指向的数据类型所以不能对指向数据做任何操作。
有一类指针可以指向另外的指针,也就是指向指针的指针定义如下:
int a = 123 ;
int *cur = &a ;
int **curr = &cur ; 这类指针需要做两次解引(**curr)才能获取真正的对象值。
指针操作一般有两个意思:
对指针指向的数据做操作(需要解引):
int a = 123 ;
int *cur = &a ;
*cur = 456 // 等价于 a = 456; (对所指向的数据做操作需要做解引在做操作(就是在变量引用时保持*号))
对指针本身操作是指改变指针的指向对象:
int a = 123 ;
int *cur = &a ;
int b = 123 ;
int *curb = &b ;
a = b ; // 等价于 a = &b (对指针本身操作不能带解引符号*) a, b两个指针现在都指向了变量 b ,变量 a 现在没有任何指针指向。
上面讲了数组的基本概念,数组和指针有着非常紧密的联系。 由于数组本身只有下标操作太过简单,所以大部分情况下都使用指针来操作数组。
指针不能直接指向数组变量,它是通过指向数组中得某个项并前后移动来操作数组;
int a[count] = {1,2,3,...} ;
int *cur = a ; // 该操作是简化操作实则是指针指向了数组的第一项,等同于 int *cur = &a[0]
也可以明确指定 int *cur = &a[2] ;
指定了数组的指针可以前后移动,导航到当前项的前后项指针:
int *next = cur 1 ;
int *prv = cur -1 ;
int *next3 = cur 3 ; // 当前项向后移动三位的项指针
数组在数据范围前后一位溢出位的指针表示叫哨兵位,一旦指针到了任意一个哨兵位就不能再做一般化处理。
int a[10] = {1,2,3,...} ;
int *cur = &a[0] ;
int *cur1 = cur -1 ; // cur1是哨兵位,表示指针已经移出数组
int *cur2 = cur 10 ; // cur1是哨兵位,表示指针已经移出数组
两个数组指针可以相减,值是类型为 ptrdiff_t 的项间距(两个操作数中不能有哨兵位)如下:
int a[] = {1,2,3,...} ;
int *cur1 = &a[1] ;
int *cur2 = &a[5] ;
ptrdiff_t pd = cur2 - cur1 ; (也可以交换两个操作数的位置,结果允许为负数)
指针可以在数组有效范围内任意移动,找到相应项后如何操作数组的真实值呢? 只需要解引既可。
int a[] = {1,2,3,...} ;
int *cur = &a[1] ;
*cur = 1 ; // 等同于 a[1] = 1
数组最重要的是下标操作。数组指针也有下标操作,但是意义和数组下标不一样
int a[] = {1,2,3,...} ;
int *cur = &a[1] ;
cur[1] = 2 ; // 等价于 *(cur + 2) = 2 也等价于 a[3] = 2
int i = cur[-2] ; // 等价于 int i = *(cur - 2) 也等价于 int i = a[1]
指针是数组的迭代器,最后让让我们看看用指针如何实现迭代
点击(此处)折叠或打开
可以用const修饰定义指针。
Ø指向常量的指针:
const int a = 123 ;
const int *cur =&a ; // const 必须
需要注意:常量的指针必须是指向常量指针,但指向常量指针可以指向常量也可以指向变量。无论如何都不能对它所指内容做更改,即使它实际指向了变量,但可以更改这个指针的指向
int c =456 ;
cur = &c ; // 更改了指针的指向,现在指向的实际是个变量
*cur = 789 ; // 不允许,虽然指向的是变量但系统认为是常量所以不允许修改
Ø常量指针:
表示不能重新再做指向更改,但也许可以修改它指向的对象的值,这取决于它指向的值是变量还是常量 如下:
const int a = 123 ;
int b = 456 ;
int *const cur1 = &a ; // 此时不允许允许 *cur = 789,因为指向了一个常量
int *const cur2 = &b ; // 此时允许允许 *cur = 789,因为指向了一个变量
cur1 = &b ; // 错误,不允许更改指针的指向
需要注意的是这类指针在定义时必须初始化。
如果我定义了这样一个指针
const int *const cur = &a;
那么既不能更改指向的数据值,也不能重新指向其他数据
const在*的左边,则指针指向的变量的值不可变;在*的右边,则指针的指向不可变。简记为“左定值,右定向”。
4.3 c风格字符串
前面内容了解了char 数组可以表示c风格字符串,既然数组可以用指针表示那么char*也可以表示c风格串
char a[]{'a','b','c','\0'} ; // 第一种数组定义语法
char a[] = “abc” ; // 第2种数组定义语法
char *a = “abc” ; // 指针表示法
c风格的字符串有多个操作函数: strlen(), strcpy(),strcat()以及strcmp()
函数中所说的结束标示NULL实际上就是最后一个字符 '\0' 。
strlen(s1)==5,原因是{'m','o','b','i','l'};指定一部分内容的时候,剩余部分会自动赋值为空字符,而'\0'是转义字符表示的就是空字符.
strlen(s2)==4,因为第五个字符是字符串结束符'\0'(==0)。
strlen(s3)==?,因为他没有结束符。
可以创建动态数组,动态数组创建时更具类型不同其初始化值也不同。
点击(此处)折叠或打开
可以看到内置类型需要在后面加上()才可以让元素初始化。
动态数组定义之后一定要手动删除掉,否则会造成内存泄露
delete [] a ; // 方括号必不可少,表示要释放一个动态数组