C 字符指针与字符数组

虽然二者在效果上有些情况下等价,但指针与数组毕竟是不同的定义,字符串操作尽量用字符数组

 
#include <stdio.h>
#include <string.h> 

int main(){
    char s1[] = "abc";
    char* s2 =  "abc";//将一个字符串的首地址赋予了字符指针变量s2
    char* s3 = "指针指向的地址与指针地址本身是两个不同的事物";
    char s4[]= "指针指向的地址与指针地址本身是两个不同的事物";

    printf("%s--%ld--%ld\n",s1,strlen(s1),sizeof(s1));//abc--3--4
    printf("%s--%ld--%ld\n",s2,strlen(s2),sizeof(s2));//abc--3--8
    printf("%s--%ld--%ld\n",s3,strlen(s3),sizeof(s3));//指针指向的地址与指针地址本身是两个不同的事物--66--8
    printf("%s--%ld--%ld\n",s4,strlen(s4),sizeof(s4));//指针指向的地址与指针地址本身是两个不同的事物--66--67
    return 0;
}
C 字符串包含另外一个字符/字符串的个数

 
#include <stdio.h> 

//一个字符串包含一个字符的个数
void strn(const char *p, const char chr)
{	
    int count = 0,i = 0;
    while(*(p+i))
    {
        if(p[i] == chr)
            ++count;
        ++i;
    }
    printf("count:%d\n",count);
}

void strn2(const char *p, const char chr)
{	
    int count = 0,i = 0;
    while(*p)
    {
        if(*p == chr)
            ++count;
        ++p;
    }
    printf("count:%d\n",count);
}

//一个字符串包含指定字符串的个数 
int strn3(const char *p, const char* ss)
{	
    int count = 0;
    while(*p)
    {
        int flag = 1;
        int i=0;
        while(*(ss+i)){
            if(p[i] != ss[i]){
                flag = 0;
                break;
            }
            ++i;
        }
        if(flag==1){
            ++count;
        }
        ++p;
    }
    return count;
}


int main()
{
    //%中是转义符,即%配合一个其他字符有一个意义,%%表示%符本身
    char tmp[] = "1:%s,2:%%com\r\n", chr = '%';
    strn(tmp, chr);   //count:3
    strn2(tmp, chr);  //count:3

    char fmt[] = "%c%sm%s";
    char ss[] = "%s";
    int count = strn3(fmt, ss);
    printf("count:%d\n",count);//count:2
}
                

 
$ gcc q.c 
$ ./a.out 
count:3
count:3
count:2

C strtok

字符串拆分

 
char *strtok(char *str, const char *delim);

- 第一个参数实际上只接受 字符数组 
- 第一个参数不是 NULL 时,strtok 函数查找 str 下一个标记,以 \0 结尾,strtok 函数会保存标记的地址
- 第一个参数为 NULl 时,strtok 函数取上次拆分字符串后剩余的字符串继续进行拆分操作,如果没有更多的字符则返回 NULL

第一个参数row必须是数组

 
#include <stdio.h>
#include <stdlib.h> 
#include <string.h> 

int main()
{
    // char* row = "Row: 2,62202232347824361435322,2023-10-12 11:18:12";
    char row[] = "Row: 2,62202232347824361435322,2023-10-12 11:18:12";
    printf("row size:%d\n",sizeof(row));
    char* val = strtok(row, ","); 
    int i=0;
    while (val != NULL) {
        i++;
        printf("col %d: %s\n", i,val);
        val = strtok(NULL, ",");
    }

    return 0;
}

strtok_r:线程安全,第二个参数row必须是数组

 
#include <stdio.h>
#include <stdlib.h> 
#include <string.h> 

void ss_arr(char** res,char* row){
    char* tmp=NULL;
    char* val = strtok_r(row, ",", &tmp); 
    int i=0;
    while (val != NULL) {
        res[i] = val;
        val = strtok_r(NULL, ",",&tmp);
        i++;
    }
}

//max_col_size:拆分成多少个元素
void deal(char* row, int max_col_size){
    char* res[max_col_size];
    ss_arr(res,row);

    int i;
    for(i=0;i<max_col_size;i++){
        printf("%s\n",res[i]);
    }
}

C 字符串比较

 
#include <stdio.h>
#include <string.h> 

