I am trying to create my own string copy function in C.
Copying the text works, however extra characters are added to the destination string at the end and I don't know why.
I would be very happy to get an answer.
Here is my code:
#include <stdio.h>
#include <string.h>
void copy(char *dst, char *src) {
int src_len = strlen(src);
char *src_strtng = &src[0];
char *dst_strtng = &dst[0];
for (int i = 0; i < src_len; i++) {
*dst_strtng++ = *src_strtng++;
}
printf("%s\n", dst);
}
int main() {
char srcString[] = "We promptly judged antique ivory buckles for the next prize!";
char dstString[strlen(srcString)];
copy(dstString, srcString);
}
create my own str copy function in C.
Missing null character termination
This is OP's key issue, lack of appending a null character to dst.
Only need to traverse src once
Rather than strlen() in copy(), just look for '\0'. *1
Does not return a char *
Save the destination pointer.
Prints output, yet strcpy() does not print anything.
Missing const for data referenced by src
Pedantic concern: str should act as if char was unsigned char *2
char *copy(char* dst, const char* src) {
unsigned char *udst = (unsigned char *) dst;
const unsigned char *usrc = (const unsigned char *) src;
do {
*udst++ = *usrc;
} while (*usrc++);
return dst;
}
Allocate enough space for the length of a string and a null character
strlen() returns the length of a string. That does not include the final null character.
int main() {
char srcString[] = "We promptly judged ...";
char dstString[strlen(srcString) + 1]; // Add 1
copy(dstString,srcString);
puts(dstString); // Print here, not in copy().
}
*1 C's strcpy() is char *strcpy(char * restrict s1, const char * restrict s2);
Note the restrict. This implies access via the pointer is not affected by other code. E.g. source string and destination will not overlap.
// Better as
char *copy(char* restrict dst, const char* restrict src) {
OP's use of strlen() in copy() is a good first step to handle overlapping memory (see following), but strcpy() does not need to handle that - suggest copy() not deal with overlap.
char *copy_handle_overlap(char* dst, const char* src) {
return memmove(dst, src, strlen(src) + 1);
}
*2 C string functions have:
For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).
This is important for the rare non-2's complement to distinguish +0 from -0.
Non-2's complement support expected to be dropped with C2X.
Related
I am studying for a Data Structures and Algorithms exam. One of the sample questions related to dynamic memory allocation requires you to create a function that passes a string, which takes it at copies it to a user defined char pointer. The question provides the struct body to start off.
I did something like this:
typedef struct smart_string {
char *word;
int length;
} smart_string;
smart_string* create_smart_string(char *str)
{
smart_string *s = (smart_string*)malloc(sizeof(smart_string));
s->length = strlen(str);
s->word = malloc(s->length);
strcpy(s->word, str);
return s;
}
But the answer was this
typedef struct smart_string {
char *word;
int length;
} smart_string;
smart_string *create_smart_string(char *str)
{
smart_string *s = malloc(sizeof(smart_string));
s->length = strlen(str);
s->word = malloc(sizeof(char) * (s->length + 1));
strcpy(s->word, str);
return s;
}
I went on code:blocks and tested them both to see any major differences. As far as I'm aware, their outputs were the same.
I did my code the way it is because I figured if we were to allocate a specific block of memory to s->word, then it should be the same number of bytes as s ->length, because that's the string we want to copy.
However the correct answer below multiplies sizeof(char) (which is just 1 byte), with s->length + 1. Why the need to add 1 to s->length? What's the importance of multiplying s->length by sizeof(char)? What mistakes did I make in my answer that I should look out for?
sizeof(char) == 1 by definition, so that doesn't matter.
You should not cast the result of malloc: Do I cast the result of malloc?
And your only real difference is that strlen returns the length of the string, not including the terminating NUL ('\0') character, so you need to add + 1 to the size of the buffer as in the solution.
If you copy there the string, the terminating character won't be copied (or worse, it will be copied on some other memory), and therefore, any function that deals with strings (unless you use special safety functions such as strscpy) will run through the buffer and past it since they won't find the end. At that point it is undefined behaviour and everything can happen, even working as expected, but can't rely on that.
The reason it is working as expected is because probably the memory just next to the buffer will be 0 and therefore it is being interpreted as the terminating character.
Your answer is incorrect because it doesn't account for the terminating '\0'-character. In C strings are terminated by 0. That's how their length can be determined. A typical implementation of strlen() would look like
size_t strlen(char const *str)
{
for (char const *p = str; *p; ++p); // as long as p doesn't point to 0 increment p
return p - str; // the length of the string is determined by the distance of
} // the '\0'-character to the beginning of the string.
But both "solutions" are fubar, though. Why would one allocate a structure consisting of an int and a pointer on the free-store ("heap")!? smart_string::length being an int is the other wtf.
#include <stddef.h> // size_t
typedef struct smart_string_tag { // *)
char *word;
size_t length;
} smart_string_t;
#include <assert.h> // assert()
#include <string.h> // strlen(), strcpy()
#include <stdlib.h> // malloc()
smart_string_t create_smart_string(char const *str)
{
assert(str); // make sure str isn't NULL
smart_string_t new_smart_string;
new_smart_string.length = strlen(str);
new_smart_string.word = calloc(new_smart_string.length + 1, sizeof *new_smart_string.word);
if(!new_smart_string.word) {
new_smart_string.length = 0;
return new_smart_string;
}
strcpy(new_smart_string.word, str);
return new_smart_string;
}
*) Understanding C Namespaces
A lot of string functions return a pointer but What are the Advantages of return a pointer to destination and return destination?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *sstrcpy ( char *destination, const char *source ){ //return a pointer to destination
while ((*destination++ = *source++));
*destination='\0';
return destination;
}
char sstrcpy2 ( char *destination, const char *source ){ //return destination
while ((*destination++ = *source++));
*destination='\0';
return *destination;
}
int main(void){
char source[] = "Well done is better than well said";
char destination[40];
sstrcpy ( destination, source );
printf ( "%s\n", destination);
return 0;
}
The idea is to give the possibility to chain the functions. I.e. to pass one function result as a parameter to another one.
sstrcpy ( destination2, sstrcpy ( destination1, source ));
As for the proposed sstrcpy2 - it will only return a single, the last character of the copied string, which is apparently \0 in your implementation, which is rather useless in most cases.
Update:
Note that the implementation sstrcpy is incorrect as is, it will return the value of destination, which was already moved to the end of the string, and not the pointer to the beginning of it. Alternatively I would suggest saving the original pointer and increment it's copy instead:
char *sstrcpy ( char *destination, const char *source ){ //return a pointer to destination
char *dst = destination;
while ((*dst++ = *source++));
*dst='\0';
return destination;
}
Bug 1: you return the end of the string, not the beginning.
Bug 2: you add 2 null terminators at the end, instead of 1.
The correct implementation should be something along the lines of:
char* sstrcpy (char*restrict dst, const char*restrict src)
{
char* original = dst;
for(*dst = *src; *src != '\0'; dst++, src++)
{
*dst = *src;
}
return original;
}
where restrict is a contract with the caller that dst and src don't overlap. Please note that this might still be naive implementation - it is fine for small microcontrollers, but when it comes to library implementations of strcpy for 32 bit systems, they will work with aligned chunks of data.
What are the Advantages of return a pointer to destination and return destination?
There are no advantages whatsoever; the standard library is filled with oddities. This allows two kinds of pointless obfuscation:
// Bad code, do not use!
/*1*/ str = strcpy(str, src); // pointless and potentially dangerous
/*2*/ strcpy(str2, strcpy(str1, src)); // pointless and potentially dangerous
This in turn allows side effects in parameter evaluation to cause bugs, so it is dangerous. Don't write crap like that. The correct versions are:
/*1*/ strcpy(str, src);
/*2*/ strcpy(str1, src);
strcpy(str2, str1);
The latter versions are safer and easier to read. The resulting machine code will be identical.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 4 years ago.
Improve this question
I'm trying to write a program that catenate 2 values in C without using strcat().
char cat (char s1, char s2){
char s3[200];
strcpy(s3,s1);
strcpy(s3+strlen(s1),s2);
return s3;
}
This is my code but it's giving this error:
argument of type "char" is incompatible with parameter of type "const char*"
What should l do?
(I recently start to learn C so please answer me in an easy way)
In your function, the parameters s1 and s2 are of type char which means a single character. Inorder for them to be strings, they must be character arrays. So
char cat (char s1[], char s2[]){
or
char cat (char *s1, char *s2){
instead of
char cat (char s1, char s2){
After this correction, you could just use sprintf() if the destination string is large enough like
sprintf(s3, "%s%s", s1, s2);
And in your program,
s3 is allocated on the stack as it is an automatic variable.
It goes out of scope when the program control exits the cat() function. If you really need to return the string, either allocate memory for s3 on the heap using malloc() and return a pointer to that memory as in
char* cat (char s1[], char s2[]){
char *s3 = NULL;
if( (s3=malloc(sizeof(char)*( strlen(s1)+strlen(s2)+1 )))==NULL )
{
perror("Not enough memory");
return NULL;
}
sprintf(s3, "%s%s", s1, s2);
return s3;
}
or create the s3 character array in the calling function and pass it to cat() as in
char s3[200];
cat(s3, s1, s2);
........
void cat (char s3[], char s1[], char s2[]){
if( strlen(s1) + strlen(s2) < 200 )//where 200 is the size of s3
{
sprintf(s3, "%s%s", s1, s2);
}
else
{
printf("\nInput strings too large");
}
}
See Returning C string from a function.
You're taking chars as arguments and using it as a return value. You probably want s1, s2 to be const char *:
char *cat (const char *s1, const char *s2){
You will have to return a char * too, which means you will have to allocate something that isn't on the stack.
char *cat (const char *s1, const char *s2){
char *s3 = (char*)malloc(200);
strcpy(s3,s1);
strcpy(s3+strlen(s1),s2); // strcat(s3, s1);
return s3;
}
A char is a small integer type (a byte), which can hold just a single encoded character, not a string. Strings in C don't have a dedicated type, they're just defined as a sequence of characters, ending with a 0 byte. So, you naturally store strings in arrays of char. E.g. the array
char str[30];
Can store a string of up to 29 characters (one more is needed for the terminating 0).
Furthermore, you have to know that arrays can't be passed to or returned from functions in C. Instead, pointers are used. If you write arrays as function arguments or return values, these types are automatically adjusted to the corresponding pointer types. It's common to say the array "decays" as a pointer. So, in your code, you attempt to return an array. Instead, a pointer to the first array element is returned. Because this array is local to your function, it doesn't exist any more after the return, so you are returning an invalid pointer.
That's why the library function strcat expects the caller to give a pointer to the result, instead of returning the result. A typical simple strcat function could look like this (not the original, returning nothing here to make the code simple):
void mystrcat(char *s, const char *append)
{
while (*s) ++s; // search end of s
while ( (*s++ = *append++) ); // copy until end of append
}
To understand this code, you have to know that 0 is false in C when evaluated in a boolean context, and any other value is true. ++ increments, so applied to pointers, moves them to point to the next element. Therefore, this code examines each character in *s until it finds a 0 byte and then starts copying characters from *append there until the 0 byte in *append is hit.
If you absolutely want to return the result, you have to dynamically allocate memory for it in your function. This could look like the following:
char *concatenate(const char *s1, const char *s2)
{
size_t resultlen = strlen(s1) + strlen(s2) + 1; // one more for the 0 byte
char *result = malloc(resultlen);
if (!result) return 0; // allocation failed, out of memory
char *p = result;
while ( (*p = *s1++) ) ++p; // copy from s1 until 0
while ( (*p++ = *s2++) ); // copy from s2 until 0
return result;
}
Of course, in this case, the caller has to free() the result when it's no longer needed.
I have to create a copy of some elements of the standard library in C and I have to create a copy of strcat. So I have to create a function that concatenate two strings in C. I know arrays in C can't change the allocated size. The only fonction i'm allowed to use is copies i made of strlen, strstr, and write() ... My code looks like this :
char *my_strcat(char *dest, char *src)
{
int dest_size;
int src_size;
int current_pos;
int free_space;
int pos_in_src;
src_size = my_strlen(src);
dest_size = my_strlen(dest);
while (dest[current_pos] != '\0')
current_pos = current_pos + 1;
free_space = dest_size - current_pos;
if (free_space < src_size)
return (0);
while (src[pos_in_src] != '\0')
{
dest[current_pos] = src[pos_in_src];
pos_in_src = pos_in_src + 1;
current_pos = current_pos + 1;
}
return (dest);
}
But I don't know how to declare my dest and src in the main.
I don't know how to create an array with a big size, declare it as a string like dest = "Hello\0" but this array has to still contains more than 6 characters.
Can you help me please ?
char dest[19] = "epite";
char *src = "chor42spotted";
my_strcat(dest, src);
Also, read the man for strcat(3)
the dest string must have enough space for the result.
https://linux.die.net/man/3/strcat
So your function is behaving incorrectly, you do not need to check that you have enough free space in dest
You want a function mystrcat which behaves exactly like stdlib strcat.
So the prototype is
/*
concatenate src to dest
dest [in / out] - the string to add to (buffer must be large enough)
src [in] - the string to concatenate.
Returns: dest (useless little detail for historical reasons).
*/
char *mystrcat(char *dest, const char *src);
Now we call it like this
int main(void)
{
char buff[1024]; // nice big buffer */
strcpy(buff, "Hello ");
mystrcat(buff, "world");
/* print the output to test it */
printf("%s\n", buff);
return 0;
}
But I'm not going to write mystrcat for you. That would make your homework exercise pointless.
The 1st parameter of the array simply has to be large enough to contain both strings + one null terminator. So if you for example have "hello" and "world", you need 5 + 5 +1 = 11 characters. Example:
#define LARGE_ENOUGH 11
int main (void)
{
char str[LARGE_ENOUGH] = "hello";
my_strcat(str, "world");
puts(str); // gives "helloworld"
}
In real world applications, you would typically allocate space for the array to either be same large number (couple of hundred bytes) or with a length based on strlen calls.
As for the implementation itself, your solution is needlessly complicated. Please note that the real strcat leaves all error checking to the caller. It is most likely implemented like this:
char* strcat (char* restrict s1, const char* restrict s2)
{
return strcpy(&s1[strlen(s1)], s2);
}
The most important part here is to note the const-correctness of the s2 parameter.
The restrict keywords are just micro-optimizations from the C standard, that tells the compiler that it can assume that the pointers point at different memory areas.
If you wish to roll out your own version with no library function calls just for fun, it is still rather easy, you just need two loops. Something like this perhaps:
char* lolcat (char* restrict s1, const char* restrict s2)
{
char* s1_end = s1;
while(*s1_end != '\0') // find the end of s1
{
s1_end++;
}
do // overwrite the end of s1 including null terminator
{
*s1_end = *s2;
s1_end++;
s2++;
} while(*s1_end != '\0'); // loop until the null term from s2 is copied
return s1;
}
I'm trying to build a string that consists of two variables that are divided by a null terminator. It must be done this way for the custom protocol we're using.
const char* vendorChar = "3333-3333-4444-aaa3-3333";
const char* userChar = "someUsername";
char usernameString[strlen(vendorChar) + strlen(userChar) + 1];
char* uPtr = usernameString;
strcpy(uPtr, vendorChar);
strcpy(uPtr+strlen(vendorChar)+1, userChar);
When I run the above code, it only sends over the value of vendorChar and ignores userChar. When it is working it should look like
4444-2222-3333-1111\0someUsername
So far I've learned that str functions will drop the null as it sees it at the end of the string. I think I have to use memcpy to preserve it, but I can't figure out how to.
You're right in your assumption, strcpy may copy up to the middle null char,
according to this, strcpy(char *str1, const char *str2) does this:
Copies the string pointed to by str2 to str1. Copies up to and including the null character of str2. If str1 and str2 overlap the behavior is undefined.
memcpy should solve the problem as it just treats the memory as a chunk of bytes, not as a string.
strcpy signature:
char *strcpy(char *dest, const char *src);
memcpy signature:
void *memcpy(void *dest, const void *src, size_t n);
So just replace the name and add the cumulative lengths (with both null chars of course).
EDIT
To eliviate some doubts raised here, consider this code:
#include "string.h"
#include "stdio.h"
int main() {
char x[10] = {0};
char y[10];
char z[10];
x[0] = x[1] = x[5] = 'a';
memcpy(y,x,10);
strcpy(z,x);
printf ("y[5]= %s\n", &y[5]);
printf ("z[5]= %s\n", &z[5]);
return 0;
}
results is:
y[5]= a
z[5]=
So it's clear that memcpy moved the entire length, including byte [5], while strcpy did not, stopping at the null termination
const char* vendorChar = [vendorId cStringUsingEncoding: [NSString defaultCStringEncoding]];
const char* userChar = [dsUsername cStringUsingEncoding: [NSString defaultCStringEncoding]];
char usernameString[strlen(vendorChar) + strlen(userChar) + 2];
char* uPtr = usernameString;
strcpy(uPtr, vendorChar);
memcpy(uPtr+strlen(vendorChar)+1, userChar, strlen(userChar) + 1);
Changes: I added space for the trailing \0, the userChar string is copied with trailing \0 included.
Firstly, you need usernameString[] to be like -
char usernameString[strlen(vendorChar) + strlen(userChar) + 3];
because 1 is for putting "\", 1 for "0" and the other 1 is for null terminator, so becomes 3. Then use strcat() create the string you need. Like, below:
strcpy(uPtr, vendorChar);
strcat(uPtr,"\\");
strcat(uPtr,"0");
strcat(uPtr, userChar);