【问题标题】:implementing strcat without changing the inputs在不改变输入的情况下实现 strcat
【发布时间】:2018-09-22 16:11:45
【问题描述】:

我想创建一个 C strcat 函数的实现来连接 2 个字符串而不修改任一输入字符串。这就是我目前所拥有的

char *my_strcat(char* s1, char* s2)
{
    char* p = malloc(strlen(s1) + strlen(s2) + 1);

    while (*s1 != '\0')
        *p++ = *s1++;

    while (*s2 != '\0')
        *p++ = *s2++;

    *p++ = '\0';

    return p;
}

我想用 s1 和 s2 中的所有字符填充 p,但是这段代码什么也不返回。可以使用一些帮助。

【问题讨论】:

  • 一点点rubber duck debugging 应该可以帮助您了解您的问题。
  • 橡皮鸭调试...或使用调试器单步调试代码。两者都应该指出问题所在 - 在递增后返回“p”,而不是 malloc() 返回的原始“p”。另外:HostileFork 对const 的建议绝对是个好主意。
  • char *my_strcat(char* s1, char* s2) { if (char* p = (char*)malloc(strlen(s1) + strlen(s2) + 1)) { char c, *sz = p; do { *p++ = c = *s1++; } while (c); p--; do { *p++ = c = *s2++; } while (c); return sz; } return 0; }
  • 代码有什么问题?看着它,它应该连接两个字符串,而且你也不要改变输入。那么,有什么问题呢?

标签: c strcat


【解决方案1】:

因为您在串联过程中增加了p

*p++ = *s1++; 

*p++ = '\0'; //don't do p++ here

p 将指向连接后超出其分配的内存。

只需添加一个指向p 开头的虚拟指针并返回它。

请在下面找到示例代码。

char *my_strcat(const char* s1,const char* s2)
{
  char *p = malloc(strlen(s1) + strlen(s2) + 1);

  char *start = p;
  if (p != NULL)
  {
       while (*s1 != '\0')
       *p++ = *s1++;
       while (*s2 != '\0')
       *p++ = *s2++;
      *p = '\0';
 }

  return start;
}

【讨论】:

  • 在这样一个基本函数中多次返回 - 不太好
【解决方案2】:

我想用 s1 和 s2 中的所有字符填充 p,但是这段代码什么也不返回。可以使用一些帮助。

您从一个 malloc 的指针开始,然后随着您的前进而递增 p

在例程结束时,您希望这个 p 指向什么?

使用这种方法,你需要记住你已经 malloc 的指针并返回它。

您可能会发现,如果您给变量起更有意义的名称 - 至少在开始时 - 您可以更好地推理它。

此外,由于您没有修改输入,因此应将它们标记为 const。这可以更好地传达您的意图 - 并为您实际尝试完成的内容提供编译时检查。如果您要重用像 strcat 这样具有现有期望的名称,这一点尤其重要。 (重用该名称是您可能会重新考虑的另一件事。)

char *my_strcat(const char* s1, const char* s2)
{
  char* result = malloc(strlen(s1) + strlen(s2) + 1);

  // To satisfy @P__J__ I will expand on this by saying that
  // Your interface should document what the behavior is when
  // malloc fails and `result` is NULL.  Depending on the
  // overall needs of your program, this might mean returning
  // NULL from my_strcat itself, terminating the program, etc.
  // Read up on memory management in other questions.

  char* dest = result;
  while (*s1 != '\0')
     *dest++ = *s1++;
  while (*s2 != '\0')
      *dest++ = *s2++;
  *dest++ = '\0';
  return result;
}

【讨论】:

  • @P__J__ 有效提出,但不能在一个问题中解决所有问题。当字符串长度足够长以在求和时溢出 size_t 时该怎么办?响应 malloc 做什么与您的整个应用程序在这种情况下做什么的世界观有关。例如如果 malloc 返回 null,则不一定能通过返回 null 来传播关注点;可能应该使用 malloc 包装器,它在内存耗尽时终止程序。如此有效,但在关于 stackoverflow 的问答中,人们试图挑选与主题相关的要点,问题与 malloc 无关。
  • 但这在 OPs 代码中是个大问题。您不应该将错误的代码作为示例,因为初学者会阅读答案。
  • @P__J__ 好吧,“巨大”可能是您的观点。但是编写能够在内存耗尽时优雅运行的程序只是评估程序适用性的一个轴。并不是每一项任务都证明努力是合理的——也不是让例程返回 NULL 必然“解决”问题。你没有回应我的数字溢出示例,但溢出也是真实的,不是吗?我的立场是,写一篇关于 malloc 异常处理的不同选项的文章本身就是一个主题,并且与所提出的问题相切。
【解决方案3】:

您正在移动指针 *p 本身,因此即使数据被复制,它(指针 p)已经被放置在前面,所以这样做可以让另一个指向内存的指针这样做:

char *my_strcat(char* s1, char* s2)
{
     char* p = malloc(strlen(s1) + strlen(s2) + 1);
     char *c=p;    //RATHER THAN POINTER P, POINTER C WILL TRAVEL/MOVE
     while (*s1 != '\0')
          *(c++) = *(s1++);
     printf("%s\n\n",p);
     while (*s2 != '\0')
          *(c++) = *(s2++);
     *c = '\0';
     return p;
}

所以在这种情况下,指针p 仍然保持在其原始位置,指向内存空间的开头。

【讨论】:

  • *(c++) 中的括号不是惯用的 C,尽管它们是正确的。
  • 没有malloc 检查。错误的。 NULL 指针分配的可能性很大。
【解决方案4】:

另一个答案。这次没有明确的临时 char 指针来保存原始的。 const 正确类型 + malloc 检查。

对编译器优化器更友好:)

#include<stdio.h>
#include<stdlib.h>
#include <string.h>


static inline char *strcpys(char *dest, const char *src)
{
    while(*dest++ = *src++);
    return dest;
}

char *mystrcat(const char *str1, const char *str2)
{
    char *result = malloc(strlen(str1) + strlen(str2) + 1);

    if(result)
    {
        strcpys(strcpys(result, str1) - 1, str2);
    }
    return result;
}

int main()
{
    char *str1 = "12345";
    char *str2 = "ABCDE";
    char *dest;

    printf("%s + %s = %s\n", str1, str2, (dest = mystrcat(str1, str2)) ? dest : "malloc error");

    free(dest);
    return 0;
}

【讨论】:

  • 如果您想避免保存指针,您可以使用 indexed(ptr[i++]) 方法吗?虽然我喜欢你的答案,但它总是有点开箱即用:)
  • DV = 复仇一号?
  • 我没听懂你
  • @kiranBiradar 我没有评论你:) 别担心
  • 好的。(空格)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-18
  • 2016-08-06
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2011-04-13
相关资源
最近更新 更多