• C--六、字符串


    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上述几个数组的一些说明与区别:

    1. 只有字符串赋值的时候才会自动加’\0’
    2. 字符串和字符数组的区别:字符串的结束标志位 ‘\0’
    3. 2与3的区别:使用sizeof关键字计算出2的长度为4。sizeof关键字计算出3的长度为5。
    4. 4:此种声明方式,会默认其为字符串,在末尾加上字符 ‘\0’,使用sizeof关键字计算出其长度为5(c语言字符串数组初始化时剩余长度全部为’\0’)。
    5. 2,3,4与5:2,3,4是字符串变量可以更改,但5是字符串常量,不允许被更改。
    6. 指针操作注意:
      1. 其保存的是一个字符串常量的地址,可以通过修改地址来更改指针指向的值
      2. 不能对野指针的空间进行操作

    demo:

    #include 
    
    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'
    	
    	//输出字符串的方式
    	//在使用中的函数,以下列方法输出字符串时
    	//都是使用'\0'作为结束标志符,如果用字符数组的方式声明可能会出现问题
    	printf("cdata2 : %s",cdata2);
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    result:
    在这里插入图片描述

    字符串中常见的错误

    1. 错误1:此种声明方式为字符串常量,不能修改:
    	char *p = "hello;"
    	*p = 'm';
    
    • 1
    • 2
    1. 错误2,野指针:
    	char *p1;//p1没有明确为其分配内存空间,是野指针
    	*p1 = 'a';//此处访问野指针空间出现segment fault
    
    • 1
    • 2

    注意

    1. C语言中指针声明时会分配随机的地址,也就是野指针。
    2. 指针分配具体地址是在赋值以后,其他数据类型分配地址是在声明以后。

    strlen与sizeof的区别

    使用sizeof来计算的时候,得出的是其在计算机中所占字节数。
    使用strlen(针对字符串的,在string.h中)计算的是有效字符的长度,不包括’\0’

    #include 
    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    result:
    在这里插入图片描述

    动态开辟字符串

    1. malloc,函数原型 void *malloc(size_t size),C库函数void *malloc(size_t size)分配所需的内存空间,并返回一个指向它的指针。
    2. realloc,函数原型 void *realloc(void *ptr,size_t size),扩容。C库函数void *realloc(void *ptr,size_t size)尝试重新调整之前调用malloc或calloc所分配的ptr所指向的内存块的大小。
    3. free,C库函数void free(void *ptr)释放之前调用calloc、malloc或realloc所分配的内存空间。
    4. memset,函数原型void *memset(void *str, int c, size_t n)。将指针变量 str 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。s 是 void 型的指针变量,所以它可以为任何类型的数据进行初始化。

    free的目的

    1. 释放空间,防止内存泄漏
    2. 防止悬挂指针----->野指针的一种。

    注意malloc申请的空间里是可能存在垃圾数据的,在使用之前要先用memset清空一下
    demo:

    #include 
    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    result:
    在这里插入图片描述

    字符串常用的API

    1. 输出字符串
      puts(),
      printf(“%s”,p)

    2. 获取字符串:
      scanf(“%s”,p),
      gets

    3. 计算长度:strlen

    4. 拷贝:
      全部或前n个字符
      char * strcpy(char* dest, const char *src);
      char * strncpy(char *dest, const char *src, int n)

    5. 断言:assert。断言一个表达式正确,如果错误就从strerr退出。

    6. 拼接:char *strcat(char *dest, const char *src);

    7. 比较:
      若str1 = str2,则返回零;若strlstr2,则返回正数(全部或前n个字符)
      int strcmp(const char *s1,const char *s2);
      int strncmp ( const char * strl, const char * str2, size_t n)

    8. 查找子字符:
      char *strchr(const char *str, int c);

    9. 查找子串:
      char *strstr(char *strl, const char *str2);

    10. 字符串分割:
      char *strtok(char *str, const char *delim)

    #include 
    #include 
    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;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    注意

    1. gets可以无限读取,易发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值
    2. strtok分割处理后原字符串str 会变,原字符串的改动是切分符原位置均更改为’\0’
  • 相关阅读:
    uniapp中table表格设置宽度无效的原因及解决办法
    STC89C51基础及项目第13天:小车go、软件调速
    vuex技术多组件共享数据-vuex模块化+namespace
    Gateway 网关
    《微服务架构设计模式》第二章
    作业比赛编号 : 1280 - 2022年春季学期《算法分析与设计》练习15
    深度选择器>>> /deep/ ::v-deep亲测好用
    Java 基础常见知识点&面试题总结(下),2022 最新版!
    JPA如何查询部分字段
    一篇文章带你搞定所有二叉树题型的递归思维(思路超详细)
  • 原文地址:https://blog.csdn.net/qq_62283001/article/details/132636638