malloc()将2个字符串连接成第三个字符串 - 编译后崩溃

时间:2014-05-13 21:36:32

标签: c string malloc concatenation

所以我正在通过“Sams教你自己C编程一天一小时,第七版”第10课练习7要求“编写一个接受两个字符串的函数。使用malloc()函数分配足够的内存在连接(链接)之后保持两个字符串。返回指向这个新字符串的指针。“

我确信有更多优雅的方式来解决这个问题,而不是我在下面尝试的方法。我最感兴趣的是为什么我的解决方案不起作用。我只学习了几个月的C并且没有重要的编程背景。请让我知道为什么这会在编译时崩溃。我正在使用Win 7上的代码块与GNU GCC编译器,如果这有所作为。谢谢:))

#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;

int main(void)
{
    char *comboString;
    char *array1 = "You\'re the man ";
    char *array2 = "Now Dog!";
    comboString = (char *)malloc(ctrtotal * sizeof(char));

    concatenated(array1, array2);

    if (comboString == NULL)
    {
        puts("Memory error");
        exit(1);
    }
    puts(comboString);
    free(comboString);

    return 0;
}

char * concatenated(char array1[], char array2[])
{
    char *array3;
    int ctr;
    int ctr2;

    for (ctr = 0; array1[ctr] != '\0'; ctr++)
        array3[ctr] = array1[ctr];

    ctr2 = ctr;

    for (ctr = 0; array2[ctr] != '\0'; ctr++)
    {
        array3[ctr2 + ctr] = array2[ctr];
    }

    array3[ctr2 + ctr + 1] = '\0';
    ctrtotal = (ctr2 + ctr + 2);

    return array3;
}

感谢您的帮助。在审核了每个人对我的错误的反馈之后,我将代码修改为以下内容:

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

char * concatenated(char array1[], char array2[]);

int main(void)
{
    char *array1 = "Testing Testing One Two ";
    char *array2 = "Three.  Finally, not crashing the mem o ry.";
    char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));

    comboString = concatenated(array1, array2);

    if (comboString == NULL)
    {
        puts("Memory error");
        exit(1);
    }

    puts(comboString);
    free(comboString);

    return 0;
}

char * concatenated(char array1[], char array2[])
{
    char *array3;
    array3 = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) );

    strcat(array3, array1);
    strcat(array3, array2);

    return array3;
}

如果有人看到任何裁员/不必要的剩余代码,可以/应该删除,请告诉我。我认识到尽可能简洁的好处。

4 个答案:

答案 0 :(得分:4)

您的代码存在许多问题:

  • int ctrtotal永远不会被初始化,因此您malloc为0字节
  • concatenated()正在将字符复制到未初始化 array3。该指针应指向malloc d缓冲区。
  • 如果concatenated正在分配内存,那么main并不需要。相反,它应该使用concatenated
  • 的结果

我不想给你完整的代码,让你错过这个学习机会。所以concatenated应该看起来像这样,在伪代码中:

count = length_of(string1) + length_of(string2) + 1
buffer = malloc(count)
copy string1 to buffer
copy string2 to buffer, after string1
set the last byte of buffer to '\0' (NUL)
return buffer

在C中,字符串表示为NUL-terminated array of characters。这就是我们分配一个额外字节并使用\0终止它的原因。


作为旁注,在处理字符串时,使用指针更容易,而不是将它们视为数组并通过索引访问它们。

这里有很多代码,但没有任何意义。我建议你先把这个程序写在纸上。然后,&#34;执行&#34;在你脑海中的程序,踩过每一行。如果你得到了一些你不了解的东西,那么你需要修复你的理解,或者你的错误代码。不要尝试编写看起来像其他代码的代码。


还有一个名为strcat的库函数,它可以使这项任务变得更加容易。看看你是否可以在这里弄清楚如何使用它。

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

                                                                                                    char *concatenate2(const char* s1, const char* s2);

                                                                                                    int main(void)
                                                                                                    {
                                                                                                        char *comboString;
                                                                                                        char *array1 = "You're the man ";
                                                                                                        char *array2 = "Now Dog!";

                                                                                                        comboString = concatenate2(array1, array2);

                                                                                                        if (comboString == NULL)
                                                                                                        {
                                                                                                            puts("Memory error");
                                                                                                            exit(1);
                                                                                                        }
                                                                                                        puts(comboString);
                                                                                                        free(comboString);

                                                                                                        return 0;
                                                                                                    }

                                                                                                    char *concatenate2(const char* s1, const char* s2)
                                                                                                    {
                                                                                                        char *result;

                                                                                                        result = malloc(strlen(s1) + strlen(s2) + 1);

                                                                                                        *result = '\0';

                                                                                                        strcat(result, s1);
                                                                                                        strcat(result, s2);

                                                                                                        return result;
                                                                                                    }

