我被要求在不使用库和指针的情况下从string.h构建strcat 。
到目前为止我有这个,但不知何故它不起作用:
void strcatO(char a[], char b[])
{
int i = 0;
for(i = 0; i < strlen(b); ++i)
{
a[strlen(a) + i + 1] = b[i];
}
printf("%s", a);
}
输出:
我被要求在不使用库和指针的情况下从string.h构建strcat 。
到目前为止我有这个,但不知何故它不起作用:
void strcatO(char a[], char b[])
{
int i = 0;
for(i = 0; i < strlen(b); ++i)
{
a[strlen(a) + i + 1] = b[i];
}
printf("%s", a);
}
输出:
不知何故它不起作用
a[strlen(a) + i + 1] = b[i];
在' 的空字符之后 附加字符。a
void strcatO(char a[], char b[]) {
int i = 0;
for(i = 0; i < strlen(b); ++i) {
a[strlen(a) + i + 1] = b[i]; // Oops: appending position is off-by-one
}
printf("%s", a);
}
strcatO("ab", "cd")
将填充a
为'a'
, 'b'
, '\0'
, 'c'
, 'd'
.
printf("%s", a);
仅打印,打印'a'
。'b'
要修复,代码需要附加到正确的位置,但这会覆盖原始的a
null 字符。因此调用strlen(a)
是不好的。
相反,为了提高效率,不要strlen()
重复调用。
void strcatO(char a[], const char b[]) {
size_t ai = 0;
while (a[ai]) { // go to end of a
ai++;
}
size_t bi = 0;
while (b[bi]) { // while not at the end of b ...
a[ai++] = b[bi++];
}
a[ai] = '\0';
printf("<%s>", a);
}
细微改进的细节:
const
inconst char b[]
暗示b
引用此函数不应尝试更改的数据。这 1) 允许这个函数连接b
它应该是一个const char []
2) 允许一个弱编译器可能看不到的优化。
size_t
比可能比 int
. _ 是字符串长度和数组大小的“正确大小”类型。OP(原始海报)确实有“不使用库”并且来自库,因此代码可以使用或更好地作为替代方案。INT_MAX
size_t
size_t
unsigned
unsigned long
出于你的问题,你不断地计算strlen希望编译器会优化,你可以这样做:
#include <stdio.h>
#include <string.h>
void strcatO(char a[], char b[])
{
size_t i = strlen(a);
size_t j;
for (j = 0; b[j] != 0; ++j)
{
a[i++] = b[j];
}
a[i] = 0;
printf("%s\n", a);
}
int main()
{
char a[20] = "aze";
char b[] = "rtyu";
strcatO(a,b);
return 0;
}
执行 :
azertyu
请注意,char a[]
对于一个参数是完全正确的char *
,没有指针是错误的;-)
并按照 Eric Postpischil 的要求指出代码中的问题:
a[strlen(a) + i + 1]
在正确位置后写入 1 个字符,必须是a[strlen(a) + 1] = 0; a[strlen(a)] = b[j];
. 在某种程度上,您可能会在结束后写得更远,因为strlen不会返回 a 的初始长度而是一个未定义的值,因为a的其余部分可能缺少空字符这一行:
a[strlen(a) + i + 1] = b[i];
将字符写入比您想要的位置更远的位置。
在您的示例中调用时,您的例程将通过a
并b
具有以下内容:
a[0] = 'e'
a[1] = 'g'
a[2] = 'g'
a[3] = 0
b[0] = 's'
b[1] = 'a'
b[2] = 'm'
b[3] = 'p'
b[4] = 'l'
b[5] = 'e'
b[6] = 0
你想产生这个结果:
a[0] = 'e'
a[1] = 'g'
a[2] = 'g'
a[3] = 's'
a[4] = 'a'
a[5] = 'm'
a[6] = 'p'
a[7] = 'l'
a[8] = 'e'
a[9] = 0
但是,由于您的代码写入a[strlen(a) + i + 1]
,它将第一个字符写入a[strlen(a) + 0 + 1]
,即a[4]
。你想要它在a[3]
. 您可以更改strlen(a) + i + 1
为strlen(a) + i
,但是,当您写入第一个字符时,您将覆盖空终止字符,并且strlen
无法再查找长度。a
要解决此问题,您可以记住进入循环之前的长度。考虑这段代码:
int i = 0;
int LengthOfA = strlen(a);
for (i = 0; i < strlen(b); ++i)
{
a[LengthOfA + i] = b[i];
}
这会将字符写入正确的位置。
但是,它不会在a
. 为此,我们可以在循环之后放置另一条语句:
a[LengthOfA + i] = 0;
那时,您的例行程序将适用于正常情况。但是,我们还可以进行另外两项改进。
首先,int
我们可以使用size_t
. 在 C 中,宽度int
是灵活的,并且size_t
在处理对象的大小时作为一个很好的类型提供。要使用它,首先要使用它#include <stddef.h>
来获得它的定义。那么你的代码可以是:
size_t i = 0;
size_t LengthOfA = strlen(a);
for (i = 0; i < strlen(b); ++i)
{
a[LengthOfA + i] = b[i];
}
a[LengthOfA + i] = 0;
其次,您的代码名义上strlen(b)
会在每次迭代中进行计算。这是浪费。最好计算一次长度并记住它:
size_t i = 0;
size_t LengthOfA = strlen(a);
size_t LengthOfB = strlen(b);
for (i = 0; i < LengthOfB; ++i)
{
a[LengthOfA + i] = b[i];
}
a[LengthOfA + i] = 0;
您没有覆盖第一个字符串null ( \0
) 终止符
a[strlen(a) + i + 1] = b[i];
应该
int len = strlen(a);
for(i = 0; i < strlen(b); ++i)
{
a[len + i] = b[i];
}
a[len+i] = '\0'; //Finally null terminate the new string.