#define str(n) n
puts(str(hello));
The above piece of code is working fine in c but the below mentioned code is not giving any output in the console
#define str(n) #n
char* name="David";
puts(strcat(str(hello ),name));
can anyone help me to figure out what is wrong with the second piece of code and please let me know in which cases we can use '#' operator in c and when we shouldn't use that ???
CodePudding user response:
The issue with the code presented in the question doesn't have anything to do with the stringification operator in particular. Rather, your use of strcat()
is invalid.
Remember that stringification produces a string literal, so this ...
#define str(n) #n char* name="David"; puts(strcat(str(hello ),name));
... is equivalent to this ...
#define str(n) #n
char* name="David";
puts(strcat("hello ",name));
strcat
attempts to write data into the array specified by the first argument, starting at the position of the string terminator. There are at least three preconditions:
- The destination array must be modifiable.
- The destination array must contain a string terminator.
- There must be enough unused space at the end of the array to accommodate the additional characters.
A string literal is not modifiable and does not contain any extra space, so conditions (1) and (3) are never met when the first argument to strcat()
is a string literal. Undefined behavior results from such a call.
CodePudding user response:
str(hello)
or str(hello )
is the string literal "hello"
.
In memory this is 'h'
, followed by 'e'
, ..., followed by 'o'
, followed by the null character (a byte with all bits set to 0, typically represented by '\0'
):
'h' 'e' 'l' 'l' 'o' '\0'
When you apply strcat
like that, it tries to replace '\0'
with a 'D'
'h' 'e' 'l' 'l' 'o' 'D'
then make the subsequent bytes 'a'
, 'v'
, ..., 'd'
, '\0'
:
'h' 'e' 'l' 'l' 'o' 'D' 'a' 'v' 'i' 'd' '\0'
Two problems with this:
- bytes after the
'\0'
have probably not been allocated to you! - it is considered undefined behavior if (quote from C99 Standard)
[t]he program attempts to modify a string literal.
For reference, from the C99 Standard, the strcat
function has the prototype
#include <string.h>
char *strcat(char * restrict s1, const char * restrict s2);
and description
The strcat function appends a copy of the string pointed to by s2 (including the terminating null character) to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1. If copying takes place between objects that overlap, the behavior is undefined.
You should place "Hello"
in a char
array large enough to also store the name that you want to concatenate if you want your desired output. For example,
#include <stdio.h>
#include <string.h>
#define STRINGIZE(x) #x
int main(void) {
char *name = "David";
char a[12] = STRINGIZE(Hello) " ";
puts(strcat(a, name));
return 0;
}
Output
Hello David
The character array, a
, has 12 elements so that it can contain all 5 characters in Hello
, the space character,
, all 5 characters in David
, plus the null character.
Note that 12 is the minimum length for the array a
to hold the string "Hello David"
(11 characters plus 1 for the null character). You will need a
to be larger if the names will be larger. If you know, from your input, the largest possible name, then you can make a
large enough to hold the largest possible name (plus Hello
plus the null character).
Alternatively, first, you decide on some arbitrary length for the array a
. Then, you use the strncat
function in a safe way such that strncat
only writes to elements of the array a
. The strncat
function essentially does the same thing as strcat
except it allows you to specify a third argument which represents the maximum number of characters from s2
to append to s1
(the null character that strncat
automatically appends to the result of the concatenation is not included in this number). In the case that you specify a third argument that instructs strncat
to never write past the end of the array a
, if the name is too long, the full name will not be stored in a
, but this is better and safer than trying to write past the end of the array, which is what strcat
would have attempted.
Again, for reference (from C99 Standard), the strncat
function has the prototype
#include <string.h>
char *strncat(char * restrict s1, const char * restrict s2,
size_t n);
and description
The strncat function appends not more than n characters (a null character and characters that follow it are not appended) from the array pointed to by s2 to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1. A terminating null character is always appended to the result. If copying takes place between objects that overlap, the behavior is undefined.