虽然二者在效果上有些情况下等价,但指针与数组毕竟是不同的定义,字符串操作尽量用字符数组
#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字符串截取用法介绍