问题
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 bea[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