虽然二者在效果上有些情况下等价,但指针与数组毕竟是不同的定义,字符串操作尽量用字符数组
#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; }
#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
字符串拆分
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]); } }
#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; }
#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: 平 淡 !
关键是结果输出要用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]); } }
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! }
自定义字符串截取,有更新时会更改这个地方,即这个地方会同步修改优化的代码,是最新的代码
#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或直到字符数组结束了
截取字符到第一个换行符
#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:--
#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; }
#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字符串截取用法介绍