0

我被要求在不使用库和指针的情况下从

到目前为止我有这个,但不知何故它不起作用:

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

输出:

一个

4

4 回答 4

2

不知何故它不起作用

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

细微改进的细节:

constinconst char b[]暗示b引用此函数不应尝试更改的数据。这 1) 允许这个函数连接b它应该是一个const char []2) 允许一个弱编译器可能看不到的优化。

size_t比可能比 int. _ 是字符串长度和数组大小的“正确大小”类型。OP(原始海报)确实有“不使用库”并且来自库,因此代码可以使用或更好地作为替代方案。INT_MAXsize_tsize_tunsignedunsigned long

于 2019-01-26T15:11:15.397 回答
2

出于你的问题,你不断地计算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的其余部分可能缺少空字符
  • 在您错过的副本之后添加空字符
于 2019-01-26T12:39:31.010 回答
1

这一行:

a[strlen(a) + i + 1] = b[i];

将字符写入比您想要的位置更远的位置。

在您的示例中调用时,您的例程将通过ab具有以下内容:

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 + 1strlen(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;
于 2019-01-26T15:30:29.677 回答
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.
于 2019-01-26T12:34:14.383 回答