I am on MacOS 11.6.1 and want to append a character to a string and copied the following from there: https://www.geeksforgeeks.org/how-to-append-a-character-to-a-string-in-c/
I am supposed to have the following ouptut:
Original String: Geek
Character to be appended: s
Appended String: Geeks
but only got the following one (with the last line missing)
Original String: Geek
Character to be appended: s
What am I doing wrong?
Here is the code
// C program to Append a Character to a String
#include <stdio.h>
#include <string.h>
int main()
{
// declare and initialize string
char str[6] = "Geek";
// declare and initialize char
char ch = 's';
// print string
printf("Original String: %s\n", str);
printf("Character to be appended: %c\n", ch);
// append ch to str
strncat(str, &ch, 1);
// print string
printf("Appended String: %s\n", str);
return 0;
}
CodePudding user response:
This is a bug in strncat
, specifically in the __builtin___strn_chk
routine used to implement it. Consider this extract of the code in the question:
char str[6] = "Geek";
char ch = 's';
strncat(str, &ch, 1);
As it happens, the compiler puts ch
immediately before str
in memory. Examining the assembly output of compilation shows strncat
is implemented with a call to __builtin___strn_chk
. Stepping through __builtin___strn_chk
in a debugger shows it calls __chk_overlap
to check whether the source and destination buffers overlap. For this call, it passes the address of str
with a length of six (the four characters in it plus the new character to be concatenated and a terminating null character after that) and the address of ch
with a length of two.
This length of two is incorrect; strncat
or __builtin___strn_chk
should take only one character from ch
. This is a mistake in __builtin___strn_chk
; it should pass a length of 1, not 2. __chk_overlap
correctly determines the buffers it was passed overlap and generates a trap.
This can be reliably reproduced with:
#include <stdio.h>
#include <string.h>
int main(void)
{
char buffer[] = "xabc\0\0";
strncat(buffer 1, buffer, 1);
}
__builtin___strncat_chk
is used because <string.h>
includes a header secure/_string.h
which defines strncat
as a macro:
#define strncat(dest, ...) \
__builtin___strncat_chk (dest, __VA_ARGS__, __darwin_obsz (dest))
So we can work around the bug by replacing strncat
with (strncat)
, which forces the strncat
function to be used instead of the macro. One could also use #undef strncat
after including <string.h>
.
CodePudding user response:
Ok, following the comment of Some programmer dude and Eric Postpischil and using strcpy() instead of strncat I could solve the problem:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[6] = "Geek";
char ch = 's';
size_t lenstr = strlen(str);
char *str2 = malloc(lenstr 1 1);
strcpy(str2, str);
str2[lenstr] = ch;
str2[lenstr 1] = '\0';
printf("Original String: %s\n", str);
printf("Character to be appended: %c\n", ch);
printf("Appended String: %s\n", str2);
return 0;
}