Poo*_*zer 1 c substring substr
另请参见C Tokenizer
这是我写的C的快速substr()(是的,变量初始化需要移动到函数的开始等,但你明白了)
我已经看到很多substr()的"智能"实现,简单的一行调用strncpy()!
它们都是错的(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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
[*]'' (")
[*]'-2' (-2)
[*]'--' (--)
[*]'10' (10)
[*]'10-11-' (10-11-)
[*]'' (")
[*]'' (")
Run Code Online (Sandbox Code Playgroud)
对于应该是简单的操作,您的功能似乎非常复杂.有些问题(并非所有这些都是错误):
strdup()和其他内存分配函数,可能会失败,您应该允许所有可能的问题.malloc()失败substr ("xxx",1,1)或工作是否substr ("xxx",1,0)产生空字符串.calloc()无论如何你都不需要记忆.strncat()- 在进行任何复制之前你应该知道你可用的大小和内存,以便你可以更快地使用(最有可能)memcpy().以下部分就是我要做的事情(我更喜欢从字符串末尾开始计算负值的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;
}
Run Code Online (Sandbox Code Playgroud)
NULL如果输入无效而不是malloc()ed空字符串,我会说返回.这样你就可以测试函数是否失败,if(p)而不是if(*p == 0).
此外,我认为你的函数泄漏内存,因为emptyString只有free()一个条件.你应该free()无条件地确保它,即在之前return.
至于你的注释strncpy()不是NUL - 终止字符串(这是真的),如果你calloc()用来分配字符串而不是malloc(),如果你分配比复制更多的一个字节,这将不会有问题,因为calloc()自动设置所有值(包括,在这种情况下,结束)为0.
我会给你更多的笔记,但我讨厌阅读camelCase代码.并不是说它有什么问题.
编辑:关于您的更新:
请注意,sizeof(char)无论您的系统如何,C标准都定义为1.如果你使用的是一个字节中使用9位的计算机(上帝保佑),那么sizeof(char)它仍然是1.并不是说它有任何问题sizeof(char)- 它清楚地显示了你的意图,并提供对称calloc()或malloc()其他类型的调用.但sizeof(int)实际上是有用的(int在16和32-以及这些新奇的64位计算机上可以有不同的大小).你知道的越多.
我还要重申,与大多数其他C代码的一致性是返回NULL错误而不是"".我知道很多函数(比如strcmp())如果你传递它们可能会做坏事 - 这是可以预料的.但是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);
Run Code Online (Sandbox Code Playgroud)
另外,strncpy()并且memcpy()可能比(小)更快/更高效strncat().
text + nStartingPos是相同的nStartingPos + text- 我会把第char *一个,因为我认为更清楚,但无论你想把它们放在哪个顺序取决于你.此外,它们周围的括号是不必要的(但很好),因为它+具有更高的优先级,.
编辑2:三行代码不做同样的事情,但在这种情况下,它们都会产生相同的结果.谢谢你抓住我.