C/C++ 学习笔记:字符串、数组相关
2016-12-15 23:43
393 查看
C/C++ 中所有字符串字面值都由编译器自动在末尾添加一个空字符,即默认以 \0 结尾。
eg:字面值 "tang" 实际上是 "tang\0",字面值"tang\0" 实际上是"tang\0\0"
char 数组
所以:sizeof(Str) 为 4;sizeof(Str1) 为 5;sizeof(Str2) 为 6。
char* 指针
不会自动在末尾补 \0
string 型变量
1. 以 \0 结尾(不会自动补 \0)
如果把上面不含 \0 的 Str 数组赋值给 string 型变量,则实际会是一直赋值到 \0 结束。相当于调用 string(constchar*s),然后
Str 退化为指针,然后赋值的时候会一直找到 \0 才结束。
2. 其 size() 和 length() 函数得到的都是不含 \0 的长度
重要的:
用字符串初始化指针时,指针指向的是放在常量区的字符串常量;
而用字符串来初始化数组时,是用字符串常量的内容初始化数组的内容;
数组名是一个右值类型( 比如字符型数组的类型为 char*const ),不能作为左值来接收另一个数组。
数组名的本质:
1. 数组名指代一种数据结构,这种数据结构就是数组;
2. 数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;
char str[10];
str++;// 编译出错,提示 str不是左值
3. 数组名作为函数形参时,沦为普通指针。
sizeof 与 strlen 的区别:
1. sizeof(...) 是运算符,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。跟里存储的内容没有关系。
具体而言,当参数分别如下时,sizeof 返回的值表示的含义如下:
a) 数组——编译时分配的数组空间大小;
b) 指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为 4);
c) 类型——该类型所占的空间大小;
d) 对象——对象的实际占用空间大小;
e) 函数——函数的返回类型所占的空间大小。函数的返回类型不能是 void。
2. strlen(...) 是函数,要在运行时才能计算。参数必须是字符型指针(char* )。
当数组名作为参数传入时,实际上数组就退化成指针了,读到 \0 为止返回长度,而且是不把 \0 计入字符串的长度的。
一些例子:
在函数中为指针char* pStr 申请空间:
写出完整版的 strcpy 函数:
编写类 String 的构造函数、析构函数和赋值函数:
eg:字面值 "tang" 实际上是 "tang\0",字面值"tang\0" 实际上是"tang\0\0"
char 数组
char StrArray[4];// 如果数组 StrArray 不是全局变量,内容是随机的。 char StrArray[4] = {'B', 'u'};// 这里会默认给剩余的 2 个元素补上 \0,若 4 个字符全指定了,就不会在最后加上 \0,因为超出数组范围了。 char Str[] = {'t', 'a', 'n', 'g'};// 不会以 \0 结尾 char Str1[] = "tang";// 因为字符串字面值是以 \0 结尾的,所以数组 Str1 也是以 \0 结尾 char Str2[] = "tang\0";// 尽管字面值有一个 \0,编译器还是会默认给字符串字面值后面加一个 \0,即这个字符串常量实际上是 "tang\0\0",所以数组 Str2 实际会以这个字符串常量被默认添加的那个 \0 结尾。
所以:sizeof(Str) 为 4;sizeof(Str1) 为 5;sizeof(Str2) 为 6。
char* 指针
不会自动在末尾补 \0
string 型变量
1. 以 \0 结尾(不会自动补 \0)
如果把上面不含 \0 的 Str 数组赋值给 string 型变量,则实际会是一直赋值到 \0 结束。相当于调用 string(constchar*s),然后
Str 退化为指针,然后赋值的时候会一直找到 \0 才结束。
2. 其 size() 和 length() 函数得到的都是不含 \0 的长度
重要的:
用字符串初始化指针时,指针指向的是放在常量区的字符串常量;
而用字符串来初始化数组时,是用字符串常量的内容初始化数组的内容;
数组名是一个右值类型( 比如字符型数组的类型为 char*const ),不能作为左值来接收另一个数组。
数组名的本质:
1. 数组名指代一种数据结构,这种数据结构就是数组;
2. 数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;
char str[10];
str++;// 编译出错,提示 str不是左值
3. 数组名作为函数形参时,沦为普通指针。
void Func( char str[100] ) { cout << sizeof( str ) << endl;// 32位机器下,这里为 4 } // Func( char str[100] ) 函数中数组名作为函数形参时,在函数体内,数组名失去了本身的内涵,仅仅只是一个指针; // 在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。
sizeof 与 strlen 的区别:
1. sizeof(...) 是运算符,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。跟里存储的内容没有关系。
具体而言,当参数分别如下时,sizeof 返回的值表示的含义如下:
a) 数组——编译时分配的数组空间大小;
b) 指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为 4);
c) 类型——该类型所占的空间大小;
d) 对象——对象的实际占用空间大小;
e) 函数——函数的返回类型所占的空间大小。函数的返回类型不能是 void。
2. strlen(...) 是函数,要在运行时才能计算。参数必须是字符型指针(char* )。
当数组名作为参数传入时,实际上数组就退化成指针了,读到 \0 为止返回长度,而且是不把 \0 计入字符串的长度的。
一些例子:
void test1() { char str[10]; char* str1 = "0123456789"; strcpy( str, str1 );// 字符串 str1 需要 11 个字节才能存放下(包括末尾的 '\0'),而 string 只有 10 个字节的空间,strcpy 会导致数组越界 }
void test2() { char str[10], str1[10]; int i; for(i=0; i<10; i++) str1 = 'a';// 编译错误。因为数组名 str1 为 char *const 类型的右值类型,根本不能赋值 // 再者,即使想对数组的第一个元素赋值,也要使用 *str1 = 'a'; strcpy( str, str1 );// 对字符数组赋值后,使用库函数strcpy进行拷贝操作,strcpy会从源地址一直往后拷贝,直到遇到'\0'为止。所以拷贝的长度是不定的。如果一直没有遇到'\0'导致越界访问非法内存,程序就崩了。 }
void test3(char* str1) { if(str1 == NULL) return ; char str[10]; if( strlen( str1 ) <= 10 )// 应改为if(strlen(str1) < 10),因为strlen的结果未统计’\0’所占用的1个字节。 strcpy( str, str1 ); }
void Test4() { char *str = (char *) malloc( 100 ); strcpy( str, "hello" ); free( str ); ... //省略的其它语句 } //在执行 char *str = (char *) malloc(100); 后未进行内存是否申请成功的判断; //另外,在 free(str) 后未置 str 为空,导致可能变成一个“野”指针,应加上:str = NULL;
Swap(int* p1, int* p2) { int *p;// p 没有申请空间就使用,是一个“野”指针,有可能指向系统区,导致程序运行的崩溃 *p = *p1; *p1 = *p2; *p2 = *p; }
在函数中为指针char* pStr 申请空间:
// 传值调用 OK void GetMemory( char **p ) { *p = (char *) malloc( 100 ); } // 引用调用 OK void GetMemory(char *&p) { p = (char *) malloc (100); } // 使用一级指针,不行 // 因为作为形参传递后,有p和pStr都指向同一个地方,当malloc后,p就指向了新的地方,而pStr没变 void GetMemory( char *p ) { p = (char *) malloc( 100 ); } // 在函数里用数组,不行 // 数组为函数内的局部自动变量,在函数返回后,内存已经被释放。 char *GetMemory( void ) { char p[] = "hello world"; return p; }
写出完整版的 strcpy 函数:
char * strcpy( char *strDest, const char *strSrc ) {// 将源字符串加 const,表明其为输入参数 assert( (strDest != NULL) && (strSrc != NULL) );// 对源地址和目的地址加非 0 断言 char *address = strDest; while( (*strDest++ = * strSrc++) != '\0' ); return address;// 为了实现链式操作,将目的地址返回 }
编写类 String 的构造函数、析构函数和赋值函数:
class String { public: String(const char *str = NULL); // 普通构造函数 String(const String &other); // 拷贝构造函数 ~String(void); // 析构函数 String& operator=(const String &other); // 赋值函数 private: char *m_data; // 用于保存字符串 }; //=============================================================================== // 普通构造函数 String::String(const char *str) { if(NULL == str) { m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志'\0'的空 assert(NULL != m_data);// 加分点:对m_data加NULL 判断 *m_data = '\0'; } else { int length = strlen(str); m_data = new char[length+1]; assert(NULL != m_data);// 若能加 NULL 判断则更好 strcpy(m_data, str); } } // String的析构函数 String::~String(void) { delete[] m_data; // 或 delete m_data; } // 拷贝构造函数 String::String(const String &other) {// 得分点:输入参数为 const 型 int length = strlen(other.m_data); m_data = new char[length+1]; assert(NULL != m_data);// 加分点:对 m_data 加 NULL 判断 strcpy(m_data, other.m_data); } // 赋值函数 String& String::operator=(const String &other) { // 得分点:输入参数为const型 if(this == &other) // 得分点:检查自赋值 return *this; delete [] m_data;// 得分点:释放原有的内存资源 int length = strlen( other.m_data ); m_data = new char[length+1]; assert(NULL != m_data);// 加分点:对 m_data 加 NULL 判断 strcpy( m_data, other.m_data ); return *this;// 得分点:返回本对象的引用 }
相关文章推荐
- C/C++ 学习笔记:字符串、数组相关
- C++学习笔记 | 第三章 字符串、向量和数组 | (1)
- 【C++学习笔记】数组和指针再C-风格字符串的演示
- C\C++ 程序员从零开始学习Android - 个人学习笔记(四) - java基础 - 数据类型、变量、字符串、数组
- C++学习笔记(一)--整形,std输出,浮点数,数组,字符串,结构,指针,循环
- C++ Primer 学习笔记(第三章:字符串、向量和数组)
- C++基础教程 学习笔记(二) 数组、字符串和指针
- 20121017c++学习笔记,文件读取,字符串相关
- C_PlusPlus学习笔记 - 5_数组、指针和字符串 (C++语言程序设计【第三版】 郑莉等,清华大学出版社)
- c++学习笔记2——指向字符串的指针数组?
- C++ 学习笔记(3)命名空间using、字符串、string、vector、迭代器、数组
- C++学习笔记三:字符串、向量和数组
- 数组、指针和字符串(一)------C++学习笔记
- [学习笔记][C++Primer Plus]使用cout格式化输出字符串,3q xuzhong
- C++学习笔记二 C++标准库 数组及指针
- 【C语言】学习笔记:字符串与字符数组
- C++数组类型学习笔记
- C/C++中关于地址、指针和引用变量的学习笔记(二) : 数组
- 声明字符串"javascript学习笔记,String字符串相关:
- C#学习笔记三字符串相关操作