Related
I'm new to c, and confused by string ending char '\0', should I allocate it?
for example, I want to store a string with a max length of 6;
If I use array, should I use char str[6] or char str[7]?
char as[3] = "abc";
printf("%s\n", as);
//seems no problem
If I use char pointer, should I use char *str = malloc(6) or char *str = malloc(7)?
For an array that is pre-initialized, you don't need to write a number in the brackets. You can just write
char str[] = "this is my string";
And the compiler will automatically calculate the number of bytes needed.
But for malloc, you must add 1. Ex:
char *strdup(const char *str)
{
char *ret = malloc(strlen(str) + 1);
strcpy(ret, str);
return ret;
}
You should be using string length + 1. In your case you must use 7 while declaring the char array.
The example you provided would have worked because of the undefined behaviour shown by printf().
In addition to stackptr's answer:
If you are planning to overwrite your array:
char str[30] = "abc";
...
strcpy(str, "Hello world"); /* This will overwrite the content of "str" */
... the length of the array must be the maximum length of the string plus 1.
In the example above you may write strings of up to 29 characters length to the array.
Note that the following definition:
char str[] = "abc";
... implicitly creates an array of 4 characters length so you are limit to 3 characters.
I'm working in C, and I have to concatenate a few things.
Right now I have this:
message = strcat("TEXT ", var);
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
Now if you have experience in C I'm sure you realize that this gives you a segmentation fault when you try to run it. So how do I work around that?
In C, "strings" are just plain char arrays. Therefore, you can't directly concatenate them with other "strings".
You can use the strcat function, which appends the string pointed to by src to the end of the string pointed to by dest:
char *strcat(char *dest, const char *src);
Here is an example from cplusplus.com:
char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");
For the first parameter, you need to provide the destination buffer itself. The destination buffer must be a char array buffer. E.g.: char buffer[1024];
Make sure that the first parameter has enough space to store what you're trying to copy into it. If available to you, it is safer to use functions like: strcpy_s and strcat_s where you explicitly have to specify the size of the destination buffer.
Note: A string literal cannot be used as a buffer, since it is a constant. Thus, you always have to allocate a char array for the buffer.
The return value of strcat can simply be ignored, it merely returns the same pointer as was passed in as the first argument. It is there for convenience, and allows you to chain the calls into one line of code:
strcat(strcat(str, foo), bar);
So your problem could be solved as follows:
char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);
Avoid using strcat in C code. The cleanest and, most importantly, the safest way is to use snprintf:
char buf[256];
snprintf(buf, sizeof(buf), "%s%s%s%s", str1, str2, str3, str4);
Some commenters raised an issue that the number of arguments may not match the format string and the code will still compile, but most compilers already issue a warning if this is the case.
Strings can also be concatenated at compile time.
#define SCHEMA "test"
#define TABLE "data"
const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry = // include comments in a string
" SELECT * " // get all fields
" FROM " SCHEMA "." TABLE /* the table */
" WHERE x = 1 " /* the filter */
;
Folks, use strncpy(), strncat(), or snprintf().
Exceeding your buffer space will trash whatever else follows in memory!
(And remember to allow space for the trailing null '\0' character!)
Also malloc and realloc are useful if you don't know ahead of time how many strings are being concatenated.
#include <stdio.h>
#include <string.h>
void example(const char *header, const char **words, size_t num_words)
{
size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
char *message = (char*) malloc(message_len);
strncat(message, header, message_len);
for(int i = 0; i < num_words; ++i)
{
message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
message = (char*) realloc(message, message_len);
strncat(strncat(message, ";", message_len), words[i], message_len);
}
puts(message);
free(message);
}
Best way to do it without having a limited buffer size is by using asprintf()
char* concat(const char* str1, const char* str2)
{
char* result;
asprintf(&result, "%s%s", str1, str2);
return result;
}
If you have experience in C you will notice that strings are only char arrays where the last character is a null character.
Now that is quite inconvenient as you have to find the last character in order to append something. strcat will do that for you.
So strcat searches through the first argument for a null character. Then it will replace this with the second argument's content (until that ends in a null).
Now let's go through your code:
message = strcat("TEXT " + var);
Here you are adding something to the pointer to the text "TEXT" (the type of "TEXT" is const char*. A pointer.).
That will usually not work. Also modifying the "TEXT" array will not work as it is usually placed in a constant segment.
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
That might work better, except that you are again trying to modify static texts. strcat is not allocating new memory for the result.
I would propose to do something like this instead:
sprintf(message2, "TEXT %s TEXT %s", foo, bar);
Read the documentation of sprintf to check for it's options.
And now an important point:
Ensure that the buffer has enough space to hold the text AND the null character. There are a couple of functions that can help you, e.g., strncat and special versions of printf that allocate the buffer for you.
Not ensuring the buffer size will lead to memory corruption and remotely exploitable bugs.
Do not forget to initialize the output buffer. The first argument to strcat must be a null terminated string with enough extra space allocated for the resulting string:
char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string );
// null_terminated_string has less than 1023 chars
As people pointed out string handling improved much. So you may want to learn how to use the C++ string library instead of C-style strings. However here is a solution in pure C
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void appendToHello(const char *s) {
const char *const hello = "hello ";
const size_t sLength = strlen(s);
const size_t helloLength = strlen(hello);
const size_t totalLength = sLength + helloLength;
char *const strBuf = malloc(totalLength + 1);
if (strBuf == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(strBuf, hello);
strcpy(strBuf + helloLength, s);
puts(strBuf);
free(strBuf);
}
int main (void) {
appendToHello("blah blah");
return 0;
}
I am not sure whether it is correct/safe but right now I could not find a better way to do this in ANSI C.
It is undefined behaviour to attempt to modify string literals, which is what something like:
strcat ("Hello, ", name);
will attempt to do. It will try to tack on the name string to the end of the string literal "Hello, ", which is not well defined.
Try something this. It achieves what you appear to be trying to do:
char message[1000];
strcpy (message, "TEXT ");
strcat (message, var);
This creates a buffer area that is allowed to be modified and then copies both the string literal and other text to it. Just be careful with buffer overflows. If you control the input data (or check it before-hand), it's fine to use fixed length buffers like I have.
Otherwise, you should use mitigation strategies such as allocating enough memory from the heap to ensure you can handle it. In other words, something like:
const static char TEXT[] = "TEXT ";
// Make *sure* you have enough space.
char *message = malloc (sizeof(TEXT) + strlen(var) + 1);
if (message == NULL)
handleOutOfMemoryIntelligently();
strcpy (message, TEXT);
strcat (message, var);
// Need to free message at some point after you're done with it.
The first argument of strcat() needs to be able to hold enough space for the concatenated string. So allocate a buffer with enough space to receive the result.
char bigEnough[64] = "";
strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);
/* and so on */
strcat() will concatenate the second argument with the first argument, and store the result in the first argument, the returned char* is simply this first argument, and only for your convenience.
You do not get a newly allocated string with the first and second argument concatenated, which I'd guess you expected based on your code.
You can write your own function that does the same thing as strcat() but that doesn't change anything:
#define MAX_STRING_LENGTH 1000
char *strcat_const(const char *str1,const char *str2){
static char buffer[MAX_STRING_LENGTH];
strncpy(buffer,str1,MAX_STRING_LENGTH);
if(strlen(str1) < MAX_STRING_LENGTH){
strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer));
}
buffer[MAX_STRING_LENGTH - 1] = '\0';
return buffer;
}
int main(int argc,char *argv[]){
printf("%s",strcat_const("Hello ","world")); //Prints "Hello world"
return 0;
}
If both strings together are more than 1000 characters long, it will cut the string at 1000 characters. You can change the value of MAX_STRING_LENGTH to suit your needs.
You are trying to copy a string into an address that is statically allocated. You need to cat into a buffer.
Specifically:
...snip...
destination
Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.
...snip...
http://www.cplusplus.com/reference/clibrary/cstring/strcat.html
There's an example here as well.
Assuming you have a char[fixed_size] rather than a char*, you can use a single, creative macro to do it all at once with a <<cout<<like ordering ("rather %s the disjointed %s\n", "than", "printf style format"). If you are working with embedded systems, this method will also allow you to leave out malloc and the large *printf family of functions like snprintf() (This keeps dietlibc from complaining about *printf too)
#include <unistd.h> //for the write example
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ \
char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \
const char *s, \
*a[] = { __VA_ARGS__,NULL}, \
**ss=a; \
while((s=*ss++)) \
while((*s)&&(++offset<(int)sizeof(buf))) \
*bp++=*s++; \
if (offset!=sizeof(buf))*bp=0; \
}while(0)
char buf[256];
int len=0;
strcpyALL(buf,len,
"The config file is in:\n\t",getenv("HOME"),"/.config/",argv[0],"/config.rc\n"
);
if (len<sizeof(buf))
write(1,buf,len); //outputs our message to stdout
else
write(2,"error\n",6);
//but we can keep adding on because we kept track of the length
//this allows printf-like buffering to minimize number of syscalls to write
//set len back to 0 if you don't want this behavior
strcpyALL(buf,len,"Thanks for using ",argv[0],"!\n");
if (len<sizeof(buf))
write(1,buf,len); //outputs both messages
else
write(2,"error\n",6);
Note 1, you typically wouldn't use argv[0] like this - just an example
Note 2, you can use any function that outputs a char*, including nonstandard functions like itoa() for converting integers to string types.
Note 3, if you are already using printf anywhere in your program there is no reason not to use snprintf(), since the compiled code would be larger (but inlined and significantly faster)
int main()
{
char input[100];
gets(input);
char str[101];
strcpy(str, " ");
strcat(str, input);
char *p = str;
while(*p) {
if(*p == ' ' && isalpha(*(p+1)) != 0)
printf("%c",*(p+1));
p++;
}
return 0;
}
Try something similar to this:
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// Insert code here...
char firstname[100], secondname[100];
printf("Enter First Name: ");
fgets(firstname, 100, stdin);
printf("Enter Second Name: ");
fgets(secondname,100,stdin);
firstname[strlen(firstname)-1]= '\0';
printf("fullname is %s %s", firstname, secondname);
return 0;
}
This was my solution
#include <stdlib.h>
#include <stdarg.h>
char *strconcat(int num_args, ...) {
int strsize = 0;
va_list ap;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++)
strsize += strlen(va_arg(ap, char*));
char *res = malloc(strsize+1);
strsize = 0;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++) {
char *s = va_arg(ap, char*);
strcpy(res+strsize, s);
strsize += strlen(s);
}
va_end(ap);
res[strsize] = '\0';
return res;
}
but you need to specify how many strings you're going to concatenate
char *str = strconcat(3, "testing ", "this ", "thing");
I have recently started to code in C and I am having quite a lot of fun with it.
But I ran into a little problem that I have tried all the solutions I could think of but to no success. How can I assign a char* variable to an array?
Example
int main()
{
char* sentence = "Hello World";
//sentence gets altered...
char words[] = sentence;
//code logic here...
return 0;
}
This of course gives me an error. Answer greatly appreciated.
You need to give the array words a length
char words[100]; // For example
The use strncpy to copy the contents
strncpy(words, sentence, 100);
Just in case add a null character if the string sentence is too long
words[99] = 0;
Turn all the compiler warnings on and trust what it says. Your array initializer must be a string literal or an initializer list. As such it needs an explicit size or an initializer. Even if you had explicitly initialized it still wouldn't have been assignable in the way you wrote.
words = sentence;
Please consult this SO post with quotation from the C standard.
As of:
How To Assign char* to an Array variable ?
You can do it by populating your "array variable" with the content of string literal pointed to by char *, but you have to give it an explicit length before you can do it by copying. Don't forget to #include <string.h>
char* sentence = "Hello World";
char words[32]; //explicit length
strcpy (words, sentence);
printf ("%s\n", words);
Or in this way:
char* sentence = "Hello World";
char words[32];
size_t len = strlen(sentence) + 1;
strncpy (words, sentence, (len < 32 ? len : 31));
if (len >= 32) words[31] = '\0';
printf ("%s\n", words);
BTW, your main() should return an int.
I think you can do it with strcpy :
#include <memory.h>
#include <stdio.h>
int main()
{
char* sentence = "Hello World";
char words[12];
//sentence gets altered...
strcpy(words, sentence);
//code logic here...
printf("%s", words);
return 0;
}
..if I didn't misunderstand. The above code will copy the string into the char array.
How To assign char* to an Array variable?
The code below may be useful for some occasions since it does not require copying a string or knowing its length.
char* sentence0 = "Hello World";
char* sentence1 = "Hello Tom!";
char *words[10]; // char *words[10] array can hold char * pointers to 10 strings
words[0] = sentence0;
words[1] = sentence1;
printf("sentence0= %s\n",words[0]);
printf("sentence1= %s\n",words[1]);
Output
sentence0= Hello World
sentence1= Hello Tom!
The statement
char* sentence = "Hello World";
Sets the pointer sentence to point to read-only memory where the character sequence "Hello World\0" is stored.
words is an array and not a pointer, you cannot make an array "point" anywhere since it is a
fixed address in memory, you can only copy things to and from it.
char words[] = sentence; // error
instead declare an array with a size then copy the contents of what sentence points to
char* sentence = "Hello World";
char words[32];
strcpy_s(words, sizeof(word), sentence); // C11 or use strcpy/strncpy instead
The string is now duplicated, sentence is still pointing to the original "Hello World\0" and the words
array contains a copy of that string. The array's content can be modified.
Among other answers I'll try to explain logic behind arrays without defined size. They were introduced just for convenience (if compiler can calculate number of elements - it can do it for you). Creating array without size is impossible.
In your example you try to use pointer (char *) as array initialiser. It is not possible because compiler doesn't know number of elements stayed behind your pointer and can really initialise the array.
Standard statement behind the logic is:
6.7.8 Initialization
...
22 If an array of unknown size is initialized, its size is determined
by the largest indexed element with an explicit initializer. At the
end of its initializer list, the array no longer has incomplete type.
I guess you want to do the following:
#include <stdio.h>
#include <string.h>
int main()
{
char* sentence = "Hello World";
//sentence gets altered...
char *words = sentence;
printf("%s",words);
//code logic here...
return 0;
}
All of the code below on C.
Both the code snippet below are compiled, but the difference is that the second program crashes at startup.
One:
#include <stdio.h>
#include <string.h>
void main() {
char *foo = "foo";
char *bar = "bar";
char *str[80];;
strcpy (str, "TEXT ");
strcat (str, foo);
strcat (str, bar);
}
Two:
#include <stdio.h>
#include <string.h>
void main() {
char *foo = "foo";
char *bar = "bar";
char *str="";
strcpy (str, "TEXT ");
strcat (str, foo);
strcat (str, bar);
}
The difference is that in the first case, said the size of the str string, while the second is not. How to make string concatenation without a direct indication of the size of the string str?
The difference is that in the first case, said the size of the str
string, while the second is not.
No. In the first program, the following statement
char *str[80];
defines str to be an array of 80 pointers to characters. What you need is a character array -
char str[80];
In the second program,
char *str="";
defines str to be a pointer to the string literal "", not an array. Arrays and pointers are different types.
Now, the second program crashes because
char *str="";
defines str to be a pointer to a string literal. The first argument of strcpy should be a pointer to a buffer which is large enough for the string to be copied which is pointed to by its second argument.
However, str points to the string literal "" which is allocated in read-only memory. By passing str to strcpy, it invoked undefined behaviour because strcpy tries to modify it which is illegal. Undefined behaviour means the behaviour is unpredictable and anything can happen from program crash to due to segfault (illegal memory access) or your hard drive getting formatted. You should always avoid code which invoked undefined behaviour.
How to make string concatenation without a direct indication of the
size of the string str?
The destination string must be large enough to store the source string else strcpy will overrun the buffer pointed to by its first argument and invoke undefined behaviour due to illegal memory access. Again, the destination string must have enough space for the source string to be appended to it else strcat will overrun the buffer and again cause undefined behaviour. You should ensure against this by specifying the correct size of the string str in this case.
Change to:
One:
#include <stdio.h>
#include <string.h>
void main() {
char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy (str, "TEXT ");
strcat (str, foo);
strcat (str, bar);
}
Two:
#include <stdio.h>
#include <string.h>
void main() {
char *foo = "foo";
char *bar = "bar";
char str[80]="";
strcpy (str, "TEXT ");
strcat (str, foo);
strcat (str, bar);
}
#include <stdio.h>
#include <string.h>
void main() {
char *foo = "foo";
char *bar = "bar";
char *str=NULL;
size_t strSize = strlen(foo)+strlen(bar)+strlen("TEXT ")+1;
str=malloc(strSize);
if(NULL==str)
{
fprintf(stderr, "malloc() failed.\n");
goto CLEANUP;
}
strcpy (str, "TEXT ");
strcat (str, foo);
strcat (str, bar);
CLEANUP
if(str)
free(str);
}
size_t len1 = strlen(first);
size_t len2 = strlen(second);
char * s = malloc(len1 + len2 + 2);
memcpy(s, first, len1);
s[len1] = ' ';
memcpy(s + len1 + 1, second, len2 + 1); // includes terminating null
Did I do good?
In the second version you have set char *str=""; this is equivalent to allocating an empty string on the stack with 1 byte which contains null for end of string. Had you written char*str="0123456789", you would have allocated 11 bytes on the stack the first 10 of which would have been "0123456789" and the 11th byte would have been null. If you try to copy more than allocated bytes to the str, your program might crash. So either allocate dynamically enough memory, or statically.
Both programs are wrong, the first provokes undefined behavior exactly as the second one.
char *str[80]; is array of pointers which you pass to functions ( strcpy, strcat) as first argument, while the first argument for those functions should be char *. Possible solution for this issue to define str as char str[80];
The issue with the second program is that char *str=""; is a pointer to read only piece of memory, which can't be changed.In this case one of possible solutions can be :
char* str = malloc(80);
strcpy(str,"");
strcpy (str, "TEXT ");
strcat (str, foo);
strcat (str, bar);
You'll have to allocate memory before copying. The first defines the size so as 80
char *str = new char[10]; could also be a method of allocation. malloc function could also be used to allocate memory.
Here are some references that might help you
http://www.cplusplus.com/reference/cstdlib/malloc/
http://www.cplusplus.com/reference/cstdlib/calloc/
I'm working in C, and I have to concatenate a few things.
Right now I have this:
message = strcat("TEXT ", var);
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
Now if you have experience in C I'm sure you realize that this gives you a segmentation fault when you try to run it. So how do I work around that?
In C, "strings" are just plain char arrays. Therefore, you can't directly concatenate them with other "strings".
You can use the strcat function, which appends the string pointed to by src to the end of the string pointed to by dest:
char *strcat(char *dest, const char *src);
Here is an example from cplusplus.com:
char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");
For the first parameter, you need to provide the destination buffer itself. The destination buffer must be a char array buffer. E.g.: char buffer[1024];
Make sure that the first parameter has enough space to store what you're trying to copy into it. If available to you, it is safer to use functions like: strcpy_s and strcat_s where you explicitly have to specify the size of the destination buffer.
Note: A string literal cannot be used as a buffer, since it is a constant. Thus, you always have to allocate a char array for the buffer.
The return value of strcat can simply be ignored, it merely returns the same pointer as was passed in as the first argument. It is there for convenience, and allows you to chain the calls into one line of code:
strcat(strcat(str, foo), bar);
So your problem could be solved as follows:
char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);
Avoid using strcat in C code. The cleanest and, most importantly, the safest way is to use snprintf:
char buf[256];
snprintf(buf, sizeof(buf), "%s%s%s%s", str1, str2, str3, str4);
Some commenters raised an issue that the number of arguments may not match the format string and the code will still compile, but most compilers already issue a warning if this is the case.
Strings can also be concatenated at compile time.
#define SCHEMA "test"
#define TABLE "data"
const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry = // include comments in a string
" SELECT * " // get all fields
" FROM " SCHEMA "." TABLE /* the table */
" WHERE x = 1 " /* the filter */
;
Folks, use strncpy(), strncat(), or snprintf().
Exceeding your buffer space will trash whatever else follows in memory!
(And remember to allow space for the trailing null '\0' character!)
Also malloc and realloc are useful if you don't know ahead of time how many strings are being concatenated.
#include <stdio.h>
#include <string.h>
void example(const char *header, const char **words, size_t num_words)
{
size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
char *message = (char*) malloc(message_len);
strncat(message, header, message_len);
for(int i = 0; i < num_words; ++i)
{
message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
message = (char*) realloc(message, message_len);
strncat(strncat(message, ";", message_len), words[i], message_len);
}
puts(message);
free(message);
}
Best way to do it without having a limited buffer size is by using asprintf()
char* concat(const char* str1, const char* str2)
{
char* result;
asprintf(&result, "%s%s", str1, str2);
return result;
}
If you have experience in C you will notice that strings are only char arrays where the last character is a null character.
Now that is quite inconvenient as you have to find the last character in order to append something. strcat will do that for you.
So strcat searches through the first argument for a null character. Then it will replace this with the second argument's content (until that ends in a null).
Now let's go through your code:
message = strcat("TEXT " + var);
Here you are adding something to the pointer to the text "TEXT" (the type of "TEXT" is const char*. A pointer.).
That will usually not work. Also modifying the "TEXT" array will not work as it is usually placed in a constant segment.
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
That might work better, except that you are again trying to modify static texts. strcat is not allocating new memory for the result.
I would propose to do something like this instead:
sprintf(message2, "TEXT %s TEXT %s", foo, bar);
Read the documentation of sprintf to check for it's options.
And now an important point:
Ensure that the buffer has enough space to hold the text AND the null character. There are a couple of functions that can help you, e.g., strncat and special versions of printf that allocate the buffer for you.
Not ensuring the buffer size will lead to memory corruption and remotely exploitable bugs.
Do not forget to initialize the output buffer. The first argument to strcat must be a null terminated string with enough extra space allocated for the resulting string:
char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string );
// null_terminated_string has less than 1023 chars
As people pointed out string handling improved much. So you may want to learn how to use the C++ string library instead of C-style strings. However here is a solution in pure C
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void appendToHello(const char *s) {
const char *const hello = "hello ";
const size_t sLength = strlen(s);
const size_t helloLength = strlen(hello);
const size_t totalLength = sLength + helloLength;
char *const strBuf = malloc(totalLength + 1);
if (strBuf == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(strBuf, hello);
strcpy(strBuf + helloLength, s);
puts(strBuf);
free(strBuf);
}
int main (void) {
appendToHello("blah blah");
return 0;
}
I am not sure whether it is correct/safe but right now I could not find a better way to do this in ANSI C.
It is undefined behaviour to attempt to modify string literals, which is what something like:
strcat ("Hello, ", name);
will attempt to do. It will try to tack on the name string to the end of the string literal "Hello, ", which is not well defined.
Try something this. It achieves what you appear to be trying to do:
char message[1000];
strcpy (message, "TEXT ");
strcat (message, var);
This creates a buffer area that is allowed to be modified and then copies both the string literal and other text to it. Just be careful with buffer overflows. If you control the input data (or check it before-hand), it's fine to use fixed length buffers like I have.
Otherwise, you should use mitigation strategies such as allocating enough memory from the heap to ensure you can handle it. In other words, something like:
const static char TEXT[] = "TEXT ";
// Make *sure* you have enough space.
char *message = malloc (sizeof(TEXT) + strlen(var) + 1);
if (message == NULL)
handleOutOfMemoryIntelligently();
strcpy (message, TEXT);
strcat (message, var);
// Need to free message at some point after you're done with it.
The first argument of strcat() needs to be able to hold enough space for the concatenated string. So allocate a buffer with enough space to receive the result.
char bigEnough[64] = "";
strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);
/* and so on */
strcat() will concatenate the second argument with the first argument, and store the result in the first argument, the returned char* is simply this first argument, and only for your convenience.
You do not get a newly allocated string with the first and second argument concatenated, which I'd guess you expected based on your code.
You can write your own function that does the same thing as strcat() but that doesn't change anything:
#define MAX_STRING_LENGTH 1000
char *strcat_const(const char *str1,const char *str2){
static char buffer[MAX_STRING_LENGTH];
strncpy(buffer,str1,MAX_STRING_LENGTH);
if(strlen(str1) < MAX_STRING_LENGTH){
strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer));
}
buffer[MAX_STRING_LENGTH - 1] = '\0';
return buffer;
}
int main(int argc,char *argv[]){
printf("%s",strcat_const("Hello ","world")); //Prints "Hello world"
return 0;
}
If both strings together are more than 1000 characters long, it will cut the string at 1000 characters. You can change the value of MAX_STRING_LENGTH to suit your needs.
You are trying to copy a string into an address that is statically allocated. You need to cat into a buffer.
Specifically:
...snip...
destination
Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.
...snip...
http://www.cplusplus.com/reference/clibrary/cstring/strcat.html
There's an example here as well.
Assuming you have a char[fixed_size] rather than a char*, you can use a single, creative macro to do it all at once with a <<cout<<like ordering ("rather %s the disjointed %s\n", "than", "printf style format"). If you are working with embedded systems, this method will also allow you to leave out malloc and the large *printf family of functions like snprintf() (This keeps dietlibc from complaining about *printf too)
#include <unistd.h> //for the write example
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ \
char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \
const char *s, \
*a[] = { __VA_ARGS__,NULL}, \
**ss=a; \
while((s=*ss++)) \
while((*s)&&(++offset<(int)sizeof(buf))) \
*bp++=*s++; \
if (offset!=sizeof(buf))*bp=0; \
}while(0)
char buf[256];
int len=0;
strcpyALL(buf,len,
"The config file is in:\n\t",getenv("HOME"),"/.config/",argv[0],"/config.rc\n"
);
if (len<sizeof(buf))
write(1,buf,len); //outputs our message to stdout
else
write(2,"error\n",6);
//but we can keep adding on because we kept track of the length
//this allows printf-like buffering to minimize number of syscalls to write
//set len back to 0 if you don't want this behavior
strcpyALL(buf,len,"Thanks for using ",argv[0],"!\n");
if (len<sizeof(buf))
write(1,buf,len); //outputs both messages
else
write(2,"error\n",6);
Note 1, you typically wouldn't use argv[0] like this - just an example
Note 2, you can use any function that outputs a char*, including nonstandard functions like itoa() for converting integers to string types.
Note 3, if you are already using printf anywhere in your program there is no reason not to use snprintf(), since the compiled code would be larger (but inlined and significantly faster)
int main()
{
char input[100];
gets(input);
char str[101];
strcpy(str, " ");
strcat(str, input);
char *p = str;
while(*p) {
if(*p == ' ' && isalpha(*(p+1)) != 0)
printf("%c",*(p+1));
p++;
}
return 0;
}
Try something similar to this:
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// Insert code here...
char firstname[100], secondname[100];
printf("Enter First Name: ");
fgets(firstname, 100, stdin);
printf("Enter Second Name: ");
fgets(secondname,100,stdin);
firstname[strlen(firstname)-1]= '\0';
printf("fullname is %s %s", firstname, secondname);
return 0;
}
This was my solution
#include <stdlib.h>
#include <stdarg.h>
char *strconcat(int num_args, ...) {
int strsize = 0;
va_list ap;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++)
strsize += strlen(va_arg(ap, char*));
char *res = malloc(strsize+1);
strsize = 0;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++) {
char *s = va_arg(ap, char*);
strcpy(res+strsize, s);
strsize += strlen(s);
}
va_end(ap);
res[strsize] = '\0';
return res;
}
but you need to specify how many strings you're going to concatenate
char *str = strconcat(3, "testing ", "this ", "thing");