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

问题描述 投票:2回答:4

所以我正在通过“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;
}

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

c string malloc concatenation
4个回答
4
投票

您的代码有很多问题:

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

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

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终止它。


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

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


还有一个名为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
投票

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

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

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


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));

请注意,上面的行分配内存并设置'comboString'指向该内存。但是,分配了多少内存?

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

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

   concatenated(array1, array2);

上面这一行的意图是array1 [“你是男人”]和array2 [“Now Dog!”]将被连接起来形成一个新的字符串[“你是那个男人现在的狗!”],它将被放置在已分配的内存中并返回给调用者。

不幸的是,这里没有捕获包含字符串的返回内存。例如,上面的行应该是:

   comboString = concatenated(array1, array2);

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

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

以及全局变量:

   int ctrtotal;

以及后来的参考:

   ctrtotal = (ctr2 + ctr + 2);

也许所有这3行都应删除?

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

   puts(comboString);
   free(comboString);

   return 0;
}

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

请注意,'* array3'现在是一个已定义的指针,但它并未指向任何特定的指针。

   int ctr;
   int ctr2;

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

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

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

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

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

   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;
   }

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以找到'\ 0',然后一旦发现从该索引中复制array1,替换'\ 0'。这在这里工作正常,因为为array3分配的内存块将被清零**因为您的程序尚未释放任何块。但是,在运行时间较长的程序中,最终可能会出现一个不以'\ 0'开头的块。您可能最终破坏堆,获得段错误等。

要解决这个问题,你应该使用strcpy,array3[0] = '\0',*array3 = '\0'

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.