【问题标题】:How to write C string functions: strncpy , strncat , and strncmp如何编写 C 字符串函数:strncpy、strncat 和 strncmp
【发布时间】:2011-01-01 02:27:33
【问题描述】:

我正在解决这个 K&R 练习:

编写库函数 strncpy 、 strncat 和 strncmp 的版本,它们最多对其参数字符串的前 n 个字符进行操作。例如, strncpy(s,t,n) 最多将 t 的 n 个字符复制到 s 。完整的描述在附录 B 中。

所以我在徘徊,如果有一个包含这些字符串函数的源代码的网站,所以我可以检查我是否做错了什么。

这些是我写的版本:如果你能告诉我我是否在功能中有一些错误或者我应该添加/更正/改进的东西,我将不胜感激!

int strncmp(char *s, char *t, int n)
{

     if(strlen(s) == strlen(t)) {

         while(*s == *t && *s && n) 
            n--, s++, t++;

         if(!n) 
             return 0; /* same length and same characters */
         else 
             return 1; /* same length, doesnt has the same characters */         
     }
     else
        return strlen(s) - strlen(t);
}

char *strncpy(char *s, char *t, int n)
{
     while(n-- && *s) {
        *s = *t;
        s++, t++;
     }

     if(strlen(t) < n)
        *s = '\0';

     return s;
}

char *strncat2(char *s, char *t, int n)
{
     while(*s)
       s++;

     while(n-- && *t) 
       *s = *t, s++, t++;

     *s = '\0';
     return s;
}

【问题讨论】:

    标签: c string function


    【解决方案1】:

    快速浏览似乎至少可以发现几个问题:

    • 在 strncmp 中:输入的 strlen() 调用无效。它们不必以空值终止。此外,根据相等性,返回值应为 0。
    • strncpy:我相信库版本用 \0 填充字符串到末尾。

    【讨论】:

    • +1,你是对的:strncpy()0s 填充目的地。
    【解决方案2】:

    当然,有很多 strncmp 和朋友的开源实现(例如 strncmp here),但它们不一定能帮助你。

    例如,您的 strncmp 只是实现了错误的算法:不是较短的字符串总是“小于”较长的字符串的情况,例如,"z"不是 小于"aa" - 所以你不能只比较长度。

    您的strncpy 正在检查*s,而应该检查*t,以及其他问题。

    查看替代的开源实现对诊断您的错误没有多大帮助:对您的代码进行同行评审,当您将其发布到 SO 时,可能会有更多帮助;-)

    【讨论】:

      【解决方案3】:

      Google 代码搜索非常适合查找标准函数的实现 :) 例如strncpy:

      http://www.google.com/codesearch/p?hl=en#XAzRy8oK4zA/libc/string/strncpy.c&q=strncpy&sa=N&cd=1&ct=rc

      【讨论】:

        【解决方案4】:

        有关解决方案,请参阅CLC Wiki page

        现在一些关于你的代码的 cmets:

        对于strncmp

        if(strlen(s) == strlen(t)) {
        

        您不需要此检查。 strlen() 遍历字符串,因此如果长度相等,您将处理两次字符串。这可能会变得昂贵。一般来说,像这样可以在任何程序中大量调用的低级函数应该是高效的(尽管过早的优化是万恶之源!)。此外,如果长度不相等,您将再次为两个字符串调用strlen()。除了昂贵之外,它也是错误的,但我们稍后会谈到。关于您的while 循环:

        while(*s == *t && *s && n) 
            n--, s++, t++;
        

        为什么要滥用逗号运算符?我会将上面的内容简化并写成(未经测试,毕竟这是正在解决的一个练习!):

        while (*s && *t && *s == *t && n--) {
            s++;
            t++;
        }
        if (!n) return 0;
        else return *s - *t;
        

        您的返回值是错误的。 strncmp() 应返回 0、小于 0 或大于 0,具体取决于第一个字符串的第一个 n 字符比较等于、小于还是大于(按字典顺序)第二个字符串。

        同样,您应该更改 strncpy()strncat2() 函数。我没有详细研究这两个,但由于这是一个练习,你可能还是想自己进行更改。

        【讨论】:

        • 按字典顺序 - 这是否意味着减去它们的 ASCII 值?
        • 不,这里的图片中没有 ASCII。如果字符集是'a' > 'b',那么strcmp("a", "b") 将返回一个大于0 的数字,这可能会令人惊讶。字典顺序是“字典顺序”,但使用特定于平台的字符编码。如果您需要依赖字符串的相对顺序,strcmp() 可能不是最好的方法(除非您确定您使用的是“健全的”系统!)。
        • 通常会像我对字符串比较函数一样执行“return *s - *t;”,但标准仅将返回值指定为 0、>0 和
        • 您的回报比较了错误的两个值:“a1”、“b1”。在 *s = 'a' 和 *t = 'b' 的路上。它们不相等,while 中断 s 和 t 递增,返回测试 '1' - '1'。
        • 嗯。谢谢!我修好了它。正如我所提到的,上面的代码未经测试。 :-)
        【解决方案5】:

        供参考:

        char* strncpy(char* s, const char* t, size_t n)
        {
            char* ret = s; // need to return this
            while (n-- && *s++ = *t++)
                 ;
            if (n) *s = 0;
            return ret;
        }
        
        // be lazy, there's no reason to write the copy part of strncpy and strncat twice.
        char* strncat(char* s, const char* t, size_t n)
        {
             char *ret = s;
             strncpy(s+strlen(s), t, n);
        //
        //   // if you don't want to call strlen, you can do this
        //   while (*s++) ;
        //   strncpy(s, t, n);
        //
             return ret;
        }
        
        int strncmp(const char* s, const char* t, size_t n)
        {
            while (n-- && *s == *t) {
                  ++s;
                  ++t;
            }
            if (n) return *s - *t;
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-04-19
          • 1970-01-01
          • 2013-04-16
          • 1970-01-01
          • 2013-05-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多