全屋定制营销,网站seo优化课程,泰安网络推广公司平台,高端网站开发怎么选一、引言#xff1a;字符串在C语言中的独特地位
在C语言中#xff0c;字符串有着特殊的地位。它不像其他语言那样有专门的字符串类型#xff0c;而是以字符数组的形式存在#xff0c;并且以空字符’\0’作为结束标志。这种设计使得字符串既简单又灵活#xff0c;但也带来了…一、引言字符串在C语言中的独特地位在C语言中字符串有着特殊的地位。它不像其他语言那样有专门的字符串类型而是以字符数组的形式存在并且以空字符’\0’作为结束标志。这种设计使得字符串既简单又灵活但也带来了一些复杂性。想象一下字符串就像一列火车· 每个字符是车厢· 字符串结束符’\0’是车尾标志· 指针就是列车时刻表告诉我们火车在哪里charstr[]Hello;// 这列火车有5节载客车厢和1节车尾标志车厢// 内存布局: H e l l o \0二、C语言字符串的本质2.1 字符串的三种表示方法C语言中表示字符串有三种主要方式#includestdio.hvoidstring_representations(){printf( 字符串的三种表示方法 \n\n);// 方法1字符数组栈上分配charstr1[]Hello World;// 自动添加\0printf(方法1 - 字符数组:\n);printf( 声明: char str1[] \Hello World\;\n);printf( 内容: %s\n,str1);printf( 大小: sizeof(str1) %zu 字节\n,sizeof(str1));printf( 地址: %p\n,(void*)str1);// 方法2字符指针指向字符串字面量char*str2Hello World;// 指向常量区printf(\n方法2 - 字符指针:\n);printf( 声明: char *str2 \Hello World\;\n);printf( 内容: %s\n,str2);printf( 大小: sizeof(str2) %zu 字节指针大小\n,sizeof(str2));printf( 地址: %p\n,(void*)str2);// 方法3动态分配的字符串堆上分配char*str3(char*)malloc(12*sizeof(char));// 为Hello World分配空间if(str3!NULL){strcpy(str3,Hello World);printf(\n方法3 - 动态分配:\n);printf( 声明: char *str3 malloc(12); strcpy(str3, \Hello World\);\n);printf( 内容: %s\n,str3);printf( 大小: 动态分配12字节\n);printf( 地址: %p\n,(void*)str3);free(str3);}printf(\n内存区域对比:\n);printf( str1: 栈内存可修改\n);printf( str2: 常量区通常不可修改\n);printf( str3: 堆内存可修改需手动释放\n);}2.2 字符串结束符’\0’的重要性‘\0’ASCII值为0是C语言字符串的终结者没有它字符串操作函数就不知道在哪里停止#includestdio.hvoidnull_terminator_demo(){printf( 字符串结束符的重要性 \n\n);// 正确的字符串自动包含\0charcorrect[]Hello;printf(正确字符串: \%s\\n,correct);printf(长度: %zu (使用strlen)\n,strlen(correct));printf(内存内容: );for(inti0;istrlen(correct);i){// 注意包含\0if(correct[i]\0){printf(\\0 );}else{printf(%c ,correct[i]);}}printf(\n\n);// 错误的字符串忘记\0charwrong[5]{H,e,l,l,o};// 没有\0printf(错误字符串: 没有\\0的字符数组\n);printf(打印结果: %s (可能包含垃圾数据)\n,wrong);// 演示strlen在没有\0时的行为printf(\n演示字符串函数的行为:\n);chartest1[6]{H,e,l,l,o,\0};chartest2[5]{H,e,l,l,o};// 没有\0printf(test1 (有\\0): \%s\, strlen %zu\n,test1,strlen(test1));printf(test2 (无\\0): );// 危险strlen会一直读取直到遇到\0size_tlen0;while(test2[len]!\0len100){// 防止无限循环len;}printf(strlen可能返回 %zu 或导致问题\n,len);printf(\n经验法则: 总是确保字符串以\\0结束\n);}三、字符指针与字符串操作3.1 声明和初始化字符串指针字符串指针的声明和初始化有多种方式各有特点#includestdio.h#includestdlib.h#includestring.hvoidstring_pointer_declaration(){printf( 字符串指针的声明与初始化 \n\n);// 1. 指向字符串字面量常量区char*ptr1Immutable String;printf(1. 指向字面量:\n);printf( ptr1 \%s\\n,ptr1);printf( 注意: 不能修改内容\n);// ptr1[0] X; // 错误运行时错误试图修改常量区// 2. 指向字符数组栈内存chararr[]Mutable String;char*ptr2arr;// 指向栈上的数组printf(\n2. 指向字符数组:\n);printf( 原始: %s\n,ptr2);ptr2[0]X;// 可以修改printf( 修改后: %s\n,ptr2);// 3. 动态分配堆内存char*ptr3(char*)malloc(20*sizeof(char));if(ptr3){strcpy(ptr3,Dynamic String);printf(\n3. 动态分配:\n);printf( 初始: %s\n,ptr3);ptr3[0]D;// 可以修改printf( 修改后: %s\n,ptr3);free(ptr3);}// 4. 指向字符串常量数组constchar*ptr4This is constant;printf(\n4. 使用const保护:\n);printf( ptr4 \%s\\n,ptr4);printf( 明确表示不可修改更安全\n);// ptr4[0] X; // 编译时错误而不是运行时错误printf(\n总结:\n);printf( - 字面量: 常量区不可修改\n);printf( - 字符数组: 栈内存可修改\n);printf( - 动态分配: 堆内存可修改需释放\n);printf( - const修饰: 明确不可修改更安全\n);}3.2 字符串指针的运算字符串指针支持指针运算这使得遍历字符串变得非常方便#includestdio.hvoidstring_pointer_arithmetic(){printf( 字符串指针运算 \n\n);charstr[]C Programming;char*ptrstr;// 指向字符串开头printf(原始字符串: \%s\\n,str);printf(指针初始位置: ptr指向 %c\n,*ptr);printf(\n1. 指针自增遍历字符串:\n);printf( 遍历结果: );while(*ptr!\0){printf(%c,*ptr);ptr;// 移动到下一个字符}printf(\n 现在ptr指向: \\0\n);// 重新指向开头ptrstr;printf(\n2. 指针运算访问特定字符:\n);printf( ptr 0 %c (str[0])\n,*(ptr0));printf( ptr 2 %c (str[2])\n,*(ptr2));printf( ptr 5 %c (str[5])\n,*(ptr5));printf(\n3. 计算字符串长度手动实现:\n);char*startstr;char*endstr;// 找到字符串结尾while(*end!\0){end;}printf( 字符串长度: %ld (指针差: end - start)\n,end-start);printf(\n4. 反向遍历字符串:\n);printf( 反向输出: );char*reverse_ptrend-1;// 指向最后一个字符不是\0while(reverse_ptrstart){printf(%c,*reverse_ptr);reverse_ptr--;}printf(\n);printf(\n5. 指针比较:\n);char*p1str;char*p2str5;printf( p1 %p, 指向 %c\n,(void*)p1,*p1);printf( p2 %p, 指向 %c\n,(void*)p2,*p2);if(p1p2){printf( p1 在 p2 前面\n);}if(p2p1){printf( p2 在 p1 后面\n);}}四、字符串处理函数详解4.1 标准库字符串函数C标准库提供了一系列字符串处理函数它们都定义在string.h中#includestdio.h#includestring.h#includestdlib.hvoidstandard_string_functions(){printf( 标准库字符串函数 \n\n);// 1. strlen - 字符串长度不包括\0char*str1Hello World;printf(1. strlen - 字符串长度:\n);printf( \%s\ 的长度是 %zu\n,str1,strlen(str1));// 2. strcpy - 字符串复制chardest1[20];strcpy(dest1,Copy Me);printf(\n2. strcpy - 字符串复制:\n);printf( 复制后: %s\n,dest1);// 3. strncpy - 安全字符串复制指定最大长度chardest2[10];strncpy(dest2,This is too long,sizeof(dest2)-1);dest2[sizeof(dest2)-1]\0;// 确保以\0结束printf(\n3. strncpy - 安全复制:\n);printf( 安全复制: %s\n,dest2);// 4. strcat - 字符串连接chardest3[30]Hello;strcat(dest3, World);printf(\n4. strcat - 字符串连接:\n);printf( 连接后: %s\n,dest3);// 5. strcmp - 字符串比较char*str2apple;char*str3banana;intresultstrcmp(str2,str3);printf(\n5. strcmp - 字符串比较:\n);printf( \%s\ 与 \%s\ 比较: ,str2,str3);if(result0){printf(小于\n);}elseif(result0){printf(大于\n);}else{printf(等于\n);}// 6. strchr - 查找字符char*str4Find the letter e;char*foundstrchr(str4,e);printf(\n6. strchr - 查找字符:\n);if(found){printf( 在 \%s\ 中找到 e位置: %s\n,str4,found);}else{printf( 未找到\n);}// 7. strstr - 查找子串char*str5C Programming Language;char*substrstrstr(str5,Program);printf(\n7. strstr - 查找子串:\n);if(substr){printf( 在 \%s\ 中找到 \Program\位置: %s\n,str5,substr);}else{printf( 未找到\n);}// 8. strtok - 字符串分割charstr6[]apple,banana,cherry,date;printf(\n8. strtok - 字符串分割:\n);printf( 分割 \%s\:\n,str6);char*tokenstrtok(str6,,);while(token!NULL){printf( - %s\n,token);tokenstrtok(NULL,,);}}4.2 手动实现字符串函数理解标准库函数的最好方法是手动实现它们#includestdio.h#includeassert.h// 1. 手动实现strlensize_tmy_strlen(constchar*str){constchar*pstr;while(*p!\0){p;}returnp-str;// 指针相减得到字符数}// 2. 手动实现strcpychar*my_strcpy(char*dest,constchar*src){char*ddest;constchar*ssrc;while((*d*s)!\0){// 空循环复制在条件中进行}returndest;}// 3. 手动实现strcatchar*my_strcat(char*dest,constchar*src){char*ddest;// 找到dest的结尾while(*d!\0){d;}// 追加srcmy_strcpy(d,src);returndest;}// 4. 手动实现strcmpintmy_strcmp(constchar*str1,constchar*str2){while(*str1(*str1*str2)){str1;str2;}return*(unsignedchar*)str1-*(unsignedchar*)str2;}// 5. 手动实现strchrchar*my_strchr(constchar*str,intch){while(*str!\0){if(*strch){return(char*)str;// 找到返回指针}str;}if(ch\0){// 特殊处理查找\0return(char*)str;}returnNULL;// 未找到}voidimplement_string_functions(){printf( 手动实现字符串函数 \n\n);// 测试my_strlenprintf(1. my_strlen 测试:\n);char*test_strHello;printf( \%s\ 长度: %zu\n,test_str,my_strlen(test_str));// 测试my_strcpyprintf(\n2. my_strcpy 测试:\n);chardest1[20];my_strcpy(dest1,Copied String);printf( 复制后: %s\n,dest1);// 测试my_strcatprintf(\n3. my_strcat 测试:\n);chardest2[30]Hello;my_strcat(dest2, World);printf( 连接后: %s\n,dest2);// 测试my_strcmpprintf(\n4. my_strcmp 测试:\n);printf( \apple\ vs \banana\: %d\n,my_strcmp(apple,banana));printf( \apple\ vs \apple\: %d\n,my_strcmp(apple,apple));printf( \banana\ vs \apple\: %d\n,my_strcmp(banana,apple));// 测试my_strchrprintf(\n5. my_strchr 测试:\n);char*strFind the letter e;char*foundmy_strchr(str,e);if(found){printf( 在 \%s\ 中找到 e从位置: %s\n,str,found);}// 验证与标准库的一致性printf(\n6. 验证与标准库的一致性:\n);chartest1[]Test String;chartest2[]Another String;assert(my_strlen(test1)strlen(test1));charcopy1[20],copy2[20];my_strcpy(copy1,test1);strcpy(copy2,test1);assert(strcmp(copy1,copy2)0);printf( 所有测试通过\n);}五、字符串数组与指针数组5.1 字符串数组的两种实现方式处理多个字符串时有两种主要方式#includestdio.h#includestring.hvoidstring_arrays(){printf( 字符串数组的两种方式 \n\n);// 方式1二维字符数组矩形数组printf(方式1: 二维字符数组\n);charnames1[4][20]{// 4个字符串每个最多19字符\0Alice,Bob,Charlie,David};printf( 内存布局: 连续存储每行固定20字节\n);for(inti0;i4;i){printf( names1[%d] \%s\ (地址: %p)\n,i,names1[i],(void*)names1[i]);}printf( 总内存: %zu 字节\n,sizeof(names1));// 可以修改内容names1[0][0]A;// 正确printf( 修改后: %s\n\n,names1[0]);// 方式2字符指针数组printf(方式2: 字符指针数组\n);char*names2[]{// 4个指针指向字符串字面量Alice,Bob,Charlie,David};printf( 内存布局: 指针数组字符串字面量\n);for(inti0;i4;i){printf( names2[%d] \%s\ (指针地址: %p, 字符串地址: %p)\n,i,names2[i],(void*)names2[i],(void*)names2[i]);}printf( 指针数组大小: %zu 字节\n,sizeof(names2));// 注意不能修改字符串字面量的内容// names2[0][0] A; // 错误运行时错误printf( 注意: 字符串字面量通常不可修改\n\n);// 方式3动态分配的指针数组printf(方式3: 动态分配的字符串数组\n);char**names3malloc(4*sizeof(char*));// 分配指针数组if(names3){for(inti0;i4;i){names3[i]malloc(20*sizeof(char));// 为每个字符串分配空间sprintf(names3[i],Dynamic %d,i1);// 创建字符串}for(inti0;i4;i){printf( names3[%d] \%s\\n,i,names3[i]);}// 可以修改names3[0][0]X;printf( 修改后: %s\n,names3[0]);// 释放内存for(inti0;i4;i){free(names3[i]);}free(names3);}printf(\n对比总结:\n);printf( 二维数组: 内存连续固定大小可修改\n);printf( 指针数组: 内存不连续字符串长度可变字面量不可修改\n);printf( 动态分配: 最灵活但需要管理内存\n);}5.2 命令行参数处理main函数的参数就是字符串指针数组的典型应用#includestdio.h// argc: 参数个数// argv: 参数向量字符串指针数组intmain(intargc,char*argv[]){printf( 命令行参数处理 \n\n);printf(程序名: %s\n,argv[0]);printf(参数个数: %d\n,argc-1);if(argc1){printf(参数列表:\n);for(inti1;iargc;i){printf( argv[%d] \%s\\n,i,argv[i]);}// 解析参数printf(\n参数解析示例:\n);for(inti1;iargc;i){if(argv[i][0]-){// 选项printf( 选项: %s\n,argv[i]);// 进一步解析选项for(intj1;argv[i][j]!\0;j){printf( 子选项: -%c\n,argv[i][j]);}}else{// 参数printf( 参数: %s\n,argv[i]);}}}else{printf(没有额外参数\n);printf(用法: %s [选项] [参数]\n,argv[0]);}return0;}/* 编译后运行示例: $ ./program -abc input.txt output.txt 输出: 命令行参数处理 程序名: ./program 参数个数: 3 参数列表: argv[1] -abc argv[2] input.txt argv[3] output.txt 参数解析示例: 选项: -abc 子选项: -a 子选项: -b 子选项: -c 参数: input.txt 参数: output.txt */六、字符串与内存管理6.1 常见的内存错误字符串操作是内存错误的常见来源#includestdio.h#includestdlib.h#includestring.hvoidcommon_string_errors(){printf( 字符串常见内存错误 \n\n);printf(错误1: 缓冲区溢出\n);charbuffer[10];// strcpy(buffer, This string is too long); // 溢出// 正确做法:strncpy(buffer,This string is too long,sizeof(buffer)-1);buffer[sizeof(buffer)-1]\0;printf( 安全复制: %s\n,buffer);printf(\n错误2: 忘记分配内存\n);char*ptr;// strcpy(ptr, Hello); // 错误ptr未初始化// 正确做法:ptrmalloc(10*sizeof(char));if(ptr){strcpy(ptr,Hello);printf( 正确分配: %s\n,ptr);free(ptr);}printf(\n错误3: 修改字符串字面量\n);char*literalImmutable;// literal[0] X; // 运行时错误// 正确做法: 使用字符数组或constcharmutable[]Mutable;mutable[0]X;// 正确printf( 可修改字符串: %s\n,mutable);printf(\n错误4: 内存泄漏\n);char*leakymalloc(100*sizeof(char));strcpy(leaky,This will leak);// 忘记 free(leaky); // 内存泄漏// 正确做法:free(leaky);leakyNULL;// 避免悬空指针printf( 已正确释放内存\n);printf(\n错误5: 使用已释放的内存\n);char*freedmalloc(20*sizeof(char));strcpy(freed,Some text);free(freed);// printf(%s\n, freed); // 错误使用已释放的内存freedNULL;// 安全做法printf( 已设置指针为NULL\n);printf(\n安全编程建议:\n);printf( 1. 始终检查边界\n);printf( 2. 使用strncpy而不是strcpy\n);printf( 3. 记得释放动态内存\n);printf( 4. 使用const保护不可修改的字符串\n);printf( 5. 释放后立即设置指针为NULL\n);}6.2 安全的字符串处理函数C11标准引入了安全版本的字符串函数#define__STDC_WANT_LIB_EXT1__1// 启用安全函数#includestdio.h#includestring.hvoidsafe_string_functions(){printf( 安全的字符串函数C11 \n\n);chardest[10];charsrc[]This is a very long string that might overflow;printf(传统方法危险:\n);// strcpy(dest, src); // 缓冲区溢出printf(安全方法1: strncpy\n);strncpy(dest,src,sizeof(dest)-1);dest[sizeof(dest)-1]\0;printf( 结果: %s\n,dest);#ifdef__STDC_LIB_EXT1__printf(\n安全方法2: strcpy_sC11安全函数\n);// strcpy_s(dest, sizeof(dest), src); // 运行时检查// printf( 如果溢出会返回错误\n);#elseprintf(\n注意: 此编译器不支持C11安全函数\n);#endifprintf(\n自己实现的安全函数:\n);// 安全的字符串复制char*safe_strcpy(char*dest,size_tdest_size,constchar*src){if(destNULL||srcNULL||dest_size0){returnNULL;}size_ti;for(i0;idest_size-1src[i]!\0;i){dest[i]src[i];}dest[i]\0;returndest;}charbuffer[10];safe_strcpy(buffer,sizeof(buffer),Hello World);printf( 安全复制到大小为10的缓冲区: %s\n,buffer);// 安全的字符串连接char*safe_strcat(char*dest,size_tdest_size,constchar*src){if(destNULL||srcNULL||dest_size0){returnNULL;}// 找到dest的结尾size_tdest_len0;while(dest_lendest_sizedest[dest_len]!\0){dest_len;}// 计算剩余空间size_tremainingdest_size-dest_len;// 追加src不超过剩余空间-1留给\0size_ti;for(i0;iremaining-1src[i]!\0;i){dest[dest_leni]src[i];}dest[dest_leni]\0;returndest;}charbuf[15]Hello;safe_strcat(buf,sizeof(buf), World!);printf( 安全连接: %s\n,buf);}七、字符串与文件操作7.1 文件中的字符串处理#includestdio.h#includestdlib.h#includestring.hvoidstring_file_operations(){printf( 字符串与文件操作 \n\n);// 1. 写入字符串到文件printf(1. 写入字符串到文件:\n);FILE*filefopen(test.txt,w);if(file){char*lines[]{Hello World\n,This is a test\n,String file operations\n};for(inti0;i3;i){fputs(lines[i],file);// 写入字符串}fclose(file);printf( 已写入3行到test.txt\n);}// 2. 从文件读取字符串printf(\n2. 从文件读取字符串:\n);filefopen(test.txt,r);if(file){charbuffer[100];intline_num1;printf( 文件内容:\n);while(fgets(buffer,sizeof(buffer),file)!NULL){printf( 行 %d: %s,line_num,buffer);// 处理每行字符串// 去除换行符size_tlenstrlen(buffer);if(len0buffer[len-1]\n){buffer[len-1]\0;}printf( 处理后的长度: %zu\n,strlen(buffer));}fclose(file);}// 3. 格式化字符串写入printf(\n3. 格式化字符串写入:\n);filefopen(data.txt,w);if(file){charname[]Alice;intage25;floatscore95.5;fprintf(file,Name: %s\n,name);fprintf(file,Age: %d\n,age);fprintf(file,Score: %.2f\n,score);fclose(file);printf( 已格式化写入到data.txt\n);}// 4. 读取CSV文件逗号分隔值printf(\n4. 读取CSV文件示例:\n);filefopen(data.csv,w);if(file){// 写入CSV数据fprintf(file,Name,Age,Score\n);fprintf(file,Alice,25,95.5\n);fprintf(file,Bob,30,88.0\n);fprintf(file,Charlie,22,92.5\n);// 回到文件开头rewind(file);// 读取并解析CSVprintf( 解析CSV数据:\n);charline[100];fgets(line,sizeof(line),file);// 跳过标题行while(fgets(line,sizeof(line),file)!NULL){// 去除换行符line[strcspn(line,\n)]\0;// 使用strtok分割char*namestrtok(line,,);char*age_strstrtok(NULL,,);char*score_strstrtok(NULL,,);if(nameage_strscore_str){intageatoi(age_str);floatscoreatof(score_str);printf( 姓名: %-10s 年龄: %3d 分数: %5.1f\n,name,age,score);}}fclose(file);}// 清理remove(test.txt);remove(data.txt);remove(data.csv);}7.2 配置文件解析#includestdio.h#includestdlib.h#includestring.h#includectype.h#defineMAX_LINE_LENGTH256#defineMAX_KEY_LENGTH50#defineMAX_VALUE_LENGTH100// 配置文件条目结构typedefstruct{charkey[MAX_KEY_LENGTH];charvalue[MAX_VALUE_LENGTH];}ConfigEntry;// 去除字符串两端的空白字符voidtrim_string(char*str){char*end;// 去除前导空白while(isspace((unsignedchar)*str)){str;}// 如果是空字符串if(*str\0){return;}// 去除尾部空白endstrstrlen(str)-1;while(endstrisspace((unsignedchar)*end)){end--;}// 写入新的结束符*(end1)\0;}// 解析配置文件intparse_config_file(constchar*filename,ConfigEntry*configs,intmax_configs){FILE*filefopen(filename,r);if(!file){printf(无法打开文件: %s\n,filename);return0;}charline[MAX_LINE_LENGTH];intcount0;while(fgets(line,sizeof(line),file)!NULLcountmax_configs){// 去除换行符line[strcspn(line,\n)]\0;// 跳过空行和注释trim_string(line);if(line[0]\0||line[0]#){continue;}// 查找等号char*equal_signstrchr(line,);if(!equal_sign){continue;// 无效行}// 分割键和值*equal_sign\0;char*keyline;char*valueequal_sign1;// 去除空白trim_string(key);trim_string(value);if(key[0]!\0){// 存储到配置数组strncpy(configs[count].key,key,MAX_KEY_LENGTH-1);configs[count].key[MAX_KEY_LENGTH-1]\0;strncpy(configs[count].value,value,MAX_VALUE_LENGTH-1);configs[count].value[MAX_VALUE_LENGTH-1]\0;count;}}fclose(file);returncount;}// 查找配置值constchar*get_config_value(constchar*key,ConfigEntry*configs,intcount){for(inti0;icount;i){if(strcmp(configs[i].key,key)0){returnconfigs[i].value;}}returnNULL;}voidconfig_file_demo(){printf( 配置文件解析示例 \n\n);// 创建示例配置文件FILE*config_filefopen(app.conf,w);if(config_file){fprintf(config_file,# 应用程序配置\n\n);fprintf(config_file,app_name My Application\n);fprintf(config_file,version 1.0.0\n);fprintf(config_file,max_users 100\n);fprintf(config_file,debug_mode true\n);fprintf(config_file,log_level info\n);fclose(config_file);}// 解析配置文件ConfigEntry configs[10];intcountparse_config_file(app.conf,configs,10);if(count0){printf(成功解析 %d 个配置项:\n\n,count);for(inti0;icount;i){printf( %-15s %s\n,configs[i].key,configs[i].value);}// 查找特定配置printf(\n查找配置项:\n);constchar*keys[]{app_name,max_users,not_found};for(inti0;i3;i){constchar*valueget_config_value(keys[i],configs,count);if(value){printf( %s: %s\n,keys[i],value);}else{printf( %s: (未找到)\n,keys[i]);}}// 类型转换示例printf(\n类型转换:\n);constchar*max_users_strget_config_value(max_users,configs,count);if(max_users_str){intmax_usersatoi(max_users_str);printf( max_users (整数): %d\n,max_users);}constchar*debug_mode_strget_config_value(debug_mode,configs,count);if(debug_mode_str){// 简单布尔值解析intdebug_mode0;if(strcmp(debug_mode_str,true)0||strcmp(debug_mode_str,1)0||strcmp(debug_mode_str,yes)0){debug_mode1;}printf( debug_mode (布尔): %s\n,debug_mode?是:否);}}// 清理remove(app.conf);}八、字符串加密与编码8.1 简单的字符串加密算法#includestdio.h#includestring.h#includectype.h// 凯撒密码将字符串中的每个字母移动n位voidcaesar_cipher(char*str,intshift){while(*str){if(isalpha(*str)){charbaseislower(*str)?a:A;*str((*str-baseshift)%26)base;}str;}}// XOR加密使用密钥对字符串进行XOR运算voidxor_cipher(char*str,charkey){while(*str){*str*str^key;// XOR运算str;}}// 简单的Base64编码简化版voidsimple_base64_encode(constchar*input,char*output){constcharbase64_table[]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/;inti0,j0;unsignedcharchar_array_3[3];unsignedcharchar_array_4[4];while(*input){char_array_3[i]*(input);if(i3){char_array_4[0](char_array_3[0]0xfc)2;char_array_4[1]((char_array_3[0]0x03)4)((char_array_3[1]0xf0)4);char_array_4[2]((char_array_3[1]0x0f)2)((char_array_3[2]0xc0)6);char_array_4[3]char_array_3[2]0x3f;for(i0;i4;i){output[j]base64_table[char_array_4[i]];}i0;}}if(i){for(intki;k3;k){char_array_3[k]\0;}char_array_4[0](char_array_3[0]0xfc)2;char_array_4[1]((char_array_3[0]0x03)4)((char_array_3[1]0xf0)4);char_array_4[2]((char_array_3[1]0x0f)2)((char_array_3[2]0xc0)6);char_array_4[3]char_array_3[2]0x3f;for(intk0;ki1;k){output[j]base64_table[char_array_4[k]];}while(i3){output[j];}}output[j]\0;}voidstring_encryption_demo(){printf( 字符串加密与编码 \n\n);// 凯撒密码示例printf(1. 凯撒密码:\n);chartext1[]Hello World;printf( 原文: %s\n,text1);caesar_cipher(text1,3);// 移3位printf( 加密: %s\n,text1);caesar_cipher(text1,-3);// 移回3位printf( 解密: %s\n\n,text1);// XOR加密示例printf(2. XOR加密:\n);chartext2[]Secret Message;charkey0x55;// 加密密钥printf( 原文: %s\n,text2);xor_cipher(text2,key);printf( 加密: );for(inti0;text2[i]!\0;i){printf(%02X ,(unsignedchar)text2[i]);}printf(\n);xor_cipher(text2,key);// 再次XOR恢复原文本printf( 解密: %s\n\n,text2);// Base64编码示例printf(3. Base64编码:\n);chartext3[]Hello Base64;charencoded[100];printf( 原文: %s\n,text3);simple_base64_encode(text3,encoded);printf( 编码: %s\n\n,encoded);// 实用示例密码隐藏printf(4. 密码输入隐藏:\n);charpassword[50];inti0;charch;printf( 请输入密码: );// 简单的密码隐藏不回显while(1){chgetchar();if(ch\n||ch\r){break;}elseif(ch127||ch8){// 退格键if(i0){i--;printf(\b \b);// 删除一个星号}}else{if(isizeof(password)-1){password[i]ch;printf(*);}}}password[i]\0;printf(\n 您输入的密码长度: %zu\n,strlen(password));// 简单加密存储for(intj0;ji;j){password[j]password[j]^0xAA;// 简单加密}printf( 加密后的密码: );for(intj0;ji;j){printf(%02X ,(unsignedchar)password[j]);}printf(\n);}九、字符串搜索与替换9.1 实现文本搜索功能#includestdio.h#includestring.h#includestdlib.h// 查找字符串中所有出现的位置voidfind_all_occurrences(constchar*str,constchar*substr){printf(在 \%s\ 中查找 \%s\:\n,str,substr);constchar*posstr;intcount0;while((posstrstr(pos,substr))!NULL){printf( 位置 %d: 偏移量 %ld\n,count,pos-str);posstrlen(substr);// 移动到下一个可能的位置}if(count0){printf( 未找到\n);}else{printf( 总共找到 %d 次\n,count);}}// 不区分大小写的字符串比较intcase_insensitive_compare(constchar*str1,constchar*str2){while(*str1*str2){if(tolower(*str1)!tolower(*str2)){returntolower(*str1)-tolower(*str2);}str1;str2;}returntolower(*str1)-tolower(*str2);}// 不区分大小写的查找voidfind_case_insensitive(constchar*str,constchar*substr){printf(\n不区分大小写查找 \%s\:\n,substr);intstr_lenstrlen(str);intsub_lenstrlen(substr);intcount0;for(inti0;istr_len-sub_len;i){// 创建临时子字符串进行比较chartemp[sub_len1];strncpy(temp,stri,sub_len);temp[sub_len]\0;if(case_insensitive_compare(temp,substr)0){printf( 位置 %d: 偏移量 %d\n,count,i);}}if(count0){printf( 未找到\n);}}// 字符串替换函数char*replace_string(constchar*str,constchar*old,constchar*new){// 计算新字符串所需的空间intcount0;constchar*tmpstr;while((tmpstrstr(tmp,old))!NULL){count;tmpstrlen(old);}// 分配内存size_tnew_lenstrlen(str)count*(strlen(new)-strlen(old))1;char*resultmalloc(new_len);if(!result){returnNULL;}char*currentresult;constchar*startstr;constchar*found;while((foundstrstr(start,old))!NULL){// 复制旧字符串之前的部分size_tlenfound-start;strncpy(current,start,len);currentlen;// 复制新字符串strcpy(current,new);currentstrlen(new);// 移动到旧字符串之后startfoundstrlen(old);}// 复制剩余部分strcpy(current,start);returnresult;}voidsearch_and_replace_demo(){printf( 字符串搜索与替换 \n\n);chartext[]The quick brown fox jumps over the lazy dog. The fox is quick.;// 查找所有出现find_all_occurrences(text,fox);find_all_occurrences(text,the);// 不区分大小写查找find_case_insensitive(text,the);// 字符串替换printf(\n字符串替换:\n);printf(原文: %s\n,text);char*replacedreplace_string(text,fox,cat);if(replaced){printf(替换后: %s\n,replaced);free(replaced);}// 更复杂的替换replacedreplace_string(text,quick,fast);if(replaced){printf(再次替换: %s\n,replaced);free(replaced);}// 单词统计printf(\n单词统计:\n);char*copystrdup(text);// 复制字符串char*word;intword_count0;wordstrtok(copy, .,!?);// 按空格和标点分割while(word!NULL){word_count;printf( 单词 %d: %s\n,word_count,word);wordstrtok(NULL, .,!?);}printf(总单词数: %d\n,word_count);free(copy);}十、实战项目简易文本编辑器#includestdio.h#includestdlib.h#includestring.h#includectype.h#defineMAX_LINES1000#defineMAX_LINE_LENGTH256// 文本缓冲区结构typedefstruct{char**lines;// 字符串指针数组intline_count;// 总行数intcapacity;// 容量}TextBuffer;// 初始化文本缓冲区TextBuffer*create_text_buffer(){TextBuffer*buffermalloc(sizeof(TextBuffer));if(!buffer)returnNULL;buffer-capacity100;buffer-line_count0;buffer-linesmalloc(buffer-capacity*sizeof(char*));if(!buffer-lines){free(buffer);returnNULL;}returnbuffer;}// 添加一行文本intadd_line(TextBuffer*buffer,constchar*text){if(buffer-line_countbuffer-capacity){// 扩容buffer-capacity*2;buffer-linesrealloc(buffer-lines,buffer-capacity*sizeof(char*));if(!buffer-lines)return0;}buffer-lines[buffer-line_count]strdup(text);if(!buffer-lines[buffer-line_count])return0;buffer-line_count;return1;}// 插入一行文本intinsert_line(TextBuffer*buffer,intposition,constchar*text){if(position0||positionbuffer-line_count){return0;// 位置无效}if(buffer-line_countbuffer-capacity){buffer-capacity*2;buffer-linesrealloc(buffer-lines,buffer-capacity*sizeof(char*));if(!buffer-lines)return0;}// 移动后续行for(intibuffer-line_count;iposition;i--){buffer-lines[i]buffer-lines[i-1];}buffer-lines[position]strdup(text);if(!buffer-lines[position])return0;buffer-line_count;return1;}// 删除一行intdelete_line(TextBuffer*buffer,intposition){if(position0||positionbuffer-line_count){return0;// 位置无效}free(buffer-lines[position]);// 移动后续行for(intiposition;ibuffer-line_count-1;i){buffer-lines[i]buffer-lines[i1];}buffer-line_count--;return1;}// 保存到文件intsave_to_file(TextBuffer*buffer,constchar*filename){FILE*filefopen(filename,w);if(!file)return0;for(inti0;ibuffer-line_count;i){fprintf(file,%s\n,buffer-lines[i]);}fclose(file);return1;}// 从文件加载intload_from_file(TextBuffer*buffer,constchar*filename){FILE*filefopen(filename,r);if(!file)return0;charline[MAX_LINE_LENGTH];// 清空当前缓冲区for(inti0;ibuffer-line_count;i){free(buffer-lines[i]);}buffer-line_count0;// 读取文件while(fgets(line,sizeof(line),file)!NULL){// 去除换行符line[strcspn(line,\n)]\0;if(!add_line(buffer,line)){fclose(file);return0;}}fclose(file);return1;}// 查找文本voidsearch_text(TextBuffer*buffer,constchar*pattern){printf(\n查找 \%s\:\n,pattern);intfound0;for(inti0;ibuffer-line_count;i){char*posstrstr(buffer-lines[i],pattern);if(pos){printf( 行 %d: %s\n,i1,buffer-lines[i]);// 高亮显示匹配部分printf( );for(intj0;jpos-buffer-lines[i];j){printf( );}for(intj0;jstrlen(pattern);j){printf(^);}printf(\n);found1;}}if(!found){printf( 未找到\n);}}// 替换文本intreplace_text(TextBuffer*buffer,constchar*old,constchar*new){intreplaced0;for(inti0;ibuffer-line_count;i){char*replaced_linereplace_string(buffer-lines[i],old,new);if(replaced_linestrcmp(replaced_line,buffer-lines[i])!0){free(buffer-lines[i]);buffer-lines[i]replaced_line;replaced1;}elseif(replaced_line){free(replaced_line);}}returnreplaced;}// 显示文本voiddisplay_text(TextBuffer*buffer){printf(\n当前文本内容:\n);printf(\n);for(inti0;ibuffer-line_count;i){printf(%3d: %s\n,i1,buffer-lines[i]);}printf(\n);}// 释放缓冲区voidfree_text_buffer(TextBuffer*buffer){for(inti0;ibuffer-line_count;i){free(buffer-lines[i]);}free(buffer-lines);free(buffer);}voidtext_editor_demo(){printf( 简易文本编辑器 \n\n);TextBuffer*buffercreate_text_buffer();if(!buffer){printf(创建文本缓冲区失败\n);return;}// 添加一些示例文本add_line(buffer,这是第一行文本);add_line(buffer,这是第二行包含一些内容);add_line(buffer,第三行用于演示文本编辑器);add_line(buffer,第四行包含关键词文本);intchoice;charinput[MAX_LINE_LENGTH];charfilename[100];intline_num;do{printf(\n菜单:\n);printf(1. 显示文本\n);printf(2. 添加行\n);printf(3. 插入行\n);printf(4. 删除行\n);printf(5. 保存到文件\n);printf(6. 从文件加载\n);printf(7. 查找文本\n);printf(8. 替换文本\n);printf(0. 退出\n);printf(请选择: );scanf(%d,choice);getchar();// 消耗换行符switch(choice){case1:display_text(buffer);break;case2:printf(请输入要添加的文本: );fgets(input,sizeof(input),stdin);input[strcspn(input,\n)]\0;// 去除换行符if(add_line(buffer,input)){printf(添加成功\n);}else{printf(添加失败\n);}break;case3:printf(请输入行号: );scanf(%d,line_num);getchar();// 消耗换行符printf(请输入要插入的文本: );fgets(input,sizeof(input),stdin);input[strcspn(input,\n)]\0;if(insert_line(buffer,line_num-1,input)){printf(插入成功\n);}else{printf(插入失败\n);}break;case4:printf(请输入要删除的行号: );scanf(%d,line_num);getchar();// 消耗换行符if(delete_line(buffer,line_num-1)){printf(删除成功\n);}else{printf(删除失败\n);}break;case5:printf(请输入文件名: );fgets(filename,sizeof(filename),stdin);filename[strcspn(filename,\n)]\0;if(save_to_file(buffer,filename)){printf(保存成功\n);}else{printf(保存失败\n);}break;case6:printf(请输入文件名: );fgets(filename,sizeof(filename),stdin);filename[strcspn(filename,\n)]\0;if(load_from_file(buffer,filename)){printf(加载成功\n);}else{printf(加载失败\n);}break;case7:printf(请输入要查找的文本: );fgets(input,sizeof(input),stdin);input[strcspn(input,\n)]\0;search_text(buffer,input);break;case8:printf(请输入要替换的文本: );fgets(input,sizeof(input),stdin);input[strcspn(input,\n)]\0;charnew_text[MAX_LINE_LENGTH];printf(请输入替换后的文本: );fgets(new_text,sizeof(new_text),stdin);new_text[strcspn(new_text,\n)]\0;if(replace_text(buffer,input,new_text)){printf(替换成功\n);}else{printf(未找到匹配文本\n);}break;case0:printf(退出文本编辑器\n);break;default:printf(无效选择\n);}}while(choice!0);free_text_buffer(buffer);}十一、总结字符串指针的核心要点11.1 关键概念回顾字符串的本质以’\0’结尾的字符数组字符串指针指向字符串第一个字符的指针内存区域字符串可以存储在栈、堆或常量区安全性注意缓冲区溢出和内存管理11.2 常见字符串操作模式操作 安全做法 危险做法复制 strncpy, 检查边界 strcpy, 不检查边界连接 strncat, 计算剩余空间 strcat, 可能溢出比较 strncmp, 指定长度 strcmp, 可能越界内存 动态分配及时释放 静态分配可能不够11.3 最佳实践始终检查边界确保目标缓冲区足够大使用const修饰不可修改的字符串提高代码安全性记得释放动态内存防止内存泄漏处理字符串结束符确保字符串正确终止考虑本地化对于多语言支持注意字符编码