所以我正在通过“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;
}
如果有人看到任何裁员/不必要的剩余代码,可以/应该删除,请告诉我。我认识到尽可能简洁的好处。
答案 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不提供现代语言所做的保护。您有责任确保保持在数组的范围内,初始化变量,并正确分配和释放内存。忽视这些事情会导致隐藏的错误,需要花费数小时才能找到,而且大多数情况下这些错误都不会马上出现。