找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3307|回复: 12

C语言实现像高级语言一样的字符串操作

[复制链接]
发表于 2019-6-21 15:45:25 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 乘简 于 2019-7-12 09:45 编辑

如何用C语言操作字符串,像高级语言一样灵活的操作,字符串的长度任意变呢?答案是肯定的,而且更灵活,效率更高!

下面实现strcpy与strcat函数的结合体
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>

  4. #define MEM_ALINE 64//预留量,为了减少内存分配次数

  5. //定义结构体,声明变量的时候必须要赋初值
  6. //比如string str={0,0,0};
  7. typedef struct{
  8.     size_t memlen;//内存长度
  9.     size_t strlen;//字符长度
  10.     char* str;//字符串,后面有'\0'
  11. }string;

  12. //本模块所有的函数在变量不用时,都需要释放内存
  13. void str_free(string *src)
  14. {
  15.     if(src->memlen){//如果已经申请过了内存
  16.         src->memlen=src->strlen=0;
  17.         free(src->str);
  18.     }
  19. }

  20. //构建字符串,sour字符串在定义string t1={0,0,0};必须要初始化成0
  21. //因为第二次要用realloc函数分配内存了
  22. //本函数支持strcpy_free(&t1,t1.str,3);也就是说把自边往后移3位
  23. //函数名后面加_free表示提醒程序员不要忘了用str_free函数释放内存
  24. void strcpy_free(string *dest,char *sour,size_t start)
  25. {
  26.     char *src=sour;//定义新变量,用于自身复制到自身时
  27.     size_t len=strlen(src)+1;//新字符的长度
  28.     if(start>dest->strlen)start=dest->strlen;//如果传入的起始位置大于原来的长度
  29.     if(len==1){//如果src="",可以直接用desc->str[xx]=0;与dest->strlen=start;来代替
  30.         if(dest->strlen){//原来有内容
  31.             dest->str[start]=0;
  32.             dest->strlen=start;
  33.         }
  34.     }
  35.     else{
  36.         int isFree=0;//是否需要释放内存
  37.         if(dest->memlen==0){//如果第1次赋值
  38.             len+=start;//整长度加上起始位置
  39.             dest->strlen=len-1;//字符长度
  40.             dest->str=(char*)malloc(len);//分配内存
  41.             dest->memlen=len;//内存长度
  42.             strcpy(&dest->str[start],src);//复制字符串
  43.         }
  44.         else{
  45.             if(src>=dest->str && src<=dest->str+start){//内存地址有重叠,可能是自身复制到自身
  46.                 src=(char*)malloc(len);//分配原来的长度
  47.                 strcpy(src,sour);//先把原来的数据复制到临时变量中
  48.                 isFree=1;//需要释放临时分配的内存
  49.             }

  50.             len+=start;//整长度加上起始位置
  51.             dest->strlen=len-1;//字符长度
  52.             if(dest->memlen<len){//内存扩容
  53.                 len+=MEM_ALINE;//多分配预留量
  54.                 dest->memlen=len;//内存长度
  55.                 dest->str=(char*)realloc(dest->str,len);//扩容内存
  56.             }

  57.             strcpy(&dest->str[start],src);//复制字符串
  58.         }

  59.         if(len+(MEM_ALINE<<1)<=dest->memlen){//如果新内存空间,比原来小2倍预留量
  60.             dest->memlen=len+MEM_ALINE;//为了节省了内存空间,保留预留量后释放多余内存
  61.             dest->str=(char*)realloc(dest->str,dest->memlen);
  62.         }

  63.         if(isFree)free(src);//释放临时分配的内存
  64.     }
  65. }

  66. int main(int argc,char*argv[])
  67. {
  68.     string t1={0,0,0};


  69.     //1.连接两个字符串
  70.     strcpy_free(&t1,"Hello! My Good ",0);
  71.     printf("%s\n",t1.str);
  72.     strcpy_free(&t1,"Friends.~~",t1.strlen);
  73.     printf("%s\n",t1.str);
  74.     strcpy_free(&t1,t1.str,7);
  75.     printf("%s\n",t1.str);
  76.     strcpy_free(&t1,"abcd",1);
  77.     printf("%s\n",t1.str);

  78.     str_free(&t1);//释放内存
  79. }
