关于C++中char型数组、指针及strcpy函数的细节观察

本文详细介绍了C++中char型数组的声明与初始化,包括自动补充'/0'的情况,以及未初始化时的不确定性。同时探讨了指针声明与初始化的区别,32位机上的内存对齐现象。还分析了strcpy函数的工作原理和使用注意事项,强调了传参时避免数组越界和指针未初始化的重要性。通过示例代码,展示了正确和错误的使用方式及其潜在问题。

1.声明字符数组时,[]中的数应为数组中字符个数,包括'/0'

   如 char p[5] = "dddd";

   则实际为:'d' 'd' 'd' 'd' '/0'.

   若 char p[5] = "ddddd";

   则编译出错,提示越界.

 

2.(1)初始化字符数组时,会自动补充'/0'

   如  char p[5] = "dd";

   则实际为:'d' 'd' '/0' '/0' '/0'

   再如  char p[3] = "";

   则实际为:'/0' '/0' '/0'

   (2)若没有只是声明字符数组,没初始化并不会自动补'/0'

   如  char p[3];

   则实际字符数组内容并不可知,因为实际上p也是个指针,现在并不知道它的指向

   (3)同理,声明字符指针并不初始化时,也不知道指针的指向

   如  char *p;

   (4)声明并初始化指针,由于"内存对齐"(由编译器实现),对32位机

    则会补齐4位,自动补'/0'

    如 char *p = "a";

    则实际为:p[0]='a',p[1]='/0',p[2]='/0',p[3]='/0'.

    若 char *p ="";

    则实际为:p[0]='/0',p[1]='/0',p[2]='/0',p[3]='/0'.

  

 

3.strlen(const char* p)函数返回的是字符数组中字符个数,不包括'/0'

   如 char p[5] = "dddd";

       char p2[3] = "";

       int i = strlen(p);

       int j = strlen(p2);

   此时 i = 4 , j = 0

 

4.关于strcpy函数

   函数的实现为:

   char *strcpy(char *strDestination, const char *strSource)

 {

    assert(strDestination && strSource);

    char *strD=strDestination;

    while ((*strDestination++=*strSource++)!='/0')

    NULL;

    return strD;

 }

   这个函数并不会检查是否下标越界,所以使用时要注意:

   ->给函数传的第一个参数必须是字符数组或者是已经指向字符数组的字符指针.   

   ->并且第一个参数的数组大小应该大于或等于第二个参数.

   (1)先讨论正确的传参,如下代码:

   char a[] = "123";char b[] = "123456";// 也可以是char *a = "123";char *b = "123456";

   char p1[4];char p2[9];    //[]中的数一定要大于等于第二个参数字符数组大小

   char *p3;p3 = p1;

   char *p4;p4 = p2;

   strcpy(p1,a);strcpy(p2,b);

   strcpy(p3,a);strcpy(p4,b);

   以上代码中实现复制是正确的.

   (2)错误代码一:

   char a[] = "123";   char *p1;  

   char *p2 = "";

   strcpy(p1,a);  //--------1  

   strcpy(p2,b);  //--------2

   以上代码编译可以通过,但运行时1,2两行都会出现错误并被退出.

   原因是p1并没有初始化,指向并不确定,将p1所指内容用"123"覆盖会导致错误,

   覆盖p2也有可能修改原先指向的并不确定的值而导致错误

   (3)错误代码二:

   char a[] = "123456";

   char p[2];

   strcpy(p,a);

   printf("%s/n%s",p,a)

   编译不会出错,运行结果为

   123456

   56 

   发现到,p的确得到了想要的值,但是a竟然被修改了

   原因是,复制时具体的操作如下:

   复制前的内存结构为p在前,a在后  :'/0' '/0' '/0' '/0' '1' '2'  '3' '4' '5' '6' '/0'

   p指向第一个'/0',a指向'1'.虽然声明为p[2],但由于"内存对齐",编译器自动补充两字符并填'/0'

   复制后的内存结构仍为p在前,a在后:'1'  '2'  '3'  '4'  '5' '6' '/0' '4' '5' '5' '/0'

   p和a所指的内存地址并不会变,所以此时p指向的是'1',a指向的是'5'

   因此就出现了上述的错误

 

### C++ 中 `char*` 数组常用函数及使用方法 #### 字符串初始化与赋值 在C++中,可以通过多种方式来定义和初始化字符指针变量。一种常见的方式是直接指定字符串字面量: ```cpp char *str = "hello"; ``` 这种方式下,`str`指向的是一个常量字符串区域,不应尝试修改其内容[^3]。 对于动态分配内存并复制字符串的情况,则需采用如下形式: ```cpp char str[20]; strcpy(str, "hello"); // 或者更安全的做法是使用 strcpy_s 来防止缓冲区溢出风险 strcpy_s(str, sizeof(str), "hello"); ``` 这里展示了如何利用标准库中的 `strcpy()` 函数完成两个字符串之间的拷贝工作。为了提高安全性,在现代编程实践中推荐优先考虑带有 `_s` 后缀的安全版本——即 `strcpy_s()` ——它允许额外传入目标缓冲区大小参数从而有效规避潜在的风险[^2]。 #### 获取字符串长度 要获取由 `char*` 类表示的字符串的实际长度(不含结尾处的空终止符),可借助于 `strlen()` 函数实现: ```cpp #include <cstring> // 包含 strlen 的头文件 char a[100] = "hello"; size_t length = strlen(a); std::cout << "Length of string is: " << length << std::endl; ``` 上述代码片段会输出 `"Length of string is: 5"` ,因为所给定字符串 `"hello"` 正好含有五个非零字符[^4]。 #### 连接字符串 当需要拼接多个字符串时,可以调用 `strcat()` 或更为安全的选择 `strcat_s()` 。需要注意的是,在执行连接之前应当确保目的缓存有足够的空间容纳新增加的部分以及原有的数据加上结束标记 `\0` : ```cpp char dest[50] = "Hello "; const char src[] = "World!"; strcat_s(dest, sizeof(dest), src); std::cout << dest; // 输出 Hello World! ``` 此例子中,首先声明了一个固定尺寸为五十个字符的空间用于存储最终结果,并预先填入部分初始文本;接着通过 `strcat_s()` 将另一段文字追加至后面形成完整的问候语句。 #### 查找子串位置 如果想要定位某个特定模式首次出现的位置,那么就可以运用 `strstr()` 函数来进行匹配操作: ```cpp const char haystack[] = "This is an example."; const char needle[] = "example"; if ( strstr(haystack, needle) != NULL ) { std::cout << "Substring found!" << std::endl; } else { std::cout << "Not Found." << std::endl; } ``` 这段程序能够判断短字符串是否存在于较长的一方之中,并据此作出相应反馈。 #### 比较字符串 最后介绍比较两段相同类的序列是否相等的方法之一就是依靠 `strcmp()` 完成这项任务。该功能接受一对待测对象作为输入参数,并依据它们之间差异程度给出正负整数值指示先后顺序关系或者是完全一致的结果: ```cpp int result; result = strcmp("abc", "def"); // 返回小于0 的数 result = strcmp("ghi", "ghi"); // 返回等于0 的数 result = strcmp("jkl", "ijk"); // 返回大于0 的数 ``` 综上所述,围绕着 `char*` 所展开的各种实用工具确实相当丰富多样,涵盖了从基本属性查询直到复杂变换处理在内的众多方面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值