答案 1 :(得分:1)

你忘了为第三个连接的字符数组分配内存(在函数中) 你应该这样做:

char *array3;
array3 = (char *)malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) ); // +1 for '\0' character.

然后将第一个和第二个数组中的字符写入第三个。

答案 2 :(得分:1)

或许漫步问题代码是最好的。

#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;

请注意,上面的行声明ctrtotal是一个整数,但不指定整数的值。

int main(void)
{
   char *comboString;

   char *array1 = "You\'re the man ";
   char *array2 = "Now Dog!";
   comboString = (char *)malloc(ctrtotal * sizeof(char));

请注意,上面的行分配内存并设置&#39; comboString&#39;指着那个记忆。但是,分配了多少内存?

(ctrtotal [???] * sizeof(char)[1])

(??? * 1)的价值是多少?这是一个问题。

   concatenated(array1, array2);

上面一行的意图是array1 [&#34;你是男人&#34;]和array2 [&#34; Now Dog!&#34;]将加入形成一个新的字符串[&#34;你是现在的狗!&#34;],它将被放置在已分配的内存中并返回给调用者。

不幸的是,此处未捕获包含该字符串的返回内存。例如,上面的行应该是:

   comboString = concatenated(array1, array2);

虽然这是有道理的,但对于这一行,它引出了一条线的目的问题:

   comboString = (char *)malloc(ctrtotal * sizeof(char));

以及全局变量:

   int ctrtotal;

以及后来的参考文献:

   ctrtotal = (ctr2 + ctr + 2);

也许应该删除所有这三行?

   if (comboString == NULL)
   {
      puts("Memory error");
      exit(1);
   }

   puts(comboString);
   free(comboString);

   return 0;
}

 char * concatenated(char array1[], char array2[])
   {
   char *array3;

请注意&#39; * array3&#39;现在是一个已定义的指针,但它没有指向任何特定的指针。

   int ctr;
   int ctr2;

&#39; concatenated()&#39;的目的是将array1和array1连接到已分配的array3中。不幸的是,没有为array3分配内存。

下面,将修改array3指向的内存。由于array3没有指向任何特定的位置,因此这不安全。

在修改数组3所指向的内存之前,必须将array3指向可以安全修改字节的内存。我建议在这里插入以下代码:

   array3 = malloc(strlen(array1) + strlen(array2) + 1);

现在,array3指向分配的内存,大到足以容纳两个字符串加上字符串终止字符&#39; \ 0&#39;。

   for (ctr = 0; array1[ctr] != '\0'; ctr++)
      array3[ctr] = array1[ctr];

   ctr2 = ctr;

   for (ctr = 0; array2[ctr] != '\0'; ctr++)
   {
      array3[ctr2 + ctr] = array2[ctr];
   }

   array3[ctr2 + ctr + 1] = '\0';
   ctrtotal = (ctr2 + ctr + 2);

   return array3;
   }

答案 3 :(得分:0)

我正在回复您修改后的代码。它有一些错误。

...
char *array2 = "Three.  Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));

comboString = concatenated(array1, array2);
...

这里不需要malloc,实际上是代码中的错误。你正在分配一块内存,但是然后用指向调用concatenated.的指针替换指针comboString的值你丢失了指向main中分配的内存块的指针,因此永远无法释放它。虽然这不会是你现在拥有的代码中的一个问题,因为很快就会发生主要的返回,它可能会导致应用程序运行较长时间内存泄漏。

strcat(array3, array1);

这也是一个错误。 strcat将通过array3查找&#39; \ 0&#39;然后一旦发现从该索引中复制array1,替换&#39; \ 0&#39;。这在这里工作正常,因为为array3分配的内存块将被清零**因为您的程序尚未释放任何块。但是,在较长时间运行的程序中,您最终可能会遇到一个不以&#39; \ 0&#39;开头的块。你可能最终破坏你的堆,得到段错误等等。

要解决此问题,您应该使用strcpy,array3[0] = '\0',*array3 = '\0'

**当操作系统启动程序时,它会初始化它为零保留的内存段(这实际上不是必需的,但几乎在任何操作系统上都是如此)。当你的程序分配并释放内存时,你最终会得到不为零的值。请注意,未初始化的局部变量可能会出现相同的错误,例如:

int i;
for (; i < 10; i++);

每当存储i的运行时堆栈上的空间已经为0时,此循环将运行10次。

总的来说,外卖是要非常小心C中的数组和动态内存分配.C不提供现代语言所做的保护。您有责任确保保持在数组的范围内,初始化变量,并正确分配和释放内存。忽视这些事情会导致隐藏的错误,需要花费数小时才能找到,而且大多数情况下这些错误都不会马上出现。