我知道C是故意的,但我很好奇为什么像子串函数这样普通的东西不包含在< string.h>中。
难道没有一种“足够正确”的方式吗?域特定要求太多?任何人都可以放弃任何光明吗?
顺便说一句,这是我在经过一番研究后提出的子串函数。 编辑:我根据评论做了一些更新。void substr (char *outStr, const char *inpStr, int startPos, size_t strLen) {
/* Cannot do anything with NULL. */
if (inpStr == NULL || outStr == NULL) return;
size_t len = strlen (inpStr);
/* All negative positions to go from end, and cannot
start before start of string, force to start. */
if (startPos < 0) {
startPos = len + startPos;
}
if (startPos < 0) {
startPos = 0;
}
/* Force negative lengths to zero and cannot
start after end of string, force to end. */
if ((size_t)startPos > len) {
startPos = len;
}
len = strlen (&inpStr[startPos]);
/* Adjust length if source string too short. */
if (strLen > len) {
strLen = len;
}
/* Copy string section */
memcpy(outStr, inpStr+startPos, strLen);
outStr[strLen] = '\0';
}
编辑:根据r的评论,我也提出了这个内容。你可以自己做支票了!
#define substr(dest, src, startPos, strLen) snprintf(dest, BUFF_SIZE, "%.*s", strLen, src+startPos)
答案 0 :(得分:6)
基本的标准库功能不会给昂贵的安全检查带来负担,而是将它们留给用户。您在实施中执行的大多数安全检查都是昂贵的:在这种基本库函数中完全不可接受。这是C,而不是Java。
一旦你从图片中得到一些检查,“substrung”函数归结为普通strlcpy
。即忽略startPos
上的安全检查,您需要做的只是
char *substr(const char *inpStr, char *outStr, size_t startPos, size_t strLen) {
strlcpy(outStr, inpStr + startPos, strLen);
return outStr;
}
虽然strlcpy
不是标准库的一部分,但它可以粗略地替换为[misused] strncpy
。再次,忽略startPos
上的安全检查,您需要做的就是
char *substr(const char *inpStr, char *outStr, size_t startPos, size_t strLen) {
strncpy(outStr, inpStr + startPos, strLen);
outStr[strLen] = '\0';
return outStr;
}
具有讽刺意味的是,在您的代码中strncpy
以同样的方式被滥用。最重要的是,许多安全检查是您选择签名类型(int
)来表示索引的直接结果,而正确的类型将是无符号类型(size_t
)。
答案 1 :(得分:3)
也许是因为它是一个单行:
snprintf(dest, dest_size, "%.*s", sub_len, src+sub_start);
答案 2 :(得分:2)
你有strcpy
和strncpy
。还不够吗?使用strcpy
,您可以模拟从字符到结尾的子字符串,使用strncpy
,您可以模拟字符中的子字符串以获取多个字符(您只需要记住在{0}处添加\0
字符串的结尾)。 strncpy
甚至比C#等价物更好,因为你可以超出子串的长度并且它不会抛出错误(如果你在dest中分配了足够的空间,你可以做strncpy(dest, src, 1000)
即使src很长1.在C#中你不能。)
如评论中所述,您甚至可以使用memcpy
,但请记住始终在字符串的末尾添加\0
,并且您必须知道要复制的字符数(因此您必须知道< strong>完全 src子字符串的长度)如果你想重构你的代码以使用wchar_t并且它不是类型安全的那一天,它使用起来有点复杂(因为它接受void *而不是char * )。所有这些都可以换取strncpy
答案 3 :(得分:0)
这是你想要的轻量级版本。避免冗余的strlen调用,并保证目标缓冲区上的空终止(strncpy不会这样做)。
void substr(char* pszSrc, int start, int N, char* pszDst, int lenDest)
{
const char* psz = pszSrc + start;
int x = 0;
while ((x < N) && (x < lenDest))
{
char ch = psz[x];
pszDst[x] = ch;
x++;
if (ch == '\0')
{
return;
}
}
// guarantee null termination
if (x > 0)
{
pszDest[x-1] = 0;
}
}
Example:
char *pszLongString = "This is a long string";
char szSub[10];
substr(pszLongString, 0, 4, szSub, 10); // copies "long" into szSub and includes the null char
因此,虽然C中没有正式的子字符串函数,但C ++字符串类通常有这样的方法:
#include <string>
...
std::string str;
std::string strSub;
str = "This is a long string";
strSub = str.substr(10, 4); // "long"
printf("%s\n", strSub.c_str());
答案 4 :(得分:0)
在C语言中,你有一个函数,它通过指针从字符串返回一个符号子集: strstr 。
char *ptr;
char string1[] = "Hello World";
char string2[] = "World";
ptr = strstr(string1, string2)
* ptr将指向第一个字符出现。
BTW你没有写一个函数,而是一个过程,ANSI字符串函数:string.h
答案 5 :(得分:-1)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* substr(const char *string, size_t from, size_t to);
int main(int argc, char *argv[])
{
char *string = argv[1];
const char *substring = substr(string,6,80);
printf("string is [%s] substring is [%s]\n",string,substring);
return 0;
}
const char* substr(const char *string, size_t from, size_t to)
{
if (to <= from)
return NULL;
if (from >= to)
return NULL;
if (string == NULL)
return NULL;
if (strlen(string) == 0)
return NULL;
if (from < 0)
from = 0;
if (to > strlen(string))
to = strlen(string);
char *substring = malloc(sizeof(char) * ((to-from)+1));
size_t index;
for (index = 0; from < to; from++, index++)
substring[index] = string[from];
substring[index] = '\0';
return substring;
}