C–六、字符串
什么是字符串呢?
简单来说,就是字符数组,不过在声明上也有区别。可以借助整形数组来理解。
int intArr[] = {1,2,3,4};//-->1
char charArr2[] = {'a','b','c','d'};//-->2
char charArr1[5] = {'a','b','c','d'};//-->3
char charArr3[] = "abcd";//-->4
//也可以写作
char *charArr4 = "abcd";//-->5
上述几个数组的一些说明与区别:
- 只有字符串赋值的时候才会自动加’\0’
- 字符串和字符数组的区别:字符串的结束标志位 ‘\0’
- 2与3的区别:使用sizeof关键字计算出2的长度为4。sizeof关键字计算出3的长度为5。
- 4:此种声明方式,会默认其为字符串,在末尾加上字符 ‘\0’,使用sizeof关键字计算出其长度为5(c语言字符串数组初始化时剩余长度全部为’\0’)。
- 2,3,4与5:2,3,4是字符串变量可以更改,但5是字符串常量,不允许被更改。
- 指针操作注意:
- 其保存的是一个字符串常量的地址,可以通过修改地址来更改指针指向的值
- 不能对野指针的空间进行操作
demo:
#include <stdio.h>
int main()
{
int idata[] = {1,2,3,4,5};
char cdata[] = {'h','e','l','l','o'};
char cdata1[6] = {'h','e','l','l','o'};
char cdata2[] = "hello";//此种声明方式,会默认其为字符串,在末尾加上字符 '\0'
int size1 = sizeof(idata)/sizeof(idata[0]);
int size = sizeof(cdata)/sizeof(cdata[0]);
int size2 = sizeof(cdata1)/sizeof(cdata1[0]);
int size3 = sizeof(cdata2)/sizeof(cdata2[0]);
printf("idata : %d\n",size1);
printf("cdata : %d\n",size);
printf("cdata1 : %d\n",size2);
printf("cdata2 : %d\n",size3);
printf("cdata1[5] : %d\n",cdata1[5]);//-->'\0'
//输出字符串的方式
//在使用<string.h>中的函数,以下列方法输出字符串时
//都是使用'\0'作为结束标志符,如果用字符数组的方式声明可能会出现问题
printf("cdata2 : %s",cdata2);
return 0;
}
result:
字符串中常见的错误
- 错误1:此种声明方式为字符串常量,不能修改:
char *p = "hello;"
*p = 'm';
- 错误2,野指针:
char *p1;//p1没有明确为其分配内存空间,是野指针
*p1 = 'a';//此处访问野指针空间出现segment fault
注意:
- C语言中指针声明时会分配随机的地址,也就是野指针。
- 指针分配具体地址是在赋值以后,其他数据类型分配地址是在声明以后。
strlen与sizeof的区别
使用sizeof来计算的时候,得出的是其在计算机中所占字节数。
使用strlen(针对字符串的,在string.h中)计算的是有效字符的长度,不包括’\0’
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(){
int a;
};
int main()
{
char *cdata1 = (char *)malloc(sizeof(char)*5);
memset(cdata1,'\0',5);
*cdata1 = 'h';
char cdata[128] = "hello";
void (*ptest)();
ptest = test;
char cdata2[] = "hello";
//pest是函数指针,也就是地址,在window下是用8是字节存储一个地址
printf("sizeof cdata :%d\n",sizeof(cdata));
printf("sizeof ptest :%d\n",sizeof(ptest));
printf("sizeof *ptest :%d\n",sizeof(*ptest));
printf("sizeof cdata2 :%d\n",sizeof(cdata2));
printf("strlen cdata :%d\n",strlen(cdata));
printf("sizeof cdata1 :%d\n",sizeof(cdata1));
printf("sizeof *cdata1 :%d\n",sizeof(*cdata1));
printf("strlen cdata1 :%d\n",strlen(cdata1));
free(cdata1);
return 0;
}
result:
动态开辟字符串
- malloc,函数原型 void *malloc(size_t size),C库函数void *malloc(size_t size)分配所需的内存空间,并返回一个指向它的指针。
- realloc,函数原型 void *realloc(void *ptr,size_t size),扩容。C库函数void *realloc(void *ptr,size_t size)尝试重新调整之前调用malloc或calloc所分配的ptr所指向的内存块的大小。
- free,C库函数void free(void *ptr)释放之前调用calloc、malloc或realloc所分配的内存空间。
- memset,函数原型void *memset(void *str, int c, size_t n)。将指针变量 str 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。s 是 void 型的指针变量,所以它可以为任何类型的数据进行初始化。
free的目的:
- 释放空间,防止内存泄漏
- 防止悬挂指针----->野指针的一种。
注意:malloc申请的空间里是可能存在垃圾数据的,在使用之前要先用memset清空一下
demo:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//悬挂指针是野指针的一种
char *p = NULL;
p = (char *)malloc(1);
*p = 'a';
free(p);
p = (char *)malloc(12);
memset(p,'\0',12);
printf("p的地址 :%p\n",p);
int len = strlen("helloLiQiaoQiao");
int newLen = len - 12 + 1;
realloc(p,newLen);
printf("扩容后p的地址 :%p\n",p);
strcpy(p,"helloLiQiaoQiao");
puts(p);
free(p);
return 0;
}
result:
字符串常用的API
-
输出字符串:
puts(),
printf(“%s”,p) -
获取字符串:
scanf(“%s”,p),
gets -
计算长度:strlen
-
拷贝:
全部或前n个字符
char * strcpy(char* dest, const char *src);
char * strncpy(char *dest, const char *src, int n) -
断言:assert。断言一个表达式正确,如果错误就从strerr退出。
-
拼接:char *strcat(char *dest, const char *src);
-
比较:
若str1 = str2,则返回零;若strl<str2,则返回负数;若strl>str2,则返回正数(全部或前n个字符)
int strcmp(const char *s1,const char *s2);
int strncmp ( const char * strl, const char * str2, size_t n) -
查找子字符:
char *strchr(const char *str, int c); -
查找子串:
char *strstr(char *strl, const char *str2); -
字符串分割:
char *strtok(char *str, const char *delim)
#include <string.h>
#include <stdio.h>
int main) {
char str[80] ="This is - www.runoob.com - website";
const char s[2] ="-";
char *token;
/*获取第一个子字符串*/
token = strtok(str, s);
/*继续获取其他的子字符串*/
while( token !=NULL ){
printf( "%s\n", token );
token = strtok(NULL,s);
}
return 0;
注意:
- gets可以无限读取,易发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值
- strtok分割处理后原字符串str 会变,原字符串的改动是切分符原位置均更改为’\0’