复制代码


)@ERB{FQEKA$8IZJG5Y]{VB.png
回复

使用道具 举报

发表于 2019-6-22 17:44:37 | 显示全部楼层
支持楼主
回复

使用道具 举报

发表于 2019-6-22 22:35:19 | 显示全部楼层
代码我领走了,会好好对待它的,别担心
回复 赞! 靠!

使用道具 举报

发表于 2019-6-23 02:53:27 | 显示全部楼层
建议使用WINDOWS定义的ANSI_STRING结构体替代你自定义的结构体:
  1. typedef struct{
  2.     size_t memlen;//内存长度
  3.     size_t strlen;//字符长度
  4.     char* str;//字符串,后面有'\0'
  5. }string;

  6. typedef struct _ANSI_STRING {
  7.   USHORT Length;        //字符串长度
  8.   USHORT MaximumLength; //内存长度
  9.   PCHAR  Buffer;        //字符串指针,结尾不一定有\0,建议一律当作结尾没有\0
  10. } ANSI_STRING;
复制代码
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2019-6-26 17:31:32 | 显示全部楼层
本帖最后由 乘简 于 2019-6-26 17:33 编辑
美俪女神 发表于 2019-6-23 02:53
建议使用WINDOWS定义的ANSI_STRING结构体替代你自定义的结构体:


不想名字太长,,麻烦,而且USHORT太短了,,,而且结尾没有'\0'的话,肯定要另外写一套内存结构,配套的函数,而不是string结构,这样不管是结尾还是中间,都允许有'\0',string就是结尾带'\0'的。
回复 赞! 靠!

使用道具 举报

发表于 2019-6-26 21:32:19 | 显示全部楼层
本帖最后由 Ayala 于 2019-6-26 21:43 编辑

用字典或者字符组 这样就可以交叉引用字符串了
另外吐槽下 c语言不是高级语言么 一般来说用c语言 使用strcat的情况不算多 感觉用的最多的地方还是传递参数,索引全路径等 如果只是打印到内存 文件或者控制台这样做就有点造轮子了
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2019-6-27 10:52:07 | 显示全部楼层
Ayala 发表于 2019-6-26 21:32
用字典或者字符组 这样就可以交叉引用字符串了
另外吐槽下 c语言不是高级语言么 一般来说用c语言 使用strca ...

完全不是这样的,如果你自己要用纯C写一个表格控件的话,,呵呵。。。

每个单元格中的文本,是变长的,我想,高级语言,在低层也是这样实现的吧。。。
回复 赞! 靠!

使用道具 举报

发表于 2019-6-27 11:12:46 | 显示全部楼层
USHORT能到65535,塞一篇小文章都够了。
此外建议UNICODE_STRING,微软有相关函数。
以wcsncat函数举例,对应有RtlAppendUnicodeStringToString。
wcsncpy就能对应RtlCopyUnicodeString。
wcsn(i)cmp对应RtlCompareUnicodeString。
这些在ntdll.dll里都导出了。
甚至还能RtlUnicodeStringPrintf,实现swnprintf的操作。
如果知道这个结构体的指针,还能用%wZ把字符串给printf出来。
所以你真的是在过度造轮。
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2019-6-27 13:16:09 | 显示全部楼层
tangptr@126.com 发表于 2019-6-27 11:12
USHORT能到65535,塞一篇小文章都够了。
此外建议UNICODE_STRING,微软有相关函数。
以wcsncat函数举例,对 ...

USHORT肯定是不够的,万一有一些奇葩的功能需要用到超过65535时,就不好了,所以一劳永逸啊。。。

还有,unicode_string其实也是可以用char *来保存的。

而且这个与ntdll.dll中的那些函数完全无关,只是想用C实现像高级语言那样的不定长字符串合并运算的功能而已。
回复 赞! 靠!

使用道具 举报

发表于 2019-6-29 11:11:56 | 显示全部楼层
乘简 发表于 2019-6-27 10:52
完全不是这样的,如果你自己要用纯C写一个表格控件的话,,呵呵。。。

每个单元格中的文本,是变长的, ...


大多使用utf或者unicode_string格式 而且也不是所谓的不定长(有最大长度限制的) 对于长文本也不是直接储存的文本指针 大多时候是储存句柄
回复 赞! 靠!

使用道具 举报

发表于 2019-6-29 11:17:04 | 显示全部楼层
本帖最后由 Ayala 于 2019-6-29 11:22 编辑
乘简 发表于 2019-6-27 10:52
完全不是这样的,如果你自己要用纯C写一个表格控件的话,,呵呵。。。

每个单元格中的文本,是变长的, ...


表格控件使用xml样式处理不定长要好些 文本内容基本上不需要连续 不过用c语言编程很自由 每个人都有自己的开发习惯 可能自己写的代码今天觉得好 明天自己看着都难受

点评

XML看到就烦,还不如JSON简单直接。。。  发表于 2019-7-4 16:25
回复 赞! 靠!

使用道具 举报

发表于 2019-7-30 19:01:16 | 显示全部楼层
美俪女神 发表于 2019-6-23 02:53
建议使用WINDOWS定义的ANSI_STRING结构体替代你自定义的结构体:


我觉得他的这个似乎更好,只是string这个类型名和C艹的stl的string重名了,写成库的话会让调用者骂娘。

好在访问快并且使用了标准类型。USHORT什么的在我看来是魔鬼

XML看到就烦,还不如JSON简单直接。。。


关于这个,不考虑一下NBT嘛?来和我一起解析mca文件,编写新的地图画工具吧
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-23 16:00 , Processed in 0.039661 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表