int main(void)
{
    char* card1="623004134003432034";
    char* card2="623004134003432034";

    if(strcmp(card1,card2)==0){
        printf("相等\n");
    }else if (strcmp(card1,card2) < 0){
        printf("小于\n");
    }else if (strcmp(card1,card2) > 0){
        printf("大于\n");
    }
    return 0;
}

C 字符串数组复制

 
#include <stdio.h> 
#include <string.h> 
    
void copyStringArray(char dest[], const char src[], int len) {  
    int i;  
    for (i = 0; i < len; i++) {  
        dest[i] = src[i];  
    }  
    dest[len] = '\0'; // 确保字符串以null结尾  
}  
    
int main() {  
    char src[][20] = {"平", "淡", "!"}; // 每个元素都是一个字符串  
    char dest[3][20]; // 目标数组的每个元素也是一个字符串  
    int len = sizeof(src) / sizeof(src[0]); // 计算原数组中元素的数量  
    int i;  
    for (i = 0; i < len; i++) {  
        copyStringArray(dest[i], src[i], strlen(src[i])); // 复制每个字符串元素  
    }  
    printf("Copied strings:\n");  
    for (i = 0; i < len; i++) {  
        printf("%s\n", dest[i]); // 打印复制后的字符串  
    }  
    return 0;  
}

 
$ ./a.out 
Copied strings:
平
淡
!
C 字符串拆分

关键是结果输出要用2维字符数组,要先固定第2维的长度

 
#include <stdio.h>
#include <stdlib.h> 
#include <string.h> 

//先将数组的长度固定下来,MAX_LEN的意思是涉及的字符长最长MAX_LEN,
//如果比这个还长,就需要定义一个更大的值 
#define MAX_LEN 30

//row必须是数组
//res:字符串数组
void ss_arr(char** res, char* row){
    char* tmp=NULL;
    char* val = strtok_r(row, ",", &tmp); 
    int i=0;
    while (val != NULL) {
        res[i] = val;
        val = strtok_r(NULL, ",",&tmp);
        i++;
    }
}

//一个字符串包含指定字符串的个数 
int strn3(const char *p, const char* ss)
{	
    int count = 0;
    while(*p)
    {
        int flag = 1;
        int i=0;
        while(*(ss+i)){
            if(p[i] != ss[i]){
                flag = 0;
                break;
            }
            ++i;
        }
        if(flag==1){
            ++count;
        }
        ++p;
    }
    return count;
}

void copyStringArray(char dest[], const char src[], int len) {  
    int i;  
    for (i = 0; i < len; i++) {  
        dest[i] = src[i];  
    }  
    dest[len] = '\0'; // 确保字符串以null结尾  
}  

//方法返回了实际长度,利用这个输出直接元素个数
int str_split(char* source_str, char* split, char dest[][MAX_LEN]){
    //将字符串转为字符数组
    int tmp_len = strlen(source_str)+1;
    char src[tmp_len];
    strcpy(src,source_str);

    //统计最终的字符串个数,并转为字符串数组
    int max_col_num = strn3(src,split)+1;
    char* tmp_arr[max_col_num]; // 每个元素都是一个字符串  
    ss_arr(tmp_arr,src);

    //将结果传出去
    int i;  
    for (i = 0; i < max_col_num; i++) {  
        copyStringArray(dest[i], tmp_arr[i], strlen(tmp_arr[i])); // 复制每个字符串元素  
    }
    return max_col_num;
}

int main(){
    char* source_str = "49,13,10,-28,-72,-86,13,10,-28,-70,-70";

    //最终拆分的数组元素个数不会超过字符串本身的字符个数
    //第1维指有多少个字符串,MAX_LEN第每个字符串有多少个字符,
    //数组的空间分配必须是连接的内存,一次分配太多不用的空白内存也不好,超过MAX_LEN时可再指定更长的长度
    char res_str[strlen(source_str)][MAX_LEN];

    //方法返回了实际长度,利用这个输出直接元素个数
    int read_size = str_split(source_str,",",res_str);
    int i;
    for(i=0;i < read_size;i++){
        printf("%d=%s\n",i,res_str[i]);
    }
    return 0;
}

 
$ gcc g.c 
$ ./a.out 
0=49
1=13
2=10
3=-28
4=-72
5=-86
6=13
7=10
8=-28
9=-70
10=-70
    

举例二

 
#include <stdio.h>
#include <stdlib.h> 
#include <string.h> 

