char *,char[],strcpy的终极解答

您所在的位置:网站首页 charstr char *,char[],strcpy的终极解答

char *,char[],strcpy的终极解答

2023-10-02 17:17| 来源: 网络整理| 查看: 265

这篇文章有一些基本的前驱内容,可以先看看大概了解https://blog.csdn.net/qq_43265890/article/details/89568638 或者你可以直接看我总结的:

另外关于堆区,栈区,常量区的讨论网上也有很多,这里再讨论一些细枝末节的事情

char *s = “abc”;这个在常量区,常量区的值可读不可写,如:s[1] = “d”;这样的方式会报错,但是可以给指针重新赋值 s = “add”。 char s[] = “abc”; s[]是一个数组,在栈中占3个字节,存放的分别是’a’,‘b’,‘c’; s不是指针。 sizeof(s)得到的结果也是数组长度,但为4(包括’\0’),可以认为,s成为了一种新的数据类型,此概念在帮助理解多维数组。

以上问题的根本原因在于`:

char * 是数据类型,即指针。 指针的特殊性包含两层意思,一层他是指针,有指针固定的大小,存放的东西是地址。另一层,他不是什么地址都存放,他要存放char类型的地址。

字符串常量在c中类型是char* ,也就是说,他本来就是一个指针,而且是char的指针。 (很奇怪吧,你可以理解成,char* s = “abcd” 是在常量区保存了"abcd",显示赋值时,其实是把这个地址给了s。别问为啥这么反常,就这么定义的) 左边是char* 右边也是char*,能够赋值是理所当然的事情!所谓类型系统,目的就是要保证赋值的类型是兼容的。

char a; char * pa = &a; 为何a不能直接赋值给pa?因为pa是char*,而a是char,类型不兼容。 为什么&a能够赋值给pa?因为&a的结果类型是char*。

并非要地址才能赋值给指针,任何东西都能赋值给指针,只要类型一致! 如: char* pa = (char* )1; 强制类型转换,让常数1转型为char*,就存进了指针里面。 地址是什么?任何在内存的变量,都有类型,和首地址,这两个能够唯一确定一个变量。类型指示了所占空间的大小,首地址指示了开始的位置,有这两个东西就能操作变量。 指针就是对应这两个东西的变量,指针的类型说的是目标地址上变量的类型,而不是指针本身有类型,指针就一种,他的大小取决于cpu,32位寻址的cpu就是一个32位的指针。

因此,可以用一个32位的无符号整数赋值给指针,让他指向任何地址。

Tips char p[] = {‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’,‘h’}; sizeof§的结果是8; char p[] = {“abcdrfgh”} sizeof§的结果是9;

strcpy的实现,这里考虑内存重叠的问题(请考虑一个问题,如果destination是char[],source是char *,是不是就不会发生内存重叠了呢?我的看法是支持的,所以这里考虑的内存重叠只会在destination是char[],source也是char[]的情况下才会发生)

首先,

不考虑内存重叠 char * strcpy(char *dst,const char *src) //[1] { assert(dst != NULL && src != NULL); //[2] char *ret = dst; //[3] while ((*dst++=*src++)!='\0'); //[4] return ret; } 重叠问题的分析:

(1)src + count dst 这时也是部分重叠,但影响拷贝,应该从高字节逆序开始。 其实第1种的第二种情况和第二种同属于一类,dst char *s = dst; while (length--) { *dst++ = *src++; } return s; } else { dst = dst + length - 1; src = src + length - 1; while (length--) { *dst-- = *src--; } return ++dst; //不要忘了++; } }

总结:内存重叠是考点,另外要注意的: [1]const修饰

源字符串参数用const修饰,防止修改源字符串。

[2]空指针检查

(A)不检查指针的有效性,说明答题者不注重代码的健壮性。

(B)检查指针的有效性时使用assert(!dst && !src);

char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。

©检查指针的有效性时使用assert(dst != 0 && src != 0);

直接使用常量(如本例中的0)会减少程序的可维护性。而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。

[3]返回目标地址

(A)忘记保存原始的strdst值。

[4]’\0’

(A)循环写成while (*dst++=*src++);明显是错误的。

(B)循环写成while (*src!=’\0’) *dst++=*src++;

循环体结束后,dst字符串的末尾没有正确地加上’\0’。

2.为什么要返回char *? 返回dst的原始值使函数能够支持链式表达式。

链式表达式的形式如:

int l=strlen(strcpy(strA,strB));

又如:

char * strA=strcpy(new char[10],strB);

返回strSrc的原始值是错误的。

其一,源字符串肯定是已知的,返回它没有意义。

其二,不能支持形如第二例的表达式。

其三,把const char *作为char *返回,类型不符,编译报错。

关于memcpy和strcpy的区别

strcpy和memcpy都是标准C库函数,它们有下面的特点。

strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。

已知strcpy函数的原型是:char* strcpy(char* dest, const char* src); memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。

void *memcpy( void *dest, const void *src, size_t count ); strcpy和memcpy主要有以下3方面的区别。 1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。 2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。 3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy 2.memcpy与memmove 功能:从存储区 src 复制 n 个字符到存储区 dest。 如果写出的代码如下:你也没考虑内存重叠!

void *memcpy(void *dest, const void *src, size_t n) { if (!dest || !src) return NULL; char *d = (char *) dest; const char *s = (const char *) src; size_t i = 0; for (i = 0; i if (!dest || !src) return NULL; char *d = (char *) dest; const char *s = (const char *) src; if (d > s && d while (n--) *d++ = *s++; } return dest; }

上述也是memmove函数实现! 都说到这了,咱把strcat和strlen都说了吧哈哈 //函数strcat的原型是char* strcat(char* des, char* src),des 和 src 所指内存区域不可以重叠且 des 必须有足够的空间来容纳 src 的字符串。

char* strcat(char* des, const char* src) // const表明为输入参数 { assert((des != NULL) && (src != NULL)); char* address = des; while (*des != '\0') // 移动到字符串末尾 ++des; while (*des++ = *src++) ; return address; }

函数strlen的原型是size_t strlen(const char *s),其中 size_t 就是 unsigned int。

strlen 与 sizeof 的区别:详细见另一篇文章 sizeof是运算符,strlen是库函数。

sizeof可以用类型、变量做参数,而strlen只能用 char* 变量做参数,且必须以\0结尾。

sizeof是在编译的时候计算类型或变量所占内存的大小,而strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度。

数组做sizeof的参数不退化,传递给strlen就退化为指针了。

int strlen(const char* str) { assert(str != NULL); int len = 0; while ((*str++) != '\0') ++len; return len; }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3