C提高(3)字符串

    xiaoxiao2021-03-25  220

    字符串的定义 C语言中没有string数据类型,那么C中如何表示字符串呢? 有两种方法 : 1. 字符数组+转义字符’\0’ 2. 字符指针

    我们来看一下一下代码:

    //字符初始化字符数组&不指定长度 char str1[] = {'a', 'b', 'c', 'd','\0'}; //通过字符数组定义一个字符串,数组长度由初始化数组元素个数决定,该语句等价于char str1[]="abcd"; //字符初始化字符数组&指定长度 char str3[128] = { 'x', 'y', 'z' }; //先定义一个128字节的字符数组,初始化前三个元素为xyz,其余元素置0。 //利用该方法我们可以初始化一个值为0的字符数组char xx[128]={0}; //字符串初始化字符数组 char str1[]= "abcd"; //字符串初始化字符指针 char *str2 = "abcd"; //定义一个字符指针str2,str2占4个字节,str2指向常量区中的占5个字节的字符串"abcd" 补充:sizeof和strlen的区别 sizeof是运算符,sizeof的结果,在编译时就已经确定。而strlen是函数,其结果在调用函数后才返回。sizeof 求的是数据类型的大小,而strlen求的是字符串的长度。

    字符串的操作 我们知道字符串的定义有字符数组和字符指针两种方法。那么对字符串的操作也就是对应的两种方法了。

    数组法–利用数组下标访问元素指针法–改变指针的值,访问不同的元素 两者的关系 char array1[]="abcd"; char *p = array1; //则array1[i]=*(p+i); 数组法和指针法是等价的只不过表示方法不同 //同理我们可以推出: array[i][j]= *(*(p+i)+j) //array1可以理解为一个“常指针”但不完全等于常指针。array1指向的是array1数组首元素地址且值不能改变。值不变是为了栈回收内存时能够准确找到当时分配内存时的地址。为什么说数组名不是一个常指针?因为array1不完全是一个常指针;字符指针一般在常量区分配内存,而字符数组在栈上分配内存。

    字符串简单应用

    字符串的遍历字符串的copy字符串查找子串字符串两头堵模型字符串的反转与递归

    字符串遍历 假设我们有一个字符串”abcdefg”我们如何遍历其中的元素呢? 遍历问题实际上可以看做是两个小问题,从哪里开始遍历以及遍历多少个元素。 打印应该从字符串首元素开始,那么如何获取首元素呢?通过首元素地址。我们定义字符数组和字符指针的时候就获取到了字符串首元素的地址。 知道了字符串首地址,我们就可以开始遍历了。那么要遍历多少个元素呢?答案是strlen()。知道了字符串元素个数就知道了要遍历多少次才能把所有的元素打印出来。

    int main(void){ char arr[] = "abcdefg"; char *p = NULL; p = arr; int i = 0; for (i = 0; i < strlen(arr); i++){ printf("arr[%d]:%c\n", i, arr[i]); printf("*(p+%d):%c\n", i, *(p + i)); } return 0; }

    字符串的copy 我们先考虑一种最直接的思路 我们有两个字符串src 和dst。我们想把src中的字符copy到dst中。

    int str_copy1(char *dst, char *src){ char *temp_dst = NULL; char *temp_src = NULL; int retn=0; //判断传参 if (dst == NULL || src == NULL) { fprintf(stderr, " dst == NULL || src == NULL \n"); retn = -1; goto END; } for (temp_dst = dst, temp_src = src; *temp_src != '\0';temp_dst++,temp_src++){ *temp_dst=*temp_src; } *temp_dst = '\0'; //打日志 printf("dst : %s\n", temp_dst); END: return retn; } /* 一:理解for函数 for(1;2;3){ 4; } 1:循环初始化条件; 2:循环结束条件; 3:循环flag改变; 4:循环体; for函数执行顺序 |-------------| ↓ ↑ 1 --> 2 --> 4 --> 3 | ↓ 结束循环 43本质上是一样的,只是写的位置不同而已。 二:其他copy的循环条件 1while ((*dst++ = *src++)); 2for (; (*dst = *src) != '\0'; ) { src++; dst++; } 3for (; *src != '\0';) { *dst++ = *src++; // *dst = *src, dst++, src++ } *dst = '\0'; */

    字符串查找子串 do-while模型和while模型 本质上是利用一个指针对字符串进行遍历

    int get_sub_str_count(char *src, char *sub_str, int *cnt_p) { char *p = src; int cnt = 0; int retn =0; if (src == NULL || sub_str == NULL) { fprintf(stderr, "(src == NULL || sub_str == NULL\n"); retn = -1; goto END; } while ((p = strstr(p, sub_str)) != NULL) { //找到了子串 cnt++; //移动指针并判断此时指针是否为空 p += strlen(sub_str); if (*p == '\0') { break; } } *cnt_p = cnt; //指针作为函数参数有输出属性 END: return retn; }

    字符串两头堵模型 利用两个指针对字符串进行操作。 下面这个程序利用左右两个指针去除字符串中左右两边的空格。 为什么要用两头堵模型? 因为在windows下读取.ini文件和Linux下读取.conf文件时,经常会遇到key=value这样的数据格式,而value的写法各种各样,我们需要先对value进行一个预处理。

    #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> int get_non_space_cnt(/*in */char *str,/*out*/ int *cnt_p) { char *p = NULL; char *q = NULL; int cnt = 0; if (str == NULL || cnt_p == NULL) { fprintf(stderr, " str == NULL || cnt_p == NULL \n"); return -1; } p = str;//指向字符串首元素 q = str + strlen(str) - 1; //指向字符串的末尾元素 //左边遍历while ((*p == ' ' && *p !='\0') ) while (isspace(*p) && *p != '\0') { p++; } //右边遍历while ((*q == ' ') && (q > p)) while (isspace(*q) && (q >p) ) { q--; } cnt = q - p + 1; *cnt_p = cnt; return 0; } int main(void) { char *str = " ds "; int cnt = 0; get_non_space_cnt(str, &cnt); printf("cnt = %d\n", cnt); return 0; }

    两头堵模型练习

    /* 有一个字符串开头或结尾含有n个空格 (” abcdefgdddd ”), 欲去掉前后空格,返回一个新字符串。 要求1:请自己定义一个接口(函数),并实现功 能; 要求2:编写测试用例。 int trimSpace(char *inbuf, char *outbuf); */

    字符串的反转与递归 字符串反转最简单的方法就是使用两头堵模型,利用两个指针分别指向头尾元素然后交换即可。 递归的方法有一定的技巧性,关键在于如何设置递归的跳出条件。通过画图能够很好的理解递归的过程。


    字符指针char *易错的地方

    对空字符串和非法字符串的判断

    void copy_str(char*from,char*to){ if(*from=='\0'||*to=='\0'){ //error!!!我们判断的是指针是否为空而不是其中的值是否为0; printf("funccopy_str()err\n"); return -1 ; } for(;*from!='\0';from++,to++){ *to=*from; } *to='\0'; }

    越界 char buff[3]="abc";

    指针的叠加会不断改变指针的方向 这也是我们为什么要在子函数里定义temp变量接收函数参数的原因,我们想保留函数初始状态,这样可操作性就会变大。

    char *getKeyByValue(char** keyvaluebuf,char* keybuf){ int i=0; char* a=(char*)malloc(50); for(;**keyvaluebuf!='\0';i++){ *a++=*(*keyvaluebuf)++; } free(a); //此时a指针指向字符'\0' }
    转载请注明原文地址: https://ju.6miu.com/read-1416.html

    最新回复(0)