//row必须是数组
void ss_arr(char** res,char* row){
    char* tmp=NULL;
    char* val = strtok_r(row, ",", &tmp); 
    int i=0;
    while (val != NULL) {
        res[i] = val;
        val = strtok_r(NULL, ",",&tmp);
        i++;
    }
}

//一个字符串包含指定字符串的个数 
int strn3(const char *p, const char* ss)
{	
    int count = 0;
    while(*p)
    {
        int flag = 1;
        int i=0;
        while(*(ss+i)){
            if(p[i] != ss[i]){
                flag = 0;
                break;
            }
            ++i;
        }
        if(flag==1){
            ++count;
        }
        ++p;
    }
    return count;
}

 
void test(){
    char* txid = "2222222";
    char* card_num = "622848002023124234";
    char* txids = "2222221,2222222,2222223";
    char* times = "2023-01-01 11:11:11,2023-01-02 11:11:11,2023-01-03 11:11:11";


    int txids_len = strlen(txids)+1;
    int times_len = strlen(txids)+1;

    char txids_arr[txids_len];
    char times_arr[times_len];

    strcpy(txids_arr,txids);
    char split[] = ",";
    int max_col_num = strn3(txids_arr,split)+1;
    printf("col num:%d\n",max_col_num);

    //字符串拆分
    char* txid_arr[max_col_num];
    ss_arr(txid_arr,txids_arr);

    int read_size = max_col_num;
    printf("read_size:%d\n",read_size);
    int i;
    for(i=0;i<max_col_num;i++){
        printf("txid=%s\n",txid_arr[i]);
    }

}

C 字符串拼接

strcat

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h> 

void scat(char* s1,char* s2){
    int s_size = strlen(s1) + strlen(s2)+1;
    char tmp[s_size];
    strcpy(tmp, s1);  
    strcat(tmp, s2);  
    printf("%s\n", tmp);
}

int main() {
    char *first = "aa";
    char *last = "bb";
    scat(first,last);
    return 0;
}

sprintf

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h> 

void sfmt(char* s1, char* s2){
    int s_size = strlen(s1) + strlen(s2)+1;
    char tmp[s_size];
    sprintf(tmp,"%s%s",s1,s2);
    printf("-%s-\n", tmp);
}

int main() {
    char *first = "aa";
    char *last = "bb";
    sfmt(first,last);
    return 0;
}

$ gcc f.c 
$ ./a.out 
-aabb-

sprintf + 指针传址 : 不用写长度,但需要多写个free

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h> 


void sfmt(char** res, char* s1, char* s2){
    int s_size = strlen(s1) + strlen(s2)+1;
    *res = (char*)malloc(s_size*sizeof(char));
    sprintf(*res,"%s%s",s1,s2);
}

int main() {
    char *first = "aa";
    char *last = "bb";

    char* res;
    sfmt(&res,first,last);
    printf("-%s-\n", res);
    free(res);
    return 0;
}

$ gcc f.c 
$ ./a.out 
-aabb-
        

数字与字符串拼接

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void ifmt(int i, char** res){
    char tmp[100];
    sprintf(tmp,"%d",i);
    *res = (char*)malloc(strlen(tmp)*sizeof(char)+1);
    sprintf(*res,"%s",tmp);
}

void dfmt(double i, char** res){
    char tmp[100];
    sprintf(tmp,"%lf",i);
    *res = (char*)malloc(strlen(tmp)*sizeof(char)+1);
    sprintf(*res,"%s",tmp);
}

先将数字转字符串,太麻烦
还是指定一下长度吧,%s%d随意组合 

C 字符串拼接-自定义 :利用C语言可变参数,自定义一个字符串拼接函数,另类模仿sprintf...

 
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//一个字符串包含指定字符串的个数 
int strn3(const char *p, const char* ss)
{	
    int count = 0;
    while(*p)
    {
        int flag = 1;
        int i=0;
        while(*(ss+i)){
            if(p[i] != ss[i]){
                flag = 0;
                break;
            }
            ++i;
        }
        if(flag==1){
            ++count;
        }
        ++p;
    }
    return count;
}



