Building strcat without the library and without pointers

老子叫甜甜 提交于 2019-12-13 04:22:50

问题


I have been asked to build the strcat from string.h without using the library and pointers.

I have this so far but somehow it doesn't work:

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

Output:


回答1:


somehow it doesn't work

a[strlen(a) + i + 1] = b[i]; appends characters after a's null character.

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") will populate a as 'a', 'b', '\0', 'c', 'd'.

Printing that with printf("%s", a); only prints 'a', 'b'.


To fix, code needs to append in the right position, yet this overwrites the original a null character. Thus calls to strlen(a) are bad.

Instead, and to improve efficiency, do not call strlen() repeatedly.

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

Details of subtle improvements:

const in const char b[] implies b references data that this function should not attempt to change. This 1) allows this function to concatenate b should it be a const char [] 2) Allows optimizations a weak compiler may not see.

size_t is better than int for long strings which could be longer than INT_MAX. size_t is the "right size" type for string lengths and array sizing. OP (Original Poster) did have "without using the library" and size_t is from the library, so code could use unsigned or better unsigned long as alternatives.




回答2:


out of your problems you continuously compute strlen for nothing hoping the compiler will optimize, you can do that :

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

Execution :

azertyu

Note that char a[] for a parameter is exactly char *, without pointers is false ;-)


and to point to the problems in your code as requested by Eric Postpischil :

  • a[strlen(a) + i + 1] writes 1 character after the right position, must be a[strlen(a) + 1] = 0; a[strlen(a)] = b[j];. In a way it is a chance else you will write more far after the end because strlen will not returns the initial length of a but an undefined value because of the probable missing null character in the rest of a
  • after the copy you miss to add the null character



回答3:


This line:

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

writes characters one position further than you want.

When called in your example, your routine is passed a and b with these contents:

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

You want to produce this result:

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

However, since your code writes to a[strlen(a) + i + 1], it writes the first character to a[strlen(a) + 0 + 1], which is a[4]. You want it in a[3]. You could change strlen(a) + i + 1 to strlen(a) + i, but then, when you have written the first character, you will have overwritten the null terminating character, and strlen will not work to find the length anymore. To fix this, you can remember the length of a before entering the loop. Consider this code:

int i = 0;
int LengthOfA = strlen(a);
for (i = 0; i < strlen(b); ++i)
{
    a[LengthOfA + i] = b[i];
}

That will write the characters to the correct place.

However, it does not put a null terminating character at the end of a. To do that, we can put another statement after the loop:

a[LengthOfA + i] = 0;

At that point, your routine will work for normal situations. However, there are two more improvements we can make.

First, instead of using int for lengths and indices, we can use size_t. In C, the width of int is flexible, and size_t is provided as a good type to use when dealing with sizes of objects. To use it, first use #include <stddef.h> to get its definition. Then your code can be:

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;

Second, your code nominally calculates strlen(b) in every iteration. This is wasteful. It is preferable to calculate the length once and remember it:

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;



回答4:


You are not overwriting the first string null(\0) terminator

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

should be

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.


来源:https://stackoverflow.com/questions/54378372/building-strcat-without-the-library-and-without-pointers

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!