这是我写的C的快速substr()(是的,变量初始化需要移动到函数的开头等,但你明白了)
我见过很多简单的衬里调用strncpy()的“聪明”的substr()实现!
它们都是错的(strncpy不保证空终止,因此调用可能不会产生正确的子字符串!)
这可能更好吗?
带出虫子!
char* substr(const char* text, int nStartingPos, int nRun)
{
char* emptyString = strdup(""); /* C'mon! This cannot fail */
if(text == NULL) return emptyString;
int textLen = strlen(text);
--nStartingPos;
if((nStartingPos < 0) || (nRun <= 0) || (textLen == 0) || (textLen < nStartingPos)) return emptyString;
char* returnString = (char *)calloc((1 + nRun), sizeof(char));
if(returnString == NULL) return emptyString;
strncat(returnString, (nStartingPos + text), nRun);
/* We do not need emptyString anymore from this point onwards */
free(emptyString);
emptyString = NULL;
return returnString;
}
int main()
{
const char *text = "-2--4--6-7-8-9-10-11-";
char *p = substr(text, -1, 2);
printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
free(p);
p = substr(text, 1, 2);
printf("[*]'%s' (-2)\n", ((p == NULL) ? "<NULL>" : p));
free(p);
p = substr(text, 3, 2);
printf("[*]'%s' (--)\n", ((p == NULL) ? "<NULL>" : p));
free(p);
p = substr(text, 16, 2);
printf("[*]'%s' (10)\n", ((p == NULL) ? "<NULL>" : p));
free(p);
p = substr(text, 16, 20);
printf("[*]'%s' (10-11-)\n", ((p == NULL) ? "<NULL>" : p));
free(p);
p = substr(text, 100, 2);
printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
free(p);
p = substr(text, 1, 0);
printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
free(p);
return 0;
}
输出:
[*]'' (")
[*]'-2' (-2)
[*]'--' (--)
[*]'10' (10)
[*]'10-11-' (10-11-)
[*]'' (")
[*]'' (")
答案 0 :(得分:7)
对于应该是简单的操作,您的功能似乎非常复杂。有些问题(并非所有这些都是错误):
strdup()
,以及其他内存分配函数, 可能失败,您应该考虑所有可能的问题。malloc()
失败substr ("xxx",1,1)
或工作substr ("xxx",1,0)
是否会产生空字符串。calloc()
内存。strncat()
- 在执行任何复制之前,你应该知道你可用的大小和内存,这样你就可以使用(最有可能)更快{{} 1}}。以下部分就是我要做的事情(我更喜欢从字符串末尾开始计算负值的Python习语,但我保持长度而不是结束位置。)
memcpy()
答案 1 :(得分:5)
如果输入无效而不是NULL
ed空字符串,我会说返回malloc()
。这样,您可以使用if(p)
而不是if(*p == 0)
来测试功能是否失败。
另外,我认为你的函数会泄漏内存,因为emptyString
在一个条件中只有free()
d。您应该无条件地确保free()
,即在return
之前。
关于你对strncpy()
的评论而不是NUL-终止字符串(这是真的),如果你使用calloc()
来分配字符串而不是malloc()
,那么这不是如果您分配比复制多一个字节的问题,则会出现问题,因为calloc()
会自动将所有值(在这种情况下,包括结尾)设置为0。
我会给你更多笔记,但我讨厌阅读camelCase代码。并不是说它有任何问题。
编辑:关于您的更新:
请注意,无论您的系统如何,C标准都将sizeof(char)
定义为1。如果你使用的是一个字节中使用9位的计算机(上帝保佑),sizeof(char)
仍然是1.并不是说sizeof(char)
有任何问题 - 它清楚地表明你的意图和为其他类型调用calloc()
或malloc()
提供对称性。但是sizeof(int)
实际上很有用(int
可以在16和32-以及这些新奇的64位计算机上使用不同的大小。你知道的越多。
我还想重申,与大多数其他C代码的一致性是在错误而不是NULL
上返回""
。我知道很多函数(比如strcmp()
)可能会做坏事,如果你把它们传递给NULL - 这是可以预料的。但是C标准库(以及许多其他C API)采用的方法是“调用者负责检查NULL
,而不是函数负责给他/她做好准备,如果他没有。”如果你想以另一种方式做到这一点,那很酷,但这与C界面设计中更强烈的趋势相反。
另外,我会使用strncpy()
(或memcpy()
)而不是strncat()
。使用strncat()
(和strcat()
)会模糊您的意图 - 这会让某人看到您的代码,认为您想要添加到字符串的末尾(您执行此操作,因为在calloc()
之后,结束是开始),当你想要做的是设置字符串。 strncat()
使您看起来像是在添加字符串,而strcpy()
(或其他复制例程)会使它看起来更像您的意图。在这种情况下,以下三行都做同样的事情 - 选择你认为最好的那一行:
strncat(returnString, text + nStartingPos, nRun);
strncpy(returnString, text + nStartingPos, nRun);
memcpy(returnString, text + nStartingPos, nRun);
另外,strncpy()
和memcpy()
可能比strncat()
更快/更有效。
text + nStartingPos
与nStartingPos + text
相同 - 我会将char *
放在第一位,因为我认为更清楚,但无论您想要将它们放入哪个顺序取决于您。此外,它们周围的括号是不必要的(但很好),因为+
的优先级高于,
。
编辑2:三行代码不做同样的事情,但在这种情况下,它们都会产生相同的结果。谢谢你抓住我。
答案 2 :(得分:1)
char* emptyString = strdup(""); /* C'mon! This cannot fail? */
您需要检查null。请记住,它仍然必须为空字符分配1个字节。
答案 3 :(得分:0)
strdup可能会失败(虽然它不太可能,不值得检查,恕我直言)。但确实有另一个问题 - 它不是标准C功能。使用malloc会更好。
答案 4 :(得分:0)
您还可以使用memmove函数从开始到长度返回子字符串。 改进/添加paxdiablo解决方案的另一个解决方案:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *splitstr(char *idata, int start, int slen) {
char ret[150];
if(slen == NULL) {
slen=strlen(idata)-start;
}
memmove (ret,idata+start,slen);
return ret;
}
/*
Usage:
char ostr[]="Hello World!";
char *ores=splitstr(ostr, 0, 5);
Outputs:
Hello
*/
希望它有所帮助。使用TCC C Compilier在Windows 7 Home Premium上测试。