//字符串拼接,最多支持6个
void sfmt3(char** res, char* fmt, int param_count,... ){
    int param_count2 = strn3(fmt, "%s");
    if(param_count2!=param_count){
        printf("输入参数个数与%%的个数不匹配,%%个数:%d,输入参数个数:%d",param_count2,param_count);
        return;
    }

    va_list param_list;
    va_start(param_list, param_count);
    
    int idx;
    char *params[param_count+1];
    // printf("---------------\n");
    int s_size;
    for(idx = 1; idx <= param_count; ++idx){
        params[idx] = va_arg(param_list, char*);
        // printf("第 %d 个参数: %s\n", idx, params[idx]);
        s_size = s_size + strlen(params[idx]);
    }
    // sprintf(*res,"%s%s","aaa","bb");
    // printf("---------------\n");
    va_end(param_list);

    s_size++;
    *res = (char*)malloc(s_size*sizeof(char));
    // printf("size:%d\n",s_size);


    if(param_count==1){
        sprintf(*res,fmt,params[1]);
    }else if(param_count==2){
        sprintf(*res,fmt,params[1],params[2]);
    }else if(param_count==3){
        sprintf(*res,fmt,params[1],params[2],params[3]);
    }else if(param_count==4){
        sprintf(*res,fmt,params[1],params[2],params[3],params[4]);
    }else if(param_count==5){
        sprintf(*res,fmt,params[1],params[2],params[3],params[4],params[5]);
    }else if(param_count==6){
        sprintf(*res,fmt,params[1],params[2],params[3],params[4],params[5],params[6]);
    }
}



int main(void)
{
    // 超出param_count的被忽略 
    char* res;
    sfmt3(&res,"%s%s\n",2,"wa ","ka ka");
    printf("res:%s\n",res); //res:wa ka ka

    sfmt3(&res,"%s%s%s\n",3,"wa ","ka ka","!");
    printf("res:%s\n",res);//res:wa ka ka!

}
                
C 字符串截取

自定义字符串截取,有更新时会更改这个地方,即这个地方会同步修改优化的代码,是最新的代码

 
#include <stdio.h> 
#include <stdlib.h>
#include <string.h>


//start:索引位置
//count:取多少个字符
void str_get(char** res, char* s1,int start,int count){
    *res = (char*)calloc((count+1),sizeof(char));
    int s_size = strlen(s1);
    int i;
    if(count>s_size){
        count = s_size;
    }
    int end = start+count;
    // printf("start:%d,end:%d\n",start,end);

    int index=0;
    for(i=start;i<end;i++){
        (*res)[index++] = s1[i];
    }
    (*res)[index] = '\0'; // 确保字符串以null结尾  
}

int main() {
    char s1[20] = "abc123";
    char* res=NULL;
    str_get(&res,s1,1,2);
    printf("--%s--\n",res);//--bc--
    free(res);

    char* tim = "2023-01-01 11:11:11";
    str_get(&res,tim,0,19);
    printf("--%s--\n",res);//--2023-01-01 11:11:11--
    free(res);
    return 0;
}

 
输入字符串格式支持 char s1[20],char* tim 两种格式
输出字符串,因为不确定具体会截取多少个字符,所以统一使用char*类型 
特征注意,因为分配了堆空间,所以最后需要free()一下  

strcpy:[开始指针,结尾]

 
#include <stdio.h>
#include <string.h>

int main() {
    char s1[20] = "abc123";
    char s2[10];
    strcpy(s2, &s1[1]);
    printf("sub string: -%s-\n", s2); //sub string: -bc123-
    return 0;
}

strncpy:从开始指针起取n个字符,包含开始位置

 
#include <stdio.h>
#include <string.h> 

int main() {
    char s1[20] = "abc1234567";
    char s2[10];
    strncpy(s2, &s1[1], 2);
    printf("sub string: -%s-\n", s2); //sub string: -bc-
    return 0;
}

strncpy从一个centos7迁移到另外一个linux上时,截取出来的字符多出来一些字符,于是写了下面自定义截取方法

 
#include <stdio.h>
#include <stdlib.h> 
#include <string.h> 

void str_get(char** res, char* s1,int start,int count){
    *res = (char*)malloc((count+1)*sizeof(char));
    int s_size = strlen(s1);
    int i;
    if(count>s_size){
        count = s_size;
    }
    int end = start+count;
    int index=0;
    for(i=start;i<end;i++){
        (*res)[index++] = s1[i];
    }
}

int main() {
    char s1[20] = "abc123";
    char* res;
    str_get(&res,s1,1,2);
    printf("--%s--\n",res);
    free(res);

    char* tim = "2023-01-01 11:11:11";
    str_get(&res,tim,0,19);
    printf("--%s--\n",res);
    free(res);
    return 0;
}


