Code
char* CreateString(char* string1, char* string2) {
int length = strlen(string1) + strlen(string2);
// Allocate memory for the resulting string
char* result = malloc((length) * sizeof(char));
// Concatenate the two strings
strcpy_s(result, sizeof result, string1);
strcat_s(result,sizeof result, string2);
return result;
}
I have this simple code of mine , all i want to do is add them together, but whenever I use strcpy_s or strcat_s it gives this error in the
picture
But it works if I use the CRT library.
Another question is that did I use the Pointers correctly? I'm new to this topic and it is confusing so I don't really understand it.
I tried to add Two Sentences together
strings require null terminating character at the end. So the buffer is too short.
sizeof result gives the size of the pointer not the size of the referenced object.
char* CreateString(char* string1, char* string2) {
size_t length = strlen(string1) + strlen(string2) + 1;
// or for Windows
// rsize_t length = strlen(string1) + strlen(string2) + 1;
// Allocate memory for the resulting string
char* result = malloc((length) * sizeof(*result));
// Concatenate the two strings
strcpy_s(result, length, string1);
strcat_s(result, length, string2);
return result;
}
Related
Let's take an example.
#include <stdio.h>
#include <string.h>
int main() {
char str1[7] = "hello ";
printf("Initial size of str1 is: %d\n", strlen(str1));
char str2[] = "buddy";
printf("%s\n", strcat(str1, str2));
printf("Final size: %d\n", strlen(str1));
}
The output of the above program will be
Initial size of str1 is: 6
hello buddy
Final size: 11
--------------------------------
Process exited after 0.835 seconds with return value 0
Press any key to continue . . .
See? how the size of str1 changed from 7 to 11 (including null variable), regarding that what I think would have happened is :
Some function I do not know may have reallocated contiguous memory for str1 starting from same address as before i.e str1 with size strlen(str1)+strlen(str2)+1 +1 for null value, and then redefined it to get hello buddy.
If I am wrong please tell, if not then, what function is it and how does it work?
One more question: how can I write a code to do the above task without the use of strcat function.
I tried doing it using realloc() but didn't quite succeed may be that's because realloc() can only reallocate dynamically allocated memory, is it so?
Buffer overflow
OP's code fails as strcat(str1,str2) attempts to write past the end of str1[] - result: undefined behavior (UB). #dimich
Instead use a larger destination buffer.
// char str1[7]="hello ";
char str1[7 + 5]="hello ";
char str2[]="buddy";
printf("%s\n",strcat(str1,str2));
Use correct print specifier
strlen() returns a size_t, not an int.
// printf("Initial size of str1 is: %d\n",strlen(str1));
printf("Initial size of str1 is: %zu\n",strlen(str1));
Tip: enable all warnings.
Alternative
One of many alternatives: copy str2 to the end of str1.
// printf("%s\n",strcat(str1,str2));
strcpy(str1 + strlen(str1), strt2);
printf("%s\n",str1);
realloc()
realloc() can only reallocate dynamically allocated memory, is it so?
realloc() should not be used on pointers to non-allocated, non-NULL pointers.
In addition to re-allocating dynamically allocated memory, realloc() can start with no prior allocation.
char *p = realloc(NULL, size);
// just like
char *p = malloc(size);
Moral of the story
Be mindful of memory usage with string functions.
Enable all warnings.
You can only reallocate the memory you have dynamically allocated (ie using malloc family functions).
ee? how the size of str1 changed from 7 to 11 (including null
variable), regarding that what I think would have happened is : A
function idk which one, but it may have reallocated contiguous memory
for str1 starting from same address as before i.e str1 with size
strlen(str1)+strlen(str2)+1 +1 for null value, and then redefined it
to get hello buddy. If i am wrong please tell, if not then , what
function is it and how does it work?
You are wrong. It is an example of an Undefined Behaviour. You have written some data outside array memory. Undefined Behavior means that your program behaviour from now is unpredictable. strcat does not reallocate any memory.
At last, how can i write a code to do the above task without the use
of strcat function.
For example:
char *mystrcat(char *dest, const char *src, const int isDynamicMemory)
{
size_t dlen = strlen(dest);
size_t slen = strlen(src);
if(isDynamicMemory)
{
dest = realloc(dest, slen + dlen + 1);
if(!dest) return NULL;
}
memcpy(dest + dlen, src, slen + 1);
return dest;
}
If dest was dynamically allocated you can reallocate it to the correct size by passing 1 as isDynamicMemory parameter
Try to do not program in the main function. Use functions for such task like writing strcat like function.
The program has undefined behavior because in the call of strcat
printf("%s\n", strcat(str1, str2));
the memory beyond the character array str1 declared like
char str1[7] = "hello ";
is being overwritten.
There is no space in the array to accommodate the string "buddy" after the stored string "hello ".
The sizes of the array str1 and str2 themselves was not changed. The function strlen does not return the size of a character array. It returns the length of a string: a sequence of characters terminated by the zero-terminating character '\0'. To get the size of a character array you should use the operator sizeof.
Pay attention to that the return type of the function strlen is size_t. To output a value of this type you have to use the conversion specifier zu instead of d.
printf("Initial size of str1 is: %zu\n", strlen(str1));
^^^
To make the program correct you have to enlarge the character array str1. Here is a demonstration program.
#include <stdio.h>
#include <string.h>
int main( void )
{
char str1[12] = "hello ";
printf( "The size of str1 is: %zu\n", sizeof( str1 ) );
printf( "The length of the stored string in str1 is: %zu\n", strlen( str1 ) );
char str2[] = "buddy";
printf("%s\n", strcat(str1, str2));
printf( "The size of str1 is: %zu\n", sizeof( str1 ) );
printf( "The length of the stored string in str1 is: %zu\n", strlen( str1 ) );
}
The program output is
The size of str1 is: 12
The length of the stored string in str1 is: 6
hello buddy
The size of str1 is: 12
The length of the stored string in str1 is: 11
As you can see from the output the size of the array str1 stays unchanged. What was changed is the length of the stored string in the array str1.
Pay attention to that the function strcat does not allocate or reallocate memory for arrays passed to the function as arguments. So if the destination array does not have enough memory to accommodate the appended string then the behavior is undefined because in this case the memory after the destination array will be overwritten.
As other answers (1, 2) mentioned, your code has a buffer overflow, a kind of undefined behaviour.
One more question: how can I write a code to do the above task without the use of strcat function.
Either:
Use snprintf()
Use strlcpy()
Implement your own version of strcat() (with some potential improvements)
Option 1
char str1[] = "hello ";
char str2[] = "buddy";
size_t total_size = sizeof(str1) + sizeof(str2) - 1; // sizeof counts \0 at the end
char res[total_size];
snprintf(res, total_size, "%s%s", str1, str2);
printf("sizeof(str1) = %zu\n", sizeof(str1));
printf("sizeof(str2) = %zu\n", sizeof(str2));
printf("total_size = %zu\n", total_size);
printf("res = %s\n", res);
sizeof(str1) = 7
sizeof(str2) = 6
total_size = 12
res = hello buddy
snprintf() lets you to control how many characters at most you want to print. This is comes handy in preventing a buffer overflow. For example, if you use sprintf(res, "%s%sxxx", str1, str2) in the above code, you'll get a BO. This is not the case with snprintf(res, total_size, "%s%sxxx", str1, str2).
Option 2
strlcpy() lets you to control how many characters at most you want to copy, and guarantees null-termination (unlike strncpy()). Possible implementations: 1, 2, 3.
Option 3 (credit: Back to Basics)
char *concatenate(char *dest, char *src)
{
while (*dest) dest++;
while ((*dest++ = *src++));
return --dest;
}
Or:
char *concatenate_n(char *dest, char *src, int n)
{
while (*dest) dest++;
for (int i = 0; i < n && (*dest++ = *src++); ++i) {}
return --dest;
}
Example:
char str1[12] = "hello ";
char str2[] = "buddy";
concatenate(str1, str2);
// concatenate_n(str1, str2, sizeof(str1) - 1 - strlen(str1)); // Remaining space in str1
printf("str1 = %s\n", str1);
printf("p = %s\n", p);
As i mentioned in the comment, overflow of str1 occures. strcat() doesn't know where and how strings are allocated. It searches end of destination string and appends source string overwriting null terminator.
If you want dynamic allocation, it could be:
char str1[]="hello ";
printf("Initial size of str1 is: %zu\n", strlen(str1));
char str2[]="buddy";
char *str3 = malloc(strlen(str1) + strlen(str2) + 1);
if (!str3)
return 1;
strcpy(str3, str1);
strcat(str3,str2);
printf("%s\n",str3);
printf("Final size: %zu\n", strlen(str3));
free(str3);
This may be optimized little bit. strlen() calculates length of string at runtime and you have strings known at compile time. So we can use it:
char str1[]="hello ";
printf("Initial size of str1 is: %zu\n", strlen(str1));
char str2[]="buddy";
char *str3 = malloc(sizeof(str1) + sizeof(str2) - 1);
if (!str3)
return 1;
strcpy(str3, str1);
strcpy(str3 + sizeof(str1) - 1, str2);
printf("%s\n",str3);
printf("Final size: %zu\n", strlen(str3));
free(str3);
Also pay attention to strlen() return type: it is size_t. We should either cast it to int for printing with %d format or print with %zu.
EDIT: fixed length calculation, fixed printf formatting modifier.
I'm doing simple c excercise using visual studio.
Using strcat_s function I receive a violation exception thru this code:
char *str1;
str1 = (char *)malloc(20);
*str1 = "Ciao ";
char *str2 = "Marco";
strcat_s(str1, sizeof(str1), str2);
printf("%s", str1);
Now, if I use a predefined array whith a fixed size, strcat_s works perfectly.
How can I use pointers to char instead of array to make it work?
Any other solution or tip will be very appreciated.
Thank you in advance.
You have to copy the strings firstly into the allocated memory. If you like to know the length of a string use strlen(). sizeof() returns the size of the datatype in byte. In your case it is a pointer (4 byte on 32bit, 8 byte on 64bit machines).
The following code should work properly:
char *str1 = (char *)malloc(20);
strcpy(str1,"Ciao ");
char *str2 = (char *)malloc(20);
strcpy(str2,"Marco ");
strcat(str1, str2);
printf("%s", str1);
There are some issues with your code, and there are some general notes on strcat_s.
Your code str1 = (char *)malloc(20); *str1 = "Ciao " does not copy Ciao; *str is a single character at the first position of str, and your expression converts string literal "Ciao " (which is a pointer to a sequence of characters) to some single character (T in this case; surprising, isn't it?). One would need to use strcpy instead. An array, like char buffer[20] = "Ciao ", in contrast, works, because this (special) case is not an assignment but an initialiser of an array.
Your code sizeof(str1) gives you the size of a pointer value, which is probably 4 or 8, and has nothing to do with the actual size of the content or the memory block reserved. One should use strlen instead.
Concerning strcat_s, one should consider that it is not available on all platforms and that you have to be aware of it's special behaviour. For example, if you call strcat_s(somebuffer, 3, "somestrlongerthan3"), which exceeds the maximum length of 3 as provided, somebuffer will be an "empty" string (i.e. the first character will be set to \0.
I'd suggest to use strncat or snprintf instead. See the following variants:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main () {
char c = "Ciao "; // Gives a compiler warning and yields 'T'
#define maxlen 20
// Variant 1: start with initialized buffer, yet no "pointer" and dynamic allocation
char resultBuffer[maxlen] = "Ciao ";
size_t charactersRemaining = maxlen-strlen(resultBuffer)-1;
strncat(resultBuffer, "Marco", charactersRemaining);
// Variant 2: use dynamically allocated buffer and snprintf, with constant "Ciao".
char *resultBuffer2 = malloc(maxlen);
const char* second2 = "Marco";
snprintf(resultBuffer2, maxlen, "Ciao %s", second2);
// Variant 3: use dynamically allocated buffer and snprintf, with probably variable "Ciao" and "Marco"
char *resultBuffer3 = malloc(maxlen);
const char* first3 = "Ciao";
const char* second3 = "Marco";
snprintf(resultBuffer3, maxlen, "%s %s", first3, second3);
return 0;
}
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 am trying to create a simple datastructure that will make it easy to convert back and forth between ASCII strings and Unicode strings. My issue is that the length returned by the function mbstowcs is correct but the length returned by the function wcslen, on the newly created wchar_t string, is not. Am I missing something here?
typedef struct{
wchar_t *string;
long length; // I have also tried int, and size_t
} String;
void setCString(String *obj, char *str){
obj->length = strlen(str);
free(obj->string); // Free original string
obj->string = (wchar_t *)malloc((obj->length + 1) * sizeof(wchar_t)); //Allocate space for new string to be copied to
//memset(obj->string,'\0',(obj->length + 1)); NOTE: I tried this but it doesn't make any difference
size_t length = 0;
length = mbstowcs(obj->string, (const char *)str, obj->length);
printf("Length = %d\n",(int)length); // Prints correct length
printf("!C string %s converted to wchar string %ls\n",str,obj->string); //obj->string is of a wcslen size larger than Length above...
if(length != wcslen(obj->string))
printf("Length failure!\n");
if(length == -1)
{
//Conversion failed, set string to NULL terminated character
free(obj->string);
obj->string = (wchar_t *)malloc(sizeof(wchar_t));
obj->string = L'\0';
}
else
{
//Conversion worked! but wcslen (and printf("%ls)) show the string is actually larger than length
//do stuff
}
}
The code seems to work fine for me. Can you provide more context, such as the content of strings you're passing to it, and what locale you're using?
A few other bugs/style issues I noticed:
obj->length is left as the allocated length, rather than updated to match the length in (wide) characters. Is that your intention?
The cast to const char * is useless and bad style.
Edit: Upon discussion, it looks like you may be using a nonconformant Windows version of the mbstowcs function. If so, your question should be updated to reflect as such.
Edit 2: The code only happened to work for me because malloc returned a fresh, zero-filled buffer. Since you are passing obj->length to mbstowcs as the maximum number of wchar_t values to write to the destination, it will run out of space and not be able to write the null terminator unless there's a proper multibyte character (one which requires more than a single byte) in the source string. Change this to obj->length+1 and it should work fine.
The length you need to pass to mbstowcs() includes the L'\0' terminator character, but your calculated length in obj->length() does not include it - you need to add 1 to the value passed to mbstowcs().
In addition, instead of using strlen(str) to determine the length of the converted string, you should be using mbstowcs(0, src, 0) + 1. You should also change the type of str to const char *, and elide the cast. realloc() can be used in place of a free() / malloc() pair. Overall, it should look like:
typedef struct {
wchar_t *string;
size_t length;
} String;
void setCString(String *obj, const char *str)
{
obj->length = mbstowcs(0, src, 0);
obj->string = realloc(obj->string, (obj->length + 1) * sizeof(wchar_t));
size_t length = mbstowcs(obj->string, str, obj->length + 1);
printf("Length = %zu\n", length);
printf("!C string %s converted to wchar string %ls\n", str, obj->string);
if (length != wcslen(obj->string))
printf("Length failure!\n");
if (length == (size_t)-1)
{
//Conversion failed, set string to NULL terminated character
obj->string = realloc(obj->string, sizeof(wchar_t));
obj->string = L'\0';
}
else
{
//Conversion worked!
//do stuff
}
}
Mark Benningfield points out that mbstowcs(0, src, 0) is a POSIX / XSI extension to the C standard - to obtain the required length under only standard C, you must instead use:
const char *src_copy = src;
obj->length = mbstowcs(NULL, &src_copy, 0, NULL);
I am running this on Ubuntu linux with UTF-8 as locale.
Here is the additional info as requested:
I am calling this function with a fully allocated structure and passing in a hard coded "string" (not a L"string"). so I call the function with what is essentially setCString(*obj, "Hello!").
Length = 6
!C string Hello! converted to wchar string Hello!xxxxxxxxxxxxxxxxxxxx
(where x = random data)
Length failure!
for reference
printf("wcslen = %d\n",(int)wcslen(obj->string)); prints out as
wcslen = 11
Can u Give solution for this code of typecasting, LPCTSTR(here lpsubkey) to Char*
for below code snippet ,
char* s="HKEY_CURRENT_USER\\";
strcat(s,(char*)lpSubKey);
printf("%S",s);
here it makes error of access violation ,so what will be the solution for that?.
...thanks in advance
There are several issues with your code that might well lead to the access violation. I don't think any have anything to do with the cast you mentioned.
You are assigning a pointer to the first element of a fixed size char array to a char * and then attempt to append to this using strcat. This is wrong as there is no additional space left in the implicitly allocated string array. You will need to allocate a buffer big enough to hold the resulting string and then copy the string constant in there before calling strcat. For example, like so:
char *s = (char*)malloc(1024 * sizeof(char));
strcpy(s, "HKEY_CURRENT_USER\\");
strcat(s, T2A(lpSubKey));
printf("%s", s);
free(s);
Please note that the fixed size array I'm allocating above is bad practise. In production code you should always determine the correct size of the array on the go to prevent buffer overflows or use functions like strncat and strncpy to ensure that you are not copying more data into the buffer than the buffer can hold.
These are not the same thing. What are you trying to do?
The problem is you are trying to append to a string that you have not reserved memory for.
Try:
char s[1024] = "HKEY_CURRENT_USER";
strcat(s,(char*)lpSubKey );
printf("%S",s);
Do be careful with the arbitrary size of 1024. If you expect your keys to be much longer your program will crash.
Also, look at strcat_s.
ATL and MFC has set of macros to such conversion, where used next letters:
W - wide unicode string
T - generic character string
A - ANSI character string
OLE - BSTR string,
so in your case you need T2A macros
strcat does not attempt to make room for the combination. You are overwriting memory that isn't part of the string. Off the top of my head:
char *strcat_with_alloc(char *s1, char *s2)
{
if (!s1 || !s2) return NULL;
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
char *dest = (char *)malloc(len1 + len2 + 1);
if (!dest) return NULL;
strcpy(dest, s1);
strcat(dest, s2);
return dest;
}
now try:
char* s="HKEY_CURRENT_USER\\";
char *fullKey = strcat_with_alloc(s,(char*)lpSubKey);
if (!fullKey)
printf("error no memory");
else {
printf("%S",fullKey);
free(fullKey);
}