So I'm working through "Sams Teach Yourself C Programming in One Hour a Day, Seventh Edition" Lesson 10 Exercise 7 which asks to "Write a function that accepts two strings. Use the malloc() function to allocate enough memory to hold the two strings after they have been concatenated (linked). Return a pointer to this new string."
I am sure there are much more elegant ways to go about this than what I have attempted below. I am mostly interested in why my solution doesn't work. I have only been learning C for a few months and have no significant programming background. Please let me know why this crashes on compilation. I am using Code Blocks on Win 7 with GNU GCC Compiler if that makes a difference. Thank you :)
#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;
int main(void)
{
char *comboString;
char *array1 = "You\'re the man ";
char *array2 = "Now Dog!";
comboString = (char *)malloc(ctrtotal * sizeof(char));
concatenated(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
int ctr;
int ctr2;
for (ctr = 0; array1[ctr] != '\0'; ctr++)
array3[ctr] = array1[ctr];
ctr2 = ctr;
for (ctr = 0; array2[ctr] != '\0'; ctr++)
{
array3[ctr2 + ctr] = array2[ctr];
}
array3[ctr2 + ctr + 1] = '\0';
ctrtotal = (ctr2 + ctr + 2);
return array3;
}
Thank you for the help. After reviewing everyone's feedback on my errors I revised the code to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * concatenated(char array1[], char array2[]);
int main(void)
{
char *array1 = "Testing Testing One Two ";
char *array2 = "Three. Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));
comboString = concatenated(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
array3 = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) );
strcat(array3, array1);
strcat(array3, array2);
return array3;
}
If anyone sees any redundancies/unnecessary remaining code the could/should be deleted, please let me know. I recognize the benefit of being as concise as possible.
Your code has a bunch of issues:
int ctrtotal is never initialized, so you are mallocing 0 bytes
concatenated() is copying characters to an uninitialized array3. This pointer should point to a mallocd buffer.
If concatenated is allocating the memory, then main doesn't need to. Instead it should use the result of concatenated.
I don't want to give you the full code, and let you to miss out on this learning opportunity. So concatenated should look like this, in psuedo-code:
count = length_of(string1) + length_of(string2) + 1
buffer = malloc(count)
copy string1 to buffer
copy string2 to buffer, after string1
set the last byte of buffer to '\0' (NUL)
return buffer
In C, strings are represented as a NUL-terminated array of characters. That's why we allocate one additional byte, and terminate it with \0.
As a side-note, when dealing with strings, it is far easier to work with pointers, instead of treating them as arrays and accessing them via indices.
There's a lot of code here that just doesn't make any sense. I suggest that you first write this program on paper. Then, "execute" the program in your head, stepping through every line. If you get to something you don't understand, then you need to either fix your understanding, or your incorrect code. Don't try to write code that looks like some other bit of code.
There's also a library function called strcat which will make this task even easier. See if you can figure out how to use it here.
Spoiler --> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *concatenate2(const char* s1, const char* s2);
int main(void)
{
char *comboString;
char *array1 = "You're the man ";
char *array2 = "Now Dog!";
comboString = concatenate2(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char *concatenate2(const char* s1, const char* s2)
{
char *result;
result = malloc(strlen(s1) + strlen(s2) + 1);
*result = '\0';
strcat(result, s1);
strcat(result, s2);
return result;
}
You forgot to allocate memory for third, concatenated, array of chars (in function)
You should do something like this:
char *array3;
array3 = (char *)malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) ); // +1 for '\0' character.
and then write chars from first and second array into third.
Perhaps a stroll through the question code is best.
#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;
Notice that the above line declares ctrtotal to be an integer, but does not specify the value of the integer.
int main(void)
{
char *comboString;
char *array1 = "You\'re the man ";
char *array2 = "Now Dog!";
comboString = (char *)malloc(ctrtotal * sizeof(char));
Notice that the above line allocates memory and sets 'comboString' to point at that memory. However, how much memory is being allocated?
(ctrtotal[???] * sizeof(char)[1])
What is the value of (??? * 1) ? This is a problem.
concatenated(array1, array2);
The intent of the line above is that array1["You\'re the man "] and array2["Now Dog!"] will be joined to form a new string["You\'re the man Now Dog!"], which will be placed in allocated memory and returned to the caller.
Unfortunately, the returned memory containing the string is not captured here. For example, perhaps the above line should be:
comboString = concatenated(array1, array2);
While this make sense, for this line, it begs a question of the purpose of the lines:
comboString = (char *)malloc(ctrtotal * sizeof(char));
as well as the global variable:
int ctrtotal;
and the later reference:
ctrtotal = (ctr2 + ctr + 2);
Perhaps all of these 3 lines should be deleted?
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
Notice that '*array3' is now a defined pointer, but it is not pointing anywhere specific.
int ctr;
int ctr2;
The purpose of 'concatenated()' is to join array1 and array1 into allocated array3. Unfortunately, no memory is allocated to array3.
Below, the memory where array3 is pointing will be modified. Since array3 is not pointing anywhere specific, this is not safe.
Prior to modifying memory where array 3 is pointing, it is important to point array3 at memory where it is safe to modify bytes. I suggest that the following code be inserted here:
array3 = malloc(strlen(array1) + strlen(array2) + 1);
Now, array3 points to allocated memory, large enough to hold both strings plus the string termination character '\0'.
for (ctr = 0; array1[ctr] != '\0'; ctr++)
array3[ctr] = array1[ctr];
ctr2 = ctr;
for (ctr = 0; array2[ctr] != '\0'; ctr++)
{
array3[ctr2 + ctr] = array2[ctr];
}
array3[ctr2 + ctr + 1] = '\0';
ctrtotal = (ctr2 + ctr + 2);
return array3;
}
I am responding to your revised code. There are a few bugs in it.
...
char *array2 = "Three. Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));
comboString = concatenated(array1, array2);
...
The malloc is unnecessary here and actually a bug in your code. You are allocating a block of memory, but you then replace the value of the pointer comboString with the pointer from the call to concatenated. You lose the pointer to the block of memory allocated in main and thus never are able to free it. Although this will not be a problem in the code you have right now since main returns soon after, it could cause a memory leak in an application that ran for a longer time.
strcat(array3, array1);
This is also a bug. strcat is going to walk through array3 to find '\0' and then once it is found copy in array1 from that index on, replacing the '\0'. This works fine here since the memory block that was allocated for array3 is going to be zeroed out** as no block has yet been freed by your program. However, in a longer running program you can end up with a block that does not start with a '\0'. You might end up corrupting your heap, getting a segfault, etc.
To fix this, you should use strcpy instead, array3[0] = '\0', or *array3 = '\0'
** When the operating system starts your program it will initialize the memory segment it reserves for it with zeroes (this actually isn't a necessity but will be true on almost any operating system). As your program allocates and frees memory, you will eventually wind up with values that are not zero. Note that the same bug can occur with uninitialized local variables such as:
int i;
for (; i < 10; i++);
This loop will run 10 times whenever the space on the runtime stack where i is stored is already 0.
Overall, the takeaway is to be very careful with arrays and dynamic memory allocation in C. C offers you none of the protections that modern languages do. You are responsible for making sure you stay within the bounds of your array, initialize your variables, and properly allocate and free your memory. Neglecting these things will lead to obscure bugs that will take you hours to find, and most of the times these bugs will not appear right away.
Related
First of all Thanks for visiting my question... :)
I am interested in competitive programming, so I daily do some amount of problem-solving, however, I only know C language at a decent level, and I often face problems while dynamically allocating something as usual, especially for strings and 2D arrays.
But I somehow manage to find ways (thanks to StackOverflow), for example, I wanted to create a function that scans string dynamically until the user enters space or new line, so I came up with the solution below and it works perfectly:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// scanf("%[^\n]%*c", str);
char *create_string(char *ptr)
{
ptr = (char *)malloc(0 * sizeof(char));
unsigned int size = 0;
char c = 0;
while (1)
{
scanf("%c", &c);
if (c == 32 || c == 10)
{
break;
}
size++;
ptr = (char *)realloc(ptr, size * sizeof(char));
ptr[size - 1] = c;
}
ptr = (char *)realloc(ptr, (size + 1) * sizeof(char));
ptr[size] = '\0';
return ptr;
}
int main()
{
char *str;
str = create_string(str);
printf("%s", str);
printf("\n%lu", strlen(str));
return 0;
}
And now for curiosity purposes, I want to know how can I do this same thing using the void function?, something like:
char *str;
create_string(&str);
should start storing everything in the dynamic memory which is pointed by str.
Also, please if you have more knowledge to show in DMA for 2D array, then please show me it, feel free to give examples with different problems.
And also How can I stop scanning the string (which was allocated dynamically) with specific string ending? for example, scanning(any kind of scanning, i.e. int, bool, custom structures etc...) should stop if user enters string "STOP", Please feel free to give pictorial examples.
Because I am sure that this question is burning like a fire in beginner's and intermediate C programmers' minds.
As C passes arguments by value, to return something via an out parameter, you need to pass in a pointer to it. So to return a char * it would:
void create_string(char **s) {
*s = malloc(42);
}
Here is your refactored code. I changed the following:
Eliminate return value of update caller.
Initialize *ptr = malloc(1) for the trailing '\0'. It eliminates an unnecessary and implementation defined malloc(0). This also eliminates the (*ptr)[size] = ... which looks wrong as the last index is expected to be size - 1. Alternatively initialize it to NULL.
Use character constants instead of magic values (32, 10).
sizeof(char) is defined as 1 so leave it out.
Reduced scope of variable c.
free() memory allocated.
(cosmetic) Use size_t size instead of unsigned int size.
(cosmetic) Avoid the noise of casting casting void *.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void create_string(char **ptr) {
*ptr = malloc(1);
size_t size = 1;
for(;;) {
char c;
scanf("%c", &c);
if (c == ' ' || c == '\n') break;
(*ptr)[size-1] = c;
size++;
*ptr = realloc(*ptr, size);
}
(*ptr)[size-1] = '\0';
}
int main() {
char *str;
create_string(&str);
printf("%s\n", str);
printf("%zu\n", strlen(str));
free(str);
}
I didn't fix these issue:
Check return value of malloc(), realloc().
v = realloc(v, ...) is unsafe and will leak memory if realloc() fails. You need to do char *tmp = realloc(v,...); if(!tmp) { // err }; v = tmp;.
Check return value of scanf() otherwise you may be operating on uninitialized data.
Use scanf("%s", ..) instead of for(;;) { scanf("%c", ...). It's more efficient to allocate a chunk at a time instead of per byte.
If user enters ctrl-d (EOF) the program will go into an infinite loop.
It's good idea to separate i/o from logic (i.e. let caller do the scanf(). That way create_string() is much more reusable.
I will say honestly, this isn't my code. It's my brother's who's studying with me but he's a ahead of me.
Please notice char *str and char *resultString in the function char *replaceWord().
/*Suppose you have a template letter.txt. You have to fill in values to a template. Letter.txt looks something like this:
Thanks {{name}} for purchasing {{item}} from our outlet {{outlet}}. Please visit our outlet {{outlet}} for any kind of problems. We plan to serve you again soon.
You have to write a program that will automatically fill the template.For this, read this file and replace these values:
{{name}} - Harry
{{item}} - Table Fan
{{outlet}} - Ram Laxmi fan outlet
Use file functions in c to accomplish the same.*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * replaceWord(const char * str, const char * oldWord, const char * newWord)
{
char * resultString;
int i, count = 0;
int newWordLength = strlen(newWord);
int oldWordLength = strlen(oldWord);
for (i = 0; str[i] != '\0'; i++)
{
if (strstr(&str[i], oldWord) == &str[i])
{
count++;
//Jumping over the word and continuing
i = i + oldWordLength - 1;
}
}
//dynamically allocation memory to resultString since it can be big or samll depending on the size of the newWord.
/*i = old string length , count = no. of times the word appeared in the string,
newWordLength-oldWordLength=difference between the new word and the old word
+1 for the null character '\0'
Basically we are saying that add the size required for the newWord to the strings length i.e i;
*/
resultString = (char *)malloc(i + count * (newWordLength - oldWordLength) + 1);
i = 0; //refreshing the i for the while loop
while (*str)
{
if (strstr(str, oldWord) == str)
{
strcpy(&resultString[i], newWord);
i += newWordLength;
str += oldWordLength;
}
else
{
resultString[i] = *str;
i+=1;
str+=1;
}
}
resultString[i] = '\0';
return resultString;
}
int main()
{
FILE *ptr = NULL;
FILE *ptr2 = NULL;
ptr = fopen("letter.txt", "r"); //where the template is stored
ptr2 = fopen("newLetter.txt", "w"); //where the new bill will be stored.
char str[200];
fgets(str, 200, ptr); //store the bill template in the str variable.
printf("The original bill template is : %s\n", str);
//Calling the replacing fucntion
char *newStr = str; //newStr will store the new bill i.e generated
newStr = replaceWord(str, "{{name}}", "Mary");
newStr = replaceWord(newStr, "{{item}}", "Waffle Machine");
newStr = replaceWord(newStr, "{{outlet}}", "Belgium Waffle");
printf("\nThe bill generated is:\n%s", newStr);
fprintf(ptr2, "%s", newStr);
fclose(ptr);
fclose(ptr2);
return 0;
}
Can someone explain why the pointer *str and *resultString are expressed different ways in the program and what are they doing? Sometimes it's *str, &str or str[i].
Please explain.
I know that a pointer is used to keep the address of the other variables but this code is still a mystery to me.
Also why was the function a pointer?
NOTE:"He said that's how it works" when I asked how.
Please help!! I can't focus on other things.
If you can't explain ;a link of explanation would be fine as well.
Sometimes it's *str, &str or str[i]
Those are operators.
*str
str is a poitner to a char, and having a * over it dereferences it. Meaning it fetches the value from the memory that it is pointing to. A pointer may not always point to a variable though, it can be any arbitrary memory address. But dereferencing memory that is not yours will result in Segmentation fault which is the my most beloved error that occurs almost everytime when processing arrays.
str[i]
This is the same as *(str + i). Meaning it increments the memory address by i * sizeof(<datatype of what str points to>). Then it fetches the value from that incremented address. This is used for getting elements of an array.
&str
This just given the address of the variable str, which is a pointer. So, it returns a pointer to a pointer(ie. str). A pointer to a pointer can exist.
The function is not a pointer. Instead, it returns a pointer which is *resultString. It is so that a string can be returned. The string had been initialized in this line:
resultString = (char *)malloc(i + count * (newWordLength - oldWordLength) + 1);
The comment explaining this is not complete.
//dynamically allocation memory to resultString since it can be big or samll depending on the size of the newWord.
/*i = old string length , count = no. of times the word appeared in the string,
newWordLength-oldWordLength=difference between the new word and the old word
+1 for the null character '\0'
Basically we are saying that add the size required for the newWord to the strings length i.e i;
*/
It also misses one key reason why malloc is being used instead of normal allocation. malloc allocates your variables on the heap which is shared among all functions and threads. While normal initialization would allocate it on the stack which is popped off when the function ends. So, no use after the function with the stack, so it should be used on the heap. And it is also for dynamic allocation.
I am learning C and I have written the following strcat function:
char * stringcat(const char* s1, const char* s2) {
int length_of_strings = strlen(s1) + strlen(s2);
char s3[length_of_strings + 1]; // add one for \0 at the end
int idx = 0;
for(int i=0; (s3[idx]=s1[i]) != 0; idx++, i++);
for(int i=0; (s3[idx]=s2[i]) != 0; idx++, i++);
s3[idx+1] = '\0';
// s3 is a character array;
// how to get a pointer to a character array?
char * s = s3;
return s;
}
That part that looks odd to me is where I have to "re-assign" the character array to a pointer, otherwise C complains that my return is a memory address. I also tried "casting" the return value to (char *) s3, but that didn't work either.
What is the most common way to do this "conversion"? Is this a common pattern in C programs?
There are many ways to handle this situation, but returning a pointer to stack-allocated memory inside the function isn't one of them (the behavior is undefined; consider this memory untouchable once the function returns).
One approach is to allocate heap memory using malloc inside the function, build the result string, then return the pointer to the newly allocated memory with the understanding that the caller is responsible for freeing the memory.
Here's an example of this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *stringcat(const char* s1, const char* s2) {
int i = 0;
int s1_len = strlen(s1);
int s2_len = strlen(s2);
char *result = malloc(s1_len + s2_len + 1);
result[s1_len+s2_len] = '\0';
for (int j = 0; j < s1_len; j++) {
result[i++] = s1[j];
}
for (int j = 0; j < s2_len; j++) {
result[i++] = s2[j];
}
return result;
}
int main(void) {
char *cat = stringcat("hello ", "world");
printf("%s\n", cat); // => hello world
free(cat);
return 0;
}
Another approach is for the caller to handle all of the memory management, which is similar to how strcat behaves:
/* Append SRC on the end of DEST. */
char *
STRCAT (char *dest, const char *src)
{
strcpy (dest + strlen (dest), src);
return dest;
}
man says:
The strcat() function appends the src string to the dest string, overwriting the terminating null byte ('\0') at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable; buffer overruns are a favorite avenue for attacking secure programs.
The problem isn't converting from array to pointer; that happens all the time implicitly, and it's no big deal. Your problem is you've just returned a pointer to invalid memory. The array you allocated in the function disappears when the function returns, and dereferencing a pointer to that array is undefined behavior (returning the pointer isn't technically illegal, but any good compiler warns you, because a pointer that is never dereferenced is usually pretty useless).
If you want to return a new array with the concatenated string, you must use dynamically allocated memory, e.g. from malloc/calloc; making the array static would also work (it would now be persistent global memory), but it would make your function both non-reentrant and non-threadsafe, so it's usually frowned on.
Your little trick of assigning to a pointer and returning the pointer may have fooled the compiler into thinking you weren't doing anything illegal, but it did nothing to make your code safer.
You might be used to languages with more dynamic memory handling, but your function here won't work because C strings are just a block of local memory which disappears when you return. That means that whatever you write to char s3[] will disappear after the return (the details vary and the memory can sometimes stick around long enough for you to think it worked even when it didn't).
Normally you'd want to allocate the memory before calling the function, and pass it in as a parameter, as in:
void stringcat(const char * first, const char * second, char * dest, const size_t dest_len)
Called like this:
char title[] = "Mr. ";
char last[] = "Jones";
char addressname[sizeof(title) + sizeof(last)];
stringcat(title, last, addressname, sizeof(addressname));
The other way to do it is to allocate the memory in the function using malloc(), and return that, but you have to remember to free it in the code when you're done with it.
The following is a piece of code where the user enters unknown amounts of words until 'E' is entered, whereupon the program should stop and print out all of the entered words. However, when run this program produces a segmentation error. Did I access some memory I shouldn't have?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 10
#define NUM_OF_WORDS 10
int main(void)
{
int num_words = 10;
char *word= malloc(CAPACITY*sizeof(char));
char **w=(char **) malloc(num_words*sizeof(char));
int i;
for(i = 0 ; scanf("%s", word)==1; ++i)
{
if(*word == 'E')
break;
if( i == num_words-1)
w = (char **)realloc(w, (num_words *=2) * sizeof(char));
w[i] =(char *) malloc(strlen(word)+1 * sizeof(char));
strcpy(w[i], word);
}
int x = 0;
for(x = 0 ; x<num_words ; x++)
printf("%s", w[x]);
return 0;
}
Your initial allocation code reads:
char *word = malloc(CAPACITY*sizeof(char));
char **w = (char **) malloc(num_words*sizeof(char));
Both these allocate 10 bytes of memory. Your second one should read:
char **w = (char **) malloc(num_words*sizeof(char *));
or:
char **w = malloc(num_words*sizeof(*w));
These both allocate enough memory for 10 pointers (which might be eight times as much memory as your original code). The second is arguably better style; the first is indubitably the classic style. In C, the cast on malloc() is not necessary; in C++, it is.
This may not be the whole problem; it is almost certainly a contributory factor.
Also, you aren't checking your memory allocations; that is not advisable. You should always check them.
This code:
if (i == num_words-1)
w = (char **)realloc(w, (num_words *=2) * sizeof(char));
is playing with fire on two accounts (plus a repeat of the previously diagnosed problem):
The assignment within the argument list is...not generally reckoned to be a good idea. I wouldn't write code with that in place, and I'd send back code I was asked to review that contained it. It isn't technically wrong; it will work. But it does not make life easier for the maintenance programmers who come after.
You should never reallocate a pointer such as w and assign the new space to the same pointer. If the memory allocation fails, you'll get back a null pointer, so you've lost the only pointer to the previous data, which is still allocated. That's a memory leak. Also, if the memory allocation fails, you have to undo the assignment within the argument list because the allocated space is still at the original size. I think you'd be better off using:
if (i == num_words - 1)
{
size_t new_size = (num_words * 2);
char **new_data = realloc(w, new_size * sizeof(*new_data));
if (new_data == 0)
...handle error; w is still valid, and num_words is still correct too...
num_words = new_size;
w = new_data;
}
Your variable num_words holds the current maximum size of the w array, but that isn't the same as the number of words actually in the array.
When you loop through the w array you are looping through too many items - some elements of the w do not have a valid string in them - trying to print them will cause a segfault.
I am having trouble concatenating strings in C, without strcat library function. Here is my code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
char *b1=(char*)malloc(100);
strcpy(b1,"Ratnavel");
int i;
int len=strlen(a1);
for(i=0;i<strlen(b1);i++)
{
a1[i+len]=b1[i];
}
a1[i+len]='\0';
printf("\n\n A: %s",a1);
return 0;
}
I made corrections to the code. This is working. Now can I do it without strcpy?
Old answer below
You can initialize a string with strcpy, like in your code, or directly when declaring the char array.
char a1[100] = "Vivek";
Other than that, you can do it char-by-char
a1[0] = 'V';
a1[1] = 'i';
// ...
a1[4] = 'k';
a1[5] = '\0';
Or you can write a few lines of code that replace strcpy and make them a function or use directly in your main function.
Old answer
You have
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|0|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_]
b1 [R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_|_|_|_|_|_]
and you want
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_]
so ...
a1[5] = 'R';
a1[6] = 'a';
// ...
a1[12] = 'l';
a1[13] = '\0';
but with loops and stuff, right? :D
Try this (remember to add missing bits)
for (aindex = 5; aindex < 14; aindex++) {
a1[aindex] = b1[aindex - 5];
}
Now think about the 5 and 14 in the loop above.
What can you replace them with? When you answer this, you have solved the programming problem you have :)
char a1[] = "Vivek";
Will create a char array a1 of size 6. You are trying to stuff it with more characters than it can hold.
If you want to be able to accommodate concatenation "Vivek" and "Ratnavel" you need to have a char array of size atleast 14 (5 + 8 + 1).
In your modified program you are doing:
char *a1=(char*)malloc(100); // 1
a1 = "Vivek"; // 2
1: Will allocate a memory chunk of size 100 bytes, makes a1 point to it.
2: Will make a1 point to the string literal "Vivek". This string literal cannot be modified.
To fix this use strcpy to copy the string into the allocated memory:
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
Also the for loop condition i<strlen(b1)-1 will not copy last character from the string, change it to i<strlen(b1)
And
a1[i]='\0';
should be
a1[i + len]='\0';
as the new length of a1 is i+len and you need to have the NUL character at that index.
And don't forget to free your dynamically allocated memory once you are done using it.
You cannot safely write into those arrays, since you have not made sure that enough space is available. If you use malloc() to allocate space, you can't then overwrite the pointer by assigning to string literal. You need to use strcpy() to copy a string into the newly allocated buffers, in that case.
Also, the length of a string in C is computed by the strlen() function, not length() that you're using.
When concatenating, you need to terminate at the proper location, which your code doesn't seem to be doing.
Here's how I would re-implement strcat(), if needed for some reason:
char * my_strcat(char *out, const char *in)
{
char *anchor = out;
size_t olen;
if(out == NULL || in == NULL)
return NULL;
olen = strlen(out);
out += olen;
while(*out++ = *in++)
;
return anchor;
}
Note that this is just as bad as strcat() when it comes to buffer overruns, since it doesn't support limiting the space used in the output, it just assumes that there is enough space available.
Problems:
length isn't a function. strlen is, but you probably shouldn't call it in a loop - b1's length won't change on us, will it? Also, it returns a size_t, which may be the same size as int on your platform but will be unsigned. This can (but usually won't) cause errors, but you should do it right anyway.
a1 only has enough space for the first string, because the compiler doesn't know to allocate extra stack space for the rest of the string since. If you provide an explicit size, like [100], that should be enough for your purposes. If you need robust code that doesn't make assumptions about what is "enough", you should look into malloc and friends, though that may be a lesson for another day.
Your loop stops too early. i < b1_len (assuming you have a variable, b1_len, that was set to the length of b1 before the loop began) would be sufficient - strlen doesn't count the '\0' at the end.
But speaking of counting the '\0' at the end, a slightly more efficient implementation could use sizeof a1 - 1 instead of strlen(a1) in this case, since a1 (and b1) are declared as arrays, not pointers. It's your choice, but remember that sizeof won't work for pointers, so don't get them mixed up.
EDIT: New problems:
char *p = malloc(/*some*/); p = /* something */ is a problem. = with pointers doesn't copy contents, it copies the value, so you're throwing away the old pointer value you got from malloc. To copy the contents of a string into a char * (or a char [] for that matter) you'd need to use strcpy, strncpy, or (my preference) memcpy. (Or just a loop, but that's rather silly. Then again, it may be good practice if you're writing your own strcat.)
Unless you're using C++, I wouldn't cast the return value of malloc, but that's a religious war and we don't need one of those.
If you have strdup, use it. If you don't, here is a working implementation:
char *strdup(const char *c)
{
size_t l = strlen(c);
char *d = malloc(l + 1);
if(d) memcpy(d, c, l + 1);
return d;
}
It is one of the most useful functions not in the C standard library.
You can do it using strcpy() too ;)
char *a = (char *) malloc(100);
char *b = (char *) malloc(100);
strcpy(a, "abc"); // initializes a
strcpy(b, "def"); // and b
strcpy((a + strlen(a)), b); // copy b at end of a
printf("%s\n",a); // will produce: "abcdef"
i think this is an easy one.
#include<stdio.h>
int xstrlen(char *);
void xstrcat(char *,char *,int);
void main()
{
char source[]="Sarker";
char target[30]="Maruf";
int j=xstrlen(target);
xstrcat(target,source,j);
printf("Source String: %s\nTarget String: %s",source,target);
}
int xstrlen(char *s)
{
int len=0;
while(*s!='\0')
{
len++;
s++;
}
return len;
}
void xstrcat(char *t,char *s,int j)
{
while(*t!='\0')
{
*t=*t;
t++;
}
while(*s!='\0')
{
*t=*s;
s++;
t++;
}
}
It is better to factor out your strcat logic to a separate function. If you make use of pointer arithmetic, you don't need the strlen function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* To completely get rid of this,
implement your our strcpy as well */
static void
my_strcat (char* dest, char* src)
{
while (*dest) ++dest;
while (*src) *(dest++) = *(src++);
*dest = 0;
}
int
main()
{
char* a1 = malloc(100);
char* b1 = malloc(100);
strcpy (a1, "Vivek");
strcpy (b1, " Ratnavel");
my_strcat (a1, b1);
printf ("%s\n", a1); /* => Vivek Ratnavel */
free (a1);
free (b1);
return 0;
}