$ gcc sp.c 
$ ./a.out 
--bc--
--2023-01-01 11:11:11--

优化说明:int index;改为int index=0;

 
原来的版本是int index;
结果换了系统再运行时发生了 
Segmentation fault (core dumped)
改为int index=0;就好了

总结

 
C中最好为变量初始值,不要使用默认值,尽量他们相等,容易发生
Segmentation fault (core dumped)

优化2:初始值赋予0值

 
#include <stdio.h> 
#include <stdlib.h>
#include <string.h>


//start:索引位置
//count:取多少个字符
void str_get(char** res, char* s1,int start,int count){
    *res = (char*)calloc((count+1),sizeof(char));
    int s_size = strlen(s1);
    int i;
    if(count>s_size){
        count = s_size;
    }
    int end = start+count;
    // printf("start:%d,end:%d\n",start,end);

    int index=0;
    for(i=start;i<end;i++){
        (*res)[index++] = s1[i];
    }
}

int main() {
    char s1[20] = "abc123";
    char* res=NULL;
    str_get(&res,s1,1,2);
    printf("--%s--\n",res);//--bc--
    free(res);

    char* tim = "2023-01-01 11:11:11";
    str_get(&res,tim,0,19);
    printf("--%s--\n",res);//--2023-01-01 11:11:11--
    free(res);
    return 0;
}

 
字符数组初始化值若不为0,则容易出现乱码,
本来该遇0结束的,结果那个位置不是0,它就可能继续往后读取找0或直到字符数组结束了

C 去除换行符

截取字符到第一个换行符

 
#include <stdio.h> 
#include <string.h> 

void toFirstEnterFlag(char* str) {
    int len = strlen(str); // 字符串长度
    for (int i = 0; i < len; i++) {
        if (str[i] == '\n' || str[i] == '\r') { // 如果是回车或换行符
            str[i] = '\0'; // 替换为空字符
            break; // 结束循环,只移除第一个出现的回车或换行符
        }
    }
}

int main() {
    char str[300]="能量既不会凭空产生,也不会凭空消失,\n它只会从一种形式转化为另一种形式,或者从一个物体转移到其它物体";
    toFirstEnterFlag(str);
    printf("结果1:%s\n", str);   //结果1:能量既不会凭空产生,也不会凭空消失,

    char str2[300]="\n";
    toFirstEnterFlag(str2);
    printf("结果2:-%s-\n", str2);//结果2:--

    return 0;
}
    

 
$ gcc d.c 
$ ./a.out 
结果1:能量既不会凭空产生,也不会凭空消失,
结果2:--
    
C 删除最后一个字符

 
#include <stdio.h>
#include <string.h> 

//删除最后一个字节,如果是汉字则会乱码
void delLastFlag(char* str) {
    int len = strlen(str)-1; // 字符串长度
    str[len] = '\0';
}

int main() {
    char str[300]="不会凭空消失,";
    printf("字节个数:%d\n",strlen(str)); //字节个数:21
    delLastFlag(str);
    printf("结果1:%s\n", str);   //结果1:不会凭空消失�

    char str2[300]="它只会从一种形式转化为另一种形式,或者从一个物体转移到其它物体\n";
    delLastFlag(str2);
    printf("结果2:%s\n", str2);   //结果2:它只会从一种形式转化为另一种形式,或者从一个物体转移到其它物体

    return 0;
}

C 删除最后一个空白

 
#include <stdio.h> 
#include <string.h> 

//删除最后一个字节,如果是汉字则会乱码
void delLastSpace(char* str) {
    int len = strlen(str)-1; // 字符串长度
    if (str[len] == '\n' || str[len] == '\r'|| str[len] == ' ') { // 如果是回车或换行符或空白
            str[len] = '\0'; // 替换为空字符
    }
}

int main() {
    char str[300]="不会凭空消失 ";
    printf("字节个数:%d\n",strlen(str)); //字节个数:19
    delLastSpace(str);
    printf("结果1:%s\n", str);   //结果1:不会凭空消失

    char str2[300]="它只会从一种形式转化为另一种形式,";
    delLastSpace(str2);
    printf("结果2:%s\n", str2);   //结果2:它只会从一种形式转化为另一种形式,

    char str3[300]="或者从一个物体转移到其它物体\n";
    delLastSpace(str3);
    printf("结果3:%s\n", str3);   //结果3:或者从一个物体转移到其它物体


    return 0;
}

参考文章
    C字符串截取用法介绍