为什么substring不是C标准库的一部分?

时间:2011-09-13 17:51:35

标签: c substring substr

我知道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)

6 个答案:

答案 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)

你有strcpystrncpy。还不够吗?使用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;
}