题
也可以看看 C 分词器
这是我为 C 编写的一个快速 substr() (是的,变量初始化需要移动到函数的开头等,但你明白了)
我见过许多 substr() 的“智能”实现,它们都是简单的一个衬垫调用 strncpy()!
它们都是错误的(strncpy 不保证 null 终止,因此调用可能不会产生正确的子字符串!)
这可能是更好的东西吗?
把 bug 拿出来!
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-)
[*]'' (")
[*]'' (")
解决方案
我想说的回报NULL
如果输入不超过malloc()
ed空字符串,而有效。这样,你可以测试功能是否失败或不符合if(p)
而非if(*p == 0)
。
另外,我想是因为emptyString
在一个条件仅free()
d你的函数泄漏内存。你应该确保你的free()
前右return
它无条件地,即。
至于在strncpy()
您的评论不是NUL终止字符串(这是真的),如果使用calloc()
分配的字符串,而不是malloc()
,这不会,如果你分配比复制一个字节更是一个问题,因为calloc()
自动设定所有值(包括,在这种情况下,端部)设置为0。
我会给你更多的音符,但我讨厌读书驼峰代码。不是说有什么错。
编辑:至于你的更新:
注意,C标准定义sizeof(char)
为1不管你的系统的。如果您使用的是在一个字节使用9位(但愿)的计算机,sizeof(char)
仍在为1。不是说有什么不好说sizeof(char)
- 这清楚地表明你的意图,并提供对称调用calloc()
或malloc()
对于其他类型。但sizeof(int)
实际上是有用的(int
s可以在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 *
第一,因为我认为这是更清晰,但你要把他们是你的什么顺序。此外,他们周围的括号是不必要的(但很好),因为+
具有比,
更高的优先级。
EDIT 2:三行代码不做同样的事情,但在这种情况下它们都将产生相同的结果。感谢赶上我这句话。
其他提示
对于本应简单的操作,您的功能似乎非常复杂。一些问题是(并非所有这些都是错误):
strdup()
, ,以及其他内存分配函数, 能 如果失败,您应该考虑到所有可能的问题。- 仅在需要时分配资源(在本例中为内存)。
- 你应该能够区分错误和有效的刺痛。此刻,你不知道是否
malloc()
的失败substr ("xxx",1,1)
或正在工作的substr ("xxx",1,0)
产生一个空字符串。 - 你不需要
calloc()
无论如何你都会覆盖的记忆。 - 所有无效参数都应该导致错误或强制为有效参数(并且您的 API 应记录哪些参数)。
- 释放本地空字符串后,无需将其设置为 NULL - 它会在函数返回时丢失。
- 你不需要 usr
strncat()
- 你 应该 在进行任何复制之前了解可用的大小和内存,以便您可以(最有可能)更快地使用memcpy()
. - 你使用base-1而不是base-0作为字符串偏移量违背了C的原则。
下面的部分是我要做的(我更喜欢 Python 的负值习惯用法,从字符串末尾开始计数,但我保留了长度而不是结束位置)。
char *substr (const char *inpStr, int startPos, int strLen) {
/* Cannot do anything with NULL. */
if (inpStr == NULL) return NULL;
/* All negative positions to go from end, and cannot
start before start of string, force to start. */
if (startPos < 0)
startPos = strlen (inpStr) + startPos;
if (startPos < 0)
startPos = 0;
/* Force negative lengths to zero and cannot
start after end of string, force to end. */
if (strLen < 0)
strLen = 0;
if (startPos >strlen (inpStr))
startPos = strlen (inpStr);
/* Adjust length if source string too short. */
if (strLen > strlen (&inpStr[startPos]))
strLen = strlen (&inpStr[startPos]);
/* Get long enough string from heap, return NULL if no go. */
if ((buff = malloc (strLen + 1)) == NULL)
return NULL;
/* Transfer string section and return it. */
memcpy (buff, &(inpStr[startPos]), strLen);
buff[strLen] = '\0';
return buff;
}
char* emptyString = strdup(""); /* C'mon! This cannot fail? */
您需要检查空。请记住,它仍然必须为空字符分配1个字节。
的strdup可能会失败(尽管它是不太可能,不值得检查,恕我直言)但它确实有一个问题 - 这是不是一个标准的C函数。这将是更好的使用malloc。
您还可以使用的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
*/
希望它能帮助。测试在Windows 7家庭高级与TCCÇCompilier。