c字符串
我们知道在关于字符串的操作函数很多都包含在头文件#include<string.h>中,例如计算字符串长度的函数strlen。今天我们们用自己的语言来实现一下关于字符串的复制,连接,和比较
strcmp()字符串比较函数的指针实现
字符串串比较的时候实际上是ASC||值的比较,因此用关系运算符比较即可
int my_strcmp(char* str, const char* src) {
assert(*str != NULL && *src != NULL);
while (*str = *src) {
if (*str = '\0') {
break;
}
str++;
src++;
}
if (str > src) {
return 1;
}
else if (str < src) {
return -1;
}
else {
return 0;
}
}
这里我们发现了在跳出循环后的代码冗余,我们可以用一个三目运算符进行优化
int my_strcmp(char* str, const char* src) {
assert(*str != NULL && *src != NULL);
while (*str = *src) {
if (*str = '\0') {
break;
}
str++;
src++;
}
if (str == '\0'&& src == '\0') {
{return 0; }
return str > src ? 1:-1;
}
经过这样的判断我们就可以得到如果str=src返回0,str>src返回1,str<src返回-1。
strcat(),字符串连接函数
我们这里可以直接使用指针访问到字符串的尾部在加上需要连接的字符串或者我们使用指针移位的方式操作,同时要注意连接前的字符串数组的大小应该要大于连接后的大小。
void my_strcat(char* p, char* q) {
assert(p != NULL && q != NULL);
int i = strlen(p); int j = 0;
while (*(q + j) != '\0') {
*(p + i) = *(q + j);
i++; j++;
}
*(p + i) = '\0';
}
char* my_strcat2(char* p, const char* q) {
while (*p++ != '\0');
while (*q != '\0') {
*p++ = *q++;
}
*p = '\0';
}
最后比较重要的是字符串默认以\0结尾,所以不管哪种方式,我们都要在尾部加上\0。
strcpy(),字符串拷贝函数,同上一个函数一样我们在最后都需要加上字符串的默认结尾\0
void my_strcpy(char* p, char* q, int len) {
assert(p != NULL && q != NULL);
if (p <= q && p >= q + len - 1) {
for (int i = 0; i < len;) {
*(q + i) = *(p + i);
i++;
}
}
else {
for (int j = len - 1; j >= 0;) {
*(q + j) = *(p + j);
j--;
}
}
}
char* my_strcpy(char*q,const char*p) {
assert(*p != NULL && *q != NULL);
while (*p != '\0'){
*q = *p;
q++;
p++;
}
*q = '\0';
}
指针习题中的问题
1. 即使不进行强制类型转换,在进行指针赋值运算时,指针变量的基类型也可以不同
这句话显然是错误的,基类型也就是指针变量的基本类型,它反映了指针变量可以存储变量大小和+1能力,比如一个char*p int *s p+1就是加了sizeof(char) ,而s+1就加了sizeof(int),所以在对指针进行赋值运算时,指针变量的基类型不能不相同
2.设变量p是一个指针变量,则语句p=0;是非法的,应该使用p=NULL;
在c语言中,这两者其实是相同的,0就是NULL,NULL也就是0
3. 指针变量之间不能用关系运算符进行比较
这个也是错误的,指针变量是可以进行关系运算符的比较的。但是同一个变量但是在不同的情况下的情况也不同
const char*s="hello";
const char*p="hello';
那么s和p的地址实际上是相同的
因为这属于字符串常量,存储的时候是存储在数据区,s会先在常量池中寻找是否有"hello",如果没有就在常量池中加入,p就会找到”hello“存储的地方并且拿到它的地址,所以s和p的地址实际上是相同的
char arr[]=”hello“;
char brr[]="hello";
在这里这两者的地址就不是相同的,因为他们是在栈中申请一块连续的内存空间存储hello\0,而我们知道,栈是从高地址往低地址分配内存空间,那么arr的地址就和brr的地址不相同
4.float a[10], x;语句 a = &x; 是非法的
这个是正确的,这就涉及到了c语言中的函数赋值问题
例如 int arr[];
int brr[10]={1,2,3,4,5};
arr[]=brr[10];
关于数组的赋值不能只有简单的等号来进行
5.C、 可以取一个指针变量的地址赋给本指针变量,这样就使得指针变量指向自身
这个选项是错误的
例如 int *p
p=&p,这是将一个二级指针赋给一个一级指针语法上就是有问题的。
6. 指针变量所占内存的大小与其类型有关,char型指针变量只占1个字节,double型指针变量占8个字节
这个是错误的,指针的大小只和操作系统有关
7.以下不能将s所指字符串正确复制到t所指存储空间的是( )。
A、 for(i=0,j=0;t[i++]=s[j++]; );
B、 for(i=0;t[i]=s[i];i++);
C、 while(*t=*s){t++;s++;}
D、 do{*t++=*s++;}while(*s );
这个题的正确选项是D选项,因为do while是先执行在判断,这就会使其先加一再判断,就会丢失字符串末尾的\0。
8.double a[10] ,*s=a;
以下能够代表数组元素a[3]的是( )。
A、 (*s)[3]
B、 *(s+3)
C、 *s[3]
D、 *s+3
在这个题目条件下就是选择b选项
但是如果改变一下题目条件
double (*s)[4]={1,2,3,4,5,6,7,8}
(s*)[4]=a;
中的a[0][3]元素应该如何选择首先找到他的地址*(a+0)+3,在对地址解引用*(*(a+0)+3)也就是*(*a+3),将a换成s,也就是*(*s+3),那么他就和A代表的值是一样的。