Is there a way to concatenate strings without pre-allocating a buffer?
Consider the following:
int main()
{
char buf1[] = "world!";
char buf2[100] = "hello ";
char * p = "hello ";
// printf("%s", strcat(p, buf1)); // UB
printf("%s", strcat(buf2, buf1)); // correct way to use strcat
return 0;
}
If I have a pointer that I want as prefix for a string, must I first copy it to a buffer and then strcat() it? Is there any function that does that implicitly?
The only options I thought of were strcat(), and sprintf(), and both require a buffer.
I need this for a function that expects one string, and I hoped for something close to the Python str1 + str2 syntax
Well, it's not standard C so not very portable, but on GNU libc systems you can use asprintf().
int main(void)
{
const char buf1[] = "world!";
const char * const p = "hello ";
char *s;
if (asprintf(&s, "%s%s", p, buf1) > 0 && s != NULL)
{
puts(s);
free(s);
}
return 0;
}
When compiled and run on a compliant system, this prints
hello world!
I you really want to use C, then you need to use buffers. In C++ or Python you can use constructors and operators that will hide the work for you, but in C you have to do things for yourself. You might create a little helper function if you want to make your code easier, but watch out for memory leaks and threading:
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
const char * strconcat(const char *p1, const char *p2)
{
static __thread char buffer[2048];
snprintf(buffer, 2048, "%s%s", p1, p2);
return buffer;
}
int main(int argc, char** argv)
{
const char *p1 = "hello ";
const char *p2 = "world!";
printf("%s\n", strconcat(p1, p2));
}
This example will work as long as the resulting string does not exceed 2048 characters; otherwise the resulting string will be truncated.
This is of course only one example of helper functions you could create.
Note that the above example returns a const char * which you cannot edit. If you want to further edit the string, you need to create a helper function which allocates a buffer, but then you need to manage your memory!
The most effective way to do this in run-time would be to call malloc and allocate room for a new string, then copy everything there. This is most likely what Python does behind the lines - though it will have a string type.
The disadvantage of doing this outside an ADT/class, is that you have to do the clean-up manually.
Using malloc + copy is however far faster than any *printf, it is thread safe and the same function can be re-used again. Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* strdog (const char* s1, const char* s2)
{
size_t size1 = strlen(s1);
size_t size2 = strlen(s2);
char* result = malloc(size1 + size2 + 1);
if(result == NULL)
{
exit(EXIT_FAILURE);
}
memcpy(result, s1, size1);
memcpy(result+size1, s2, size2);
result[size1 + size2] = '\0';
return result;
}
inline void cleandog (char* s)
{
free(s);
}
int main (void)
{
char s1[] = "hello ";
char s2[] = "world";
char* str = strdog(s1, s2);
puts(str);
cleandog(str);
}
Note however that C supports compile-time concatenation. So if you are only using string literals, you should do something like this:
#define HELLO "hello "
#define WORLD "world"
...
const char* str = HELLO WORLD;
puts(str);
This is of course the superior version of them all, but only works with compile-time string literals.
Related
In the Ritchie/Kernighan book, they show a few ways how to create a self made strcpy function, one of them is with using array subscribed instead of char pointers , but when I try this method and run the code it only gives me the second word in this case "world" and not the word "hello"
any clue?
#include <stdio.h>
void xstrcpy(char *a, char *b)
{
int i = 0;
while((a[i] = b[i]) != '\0')
{
i++;
}
}
int main()
{
char name[20] = "hello";
char names[20] = "world";
xstrcpy(names, name);
printf("%s\n", names);
}
Your function overwrites a with the content of b. You could call as like this:
xstrcpy(names + strlen(names), name);
Or you could implement concatenation. Require caller to pass in a sufficiently large string array (dest). Then find the end (end) of the string and copy src to dest. Using the pointers passed in, but you could also use separate indices into dest and src:
#include <stdio.h>
#include <string.h>
// require caller to pass in a dest array large enough for a copy of src
char *xstrcat(char *dest, const char *src) {
char *end = strchr(dest, '\0');
while(*end++ = *src++);
return dest;
}
int main() {
char dest[sizeof("hello") + sizeof("world") - 1] = "hello";
char src[] = "world";
xstrcat(dest, src);
printf("%s\n", dest);
return 0;
}
this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.
My task is like this: I should implement the strcpy function under the following constraints:
The function should use pointer expression (*(d+i))
I should implement it without using <string.h>
I'm programming in Visual Studio 2019.
I searched some source code in google and run them, but my program has a logical error. The program ends right away, each time. I don't know what I'm doing wrong.
Here's my code in Visual Studio 2019 on Windows. Please tell me what's wrong.
#include <stdio.h>
void strcpy(char*, char*);
int main()
{
char* sen1 = "Hello";
char* sen2 = "Friends";
strcpy(sen1, sen2);
printf("The result: %s\n", sen1);
return 0;
}
void strcpy(char* str1, char* str2)
{
int i = 0;
while (*(str2 + i) != '\0')
{
*(str1 + i) = *(str2 + i);
i++;
}
*(str1 + i) = '\0';
}
In addition to needing to provide writable storage for sen1, you should also check to ensure str2 != NULL in your function before dereferencing str2 (otherwise, even if you fix all other errors -- a segfault will likely result)
For example, in your code you can define a constant to use in setting the size of a sen1 array (or you can allocate storage with malloc(), calloc(), or realloc() -- save that for later). Using an array you can do, e.g.
#include <stdio.h>
#include <stdlib.h>
#define MAXC 64 /* if you need a constant, #define one (or more) */
...
int main (void)
{
char sen1[MAXC] = "Hello";
char *sen2 = "Friends";
mystrcpy (sen1, sen2);
printf ("The result: %s\n", sen1);
}
In your strcpy function, check that str2 isn't NULL before using str2 in your function, e.g.
char *mystrcpy (char *dest, const char *src)
{
char *p = dest;
if (!src || !dest) { /* ensure src or dest is not NULL */
fputs ("error: src or dest parameters NULL in mystrcpy().\n", stderr);
exit (EXIT_FAILURE);
}
do /* loop */
*p++ = *src; /* copy each char in src to dest */
while (*src++); /* (including the nul-termianting char) */
return dest; /* return pointer to dest */
}
Now you will copy your source string to your destination string in your (renamed) mystrcpy() function, receiving the results you expect:
Example Use/Output
$ ./bin/mystrcpy
The result: Friends
Look things over and let me know if you have further questions.
Two problems, at least:
String literals are not writable in C. Often the symptom is a crash (SIGSEGV).
You are not allowed to use the identifier strcpy for your own function. Use another name.
Three clean code issues, at least:
Turn int main() into int main(void) to make it properly typed.
str1 and str2 are too generic names. They don't indicate which is the source and which is the destination pointer. What about my_strcpy(char *dest, char *src)?
I'd use size_t i for the index counter instead of int, because that's the type all the string length functions and the sizeof operator return. It's also an unsigned type and can copy really long strings :-) The size_t is available after #include <stddef.h>.
You want this:
...
char* source = "Hello";
// or char source[] = "Hello";
char destination[1000]; // destination buffer long enough for playing around
my_strcpy(destination, source);
printf("%s\n", destination); // should print "Hello" if my_strcpy is corect
...
For the rest read Jens's answer.
Among the other good answers, just regarding the implementation of your strcpy function and not a detailed issue analyze of your actual code, another approach is this:
char * n_strcpy(char * dest, char const * src)
{
if (dest == NULL || src == NULL)
{
return NULL;
}
char *ptr = dest;
while ((*dest++ = *src++));
return ptr;
}
If we use for example:
char* strs[2];
strs[1] = "Hello";
strs[2] = "World!";
strcat(strs[1],strs[2]);
Then an access violation comes up (Access violation writing location 0x0028CC75).
So why use const char *strs[2]; since the strs1[1], strs1[2] cannot be changed?
// string literals are non-writeable so const is appropriate here
const char* strs[2] = {"Hello", "World!"};
// let's create a target buffer with sufficient space
char buffer[20];
// copy the first string there
strcpy(buffer, strs[0]);
// add the second string there
strcat(buffer, strs[1]);
Two sources of access violation in your case
String literals are read only and writing to them is undefined behavior
In c arrays are 0 index based, so strs[2] does not exist, only strs[0] and strs[1].
Using const prevents you from accidentally modifying them, but it does not forbid you.
Arrays are modifiable though,
#include <stdio.h>
#include <string.h>
int
main(void)
{
char strs[2][11] = {"Hello", "World"};
strcat(strs[0], strs[1]);
return 0;
}
the above works as you expected it.
Here it is how you would do it correctly with dynamic allocation
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *
autostrcat(const char *const head, const char *const tail)
{
char *result;
size_t headlen;
size_t taillen;
if ((head == NULL) || (tail == NULL))
return NULL;
headlen = strlen(head);
taillen = strlen(tail);
result = malloc(1 + headlen + taillen);
if (result == NULL)
return NULL;
memcpy(result, head, headlen);
memcpy(&result[headlen], tail, taillen);
result[headlen + taillen] = '\0';
return result;
}
int
main(void)
{
const char *strs[2] = {"Hello", "World"};
char *result = autostrcat(strs[0], strs[1]);
if (result != NULL)
printf("%s\n", result);
free(result);
return 0;
}
Since you used strlen() you know what the lengths of the strings are, so using strcat() would be unecessarily expensive because it would again figure out the length of the first string as strlen() does.
Wow. So much wrong.
Arrays are 0 based, not 1 based in C.
The strings are based in program space, most likely, so aren't writeable.
you should create a buffer, and then fill it.
char* concat = (char *) _alloca(strlen(strs[0]) + strlen(strs[1])+1);
strcpy(concat, strs[0]);
strcat(concat, strs[1]);
I am trying to implement
void strcpyy(char *s, char *t){
while(*s++ = *t++){
}
}
which is an example from K&R. The implementation should be fairly easy but for some reason, that is not the case for me at the moment. So I have the following
int main(){
char *mess = "hello world";
char *mess = (char *) malloc(strlen(mess) + 1);
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
Every time I run the program, I keep on getting a big list of errors each time I run with -Wall. I would think that to implement and use strcpyy, you would have to malloc space to copy the string and once you do so, you should be able to print out aess which theoratically should contain a copy of mess. Any help would be much appreciated!
It is always a good practice to pay attention to the error messages, especially to the first message (others often are the consequences of the first error). The error message surely indicated the line number corresponding to the line with malloc, and most probably told you what's the problem there.
Correct your program to read:
char *mess = "hello world";
char *aess = (char *) malloc(strlen(mess) + 1);
or the complete function is:
int main(){
char *mess = "hello world";
char *aess = (char *) malloc(strlen(mess) + 1);
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
The problem is that your line
char *mess = (char *) malloc(strlen(mess) + 1);
overwrites the first line
char *mess = "hello world";
and the line
char *aess;
leaves the variable unassigned.
The compile error is because the compiler cannot choose between
char *mess = "hello world";
and
char *mess = (char *) malloc(strlen(mess) + 1);
which introduce a new variable each but with the same name.
The program will look the following way
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void strcpyy( char *s, const char *t )
{
while ( *s++ = *t++ );
}
int main( void )
{
char *t = "hello world";
char *s = ( char * )malloc( strlen( t ) + 1 );
strcpyy( s, t );
printf( "%s\n", s );
free( s );
return 0;
}
change
char *mess = "hello world";
char *mess = (char *) malloc(strlen(mess) + 1);
char *aess;
to
char *mess = "hello world";
char *aess = malloc(strlen(mess) + 1);
mess is a string literal, which is hold in read-only memory. you were overwriting it and losing string that you wanted to copy. you need to assign some space for place where you want to copy characters, in your case aess variable. also, remember to free(aess); at the end of your program. if not, you'll get memory leaks.
why are you declaring and defining mess two times? never declare two variables with the same name if they have the same scope ,by doing this you confuse the compiler;
I'd recommed using strdup like this :
int main(){
char *mess = strdup("hello world");
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
or just a plain array like this
int main(){
char mess[] = "hello world";
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}