C23标准化 strdup() / strndup() ,但被遗漏了 stpcpy() . stpcpy() 不同于 strcpy() 其中,它返回一个指向复制字符串的终止空字节的指针,而不是指向目标字符串的起始地址的指针。 它允许这样做: char bigString[1000]; bigString[0]=“\0”; stpcy(stpcpy(stpcdy(stpcy,bigString,“John”),“Paul”,“Geoge”,“),“Joel”)); 而不是: char bigString[1000]; bigString[0]=“\0”;// 或strcpy() strcat(strcat,strcat); 如果你不知道, strcat() 使用 画家Shlemiel的算法 . 有两个不同版本的 基本名称() (POSIX和GNU)。 POSIX版本修改了 路径 参数,当使用静态字符串调用时可能会出现segfault,例如 “/usr/” 。我尝试遵循的GNU版本没有。 关于 打印() 和 血管打印() ,我会直接引用 手册页 : 功能 打印() 和 vasprintf() 是的类似物 冲刺(3) 和 vsprintf(3) ,只是它们分配了一个足够大的字符串来保存输出,包括终止的空字节,并通过第一个参数返回指向它的指针。 此指针应传递给 免费(3) 在不再需要时释放分配的存储。 不幸的是,ISO C23也忽略了这两个优点。 这个 strchrnul() 不同于 strchr() 其中,它返回一个指向匹配字符的指针,或指向末尾的空字节的指针 秒 (即, s+字符串) 如果找不到字符。 我发现这很有用的一个地方是从输入字符串中删除尾随换行符。 使用 strchr() ,一个人会这样做: char*p=strchr(s,'\n'); 如果(p){ *p=“\0”; } 使用 strchrnul() ,您可以跳过分支并直接取消引用结果: *strchrnul(s,'\n')='\0'; 这个 strcasecmp() 函数对 两个字符串,忽略字符的大小写。
代码:
#如果索引UTIL_H #定义UTIL_H 1 #包括<stdarg.h> int util_vasprintf(char**restrict strp, const char fmt[restrict static 1], va_list ap); [[gnu::format(printf,2,3)]]int util_asprintf(char**restrict strp, const char fmt[restrict static 1], ...); [[gnu::returns_nonnull]]char*util_stpcpy(char dest[restrict static 1], const char src[restrict static 1]); [[gnu::returns_nonnull]]常量字符*util_basename(常量字符路径[static 1]); [[gnu::pure,gnu::returns_nonnull]]字符*util_strchrnul(const字符s[static 1], int c); [[gnu::pure]]int util_strcasecmp(const char s[restrict static 1], const char t[restrict static 1]); #endif/*UTIL_H*/
#包括<ctype.h> #包括<stdio.h> #包括<stdlib.h> #包括<string.h> #包括<stdarg.h> #包括“util.h” int util_vasprintf(char**restrict strp,const char fmt[restrict static 1], va_list ap) { va列表ap_copy; va副本(ap_copy,ap); const int nwritten=vsnprintf(nullptr,0,fmt,ap_copy); va_end(ap_copy); if(nwriten<0){ 死亡; } *strp=malloc((size_t)nwritten+1); if(*strp==nullptr){ 死亡; } const int status=vsprintf(*strp,fmt,ap); if(状态<0){ 自由(*strp); 死亡; } 返回状态; 致命: /*BSD实现在失败时将*strp设置为nullptr。 Linux的叶子 *内容未定义。 C和POSIX都没有对此进行标准化 *功能*/ *strp=nullptr; 返回-1; } int util_asprintf(char**restrict strp,const char fmt[static 1],…) { va_list argp; va启动(argp,fmt); *strp=nullptr; int nwritten=util_vasprintf(strp,fmt,argp); va_end(argp); 返回nwriten; } char*util_stpcpy(char dest[restrict static 1], const char src[restrict static 1]) { const size_t len=字符串(src); return(char*)memcpy(dest,src,len+1)+len; } const char*util_basename(const char-路径[static 1]) { char*const cp=strrchr(路径,'/'); 返回cp? cp+1:路径; } char*util_strchrnul(常量char s[static 1],int c) { 同时(*s){ 如果(*s==c){ 断裂; } } 返回(char*)s; } int util_strcasecmp(const char s[restrict static 1], const char t[限制静态1]) { 整数p,q; 做{ p=*s++; if(islower((unsigned char)p)){ p=toupper((无符号字符)p); } q=*t++; if(islower((unsigned char)q)){ q=toupper((无符号字符)p); } }而(p==q&&q!='\0'); 返回p-q; } #ifdef测试主 #包括<assert.h> int main(无效) { 断言(strcmp(util_basename(“/usr/lib”),“lib”,==0); 断言(strcmp(util_basename(“/usr/”),“”)==0); 断言(strcmp(util_basename(“usr”),“usr“)==0); 断言(strcmp(util_basename(“/”),“”)==0); 断言(strcmp(util_basename(“.”),“.”,==0); assert(strcmp(util_basename(“..”),“..”)==0); 断言(util_strcasecmp(“aPplE”,“aPplE”)==0); 断言(util_strcasecmp(“苹果”,“苹果”)==0); 断言(util_strcasecmp(“HELLO”,“HELLO”)==0); 断言(util_strcasecmp(“,”)==0); 断言(util_strcasecmp(“HrLLO”,“HELLO”)); } #结尾