I have made this program to emulate strcat functionality but there is an error with printf which I don't understand...
Here is the code:
#include <stdio.h>
char *mystrcat(char *s1, char *s2);
int main(void)
{
char *s1,*s2;
s1="asdad";
s2="asdad";
s1=mystrcat(s1,s2);
printf(s1);
return 0;
}
char *mystrcat(char *s1,char *s2)
{
int i,j;
for(i=0;s1[i]<'\0';i++) ;
for(j=0;s2[j]!='\0';j++) s1[i+j]=s2[j];
s1[i+j]='\0';
return s1;
}
The first problem is that s1 doesn't have enough space to append s2 to it. You need the size of the buffer pointed to by s1 to be at least strlen(s1) + strlen(s2) + 1 (the + 1 being the NUL terminator).
The second problem is that string literals are read-only. You assign s1 from "asdad", which creates a pointer to (potentially) read-only memory. Of course the first problem means that you wouldn't have enough space to append to the end even if it were writeable, but this is one of the common pitfalls in C and worth mentioning.
Third problem (already mentioned in another answer) is that the comparison s1[i] < '\0' is wrong and you will not correctly find the length of s1 since the loop will not run even a single iteration. The correct condition is the same as in your second loop, != '\0'. (This masks problem 1 since then you are inadvertently overwriting s1 from the beginning.)
At least, s1[i] < '\0' is the same as s1[i] < 0, which is always false.
Related
I need help with char array. I want to create a n-lenght array and initialize its values, but after malloc() function the array is longer then n*sizeof(char), and the content of array isnt only chars which I assign... In array is few random chars and I dont know how to solve that... I need that part of code for one project for exam in school, and I have to finish by Sunday... Please help :P
#include<stdlib.h>
#include<stdio.h>
int main(){
char *text;
int n = 10;
int i;
if((text = (char*) malloc((n)*sizeof(char))) == NULL){
fprintf(stderr, "allocation error");
}
for(i = 0; i < n; i++){
//text[i] = 'A';
strcat(text,"A");
}
int test = strlen(text);
printf("\n%d\n", test);
puts(text);
free(text);
return 0;
}
Well before using strcat make
text[0]=0;
strcat expects null terminated char array for the first argument also.
From standard 7.24.3.1
#include <string.h>
char *strcat(char * restrict s1,
const char * restrict s2);
The strcat function appends a copy of the string pointed to by s2
(including the terminating null character) to the end of the string
pointed to by s1. The initial character of s2 overwrites the null
character at the end of s1.
How do you think strcat will know where the first string ends if you don't
put a \0 in s1.
Also don't forget to allocate an extra byte for the \0 character. Otherwise you are writing past what you have allocated for. This is again undefined behavior.
And earlier you had undefined behavior.
Note:
You should check the return value of malloc to know whether the malloc invocation was successful or not.
Casting the return value of malloc is not needed. Conversion from void* to relevant pointer is done implicitly in this case.
strlen returns size_t not int. printf("%zu",strlen(text))
To start with, you're way of using malloc in
text = (char*) malloc((n)*sizeof(char)
is not ideal. You can change that to
text = malloc(n * sizeof *text); // Don't cast and using *text is straighforward and easy.
So the statement could be
if(NULL == (text = (char*) malloc((n)*sizeof(char))){
fprintf(stderr, "allocation error");
}
But the actual problem lies in
for(i = 0; i < n; i++){
//text[i] = 'A';
strcat(text,"A");
}
The strcat documentation says
dest − This is pointer to the destination array, which should contain
a C string, and should be large enough to contain the concatenated
resulting string.
Just to point out that the above method is flawed, you just need to consider that the C string "A" actually contains two characters in it, A and the terminating \0(the null character). In this case, when i is n-2, you have out of bounds access or buffer overrun1. If you wanted to fill the entire text array with A, you could have done
for(i = 0; i < n; i++){
// Note for n length, you can store n-1 chars plus terminating null
text[i]=(n-2)==i?'A':'\0'; // n-2 because, the count starts from zero
}
//Then print the null terminated string
printf("Filled string : %s\n",text); // You're all good :-)
Note: Use a tool like valgrind to find memory leaks & out of bound memory accesses.
I was trying to implement strcat by myself, It seems to work but I don't understand how come p has '\0' at its end? it didn't copy it from b and it shouldn't be there without putting it. Any explanation? The output is "yesMichaelJudy".
#include<string.h>
#include<stdio.h>
#include <stdlib.h>
#include<conio.h>
char* strcat1( char *s1, const char *s2 )
{
register char *p = s1;
while ( *p )
++p;
while (*s2){
*p=*s2;
++p;
++s2;
}
if (*p=='\0') printf("yes");
++p;
p='\0';
return s1;
}
int main(){
char* a;
char* b;
char* result;
result=(char *)calloc(20,sizeof(char));
a=(char *) calloc(20,sizeof(char));
b=(char *) calloc(20,sizeof(char));
strcpy (a,"Michael");
strcpy (b,"Judy");
result=strcat1(a,b);
printf(result);
getch();
return 1;
}
You're allocating the space larger than it needs to be and you're using calloc() which by definition clears all the characters to zero; therefore the extra characters at the end are zero.
strcpy copies the NUL character at the end of a string. Even if it didn't, you're using calloc to allocate your a and b, and calloc allocates and zeros the memory. Since you're allocating more space than you use (allocating 20 bytes, using 4 for Judy and 7 for Michael) you have some zero bytes after the strings anyway.
p='\0';
That's nonsense. It does nothing useful. It will also generate at least a compiler warning if not an error. The code should be
*p='\0';
Which is what puts \0 at the end of the string.
strcpy() null-terminates the string. But even if it didn't, calloc() puts it there. calloc() zeroes out the allocated memory. As soon as you allocated the memory, a and b are just a bunch of string-terminators.
calloc zero initializes ( ie fills it with NUL or '\0') the allocated buffer.
p in your strcat1 points into the array passed through parameter s1. And parameter s1 corresponds to argument a in main. The content of array a in main is filled with data by strcpy (a,"Michael"). This is what put that '\0' at the end of that data. strcpy did that. (You can also say that that '\0' came from "Michael" since "Michael" also has a '\0' at the end, even if it is not specified explicitly).
char a[10];
scanf("%s",a);
int i=0;
while(a[i]!='\0')
printf("\n%c",a[i++]); //similar to printf("%s",a);
char *b;
b=malloc(10*sizeof(char));
scanf("%s",b);
i=0;
while((b+i)!='\0')
printf("\n%c",*(b+i++)); //not similar to printf("%s",a);
For input "abcd", the first loop prints a[] is it would be with printf(). But the same is not true for *b.
Second loops continues for too many until it encounters a '\0'.
So, does this mean '\0' is appended at the end of character strings automatically but not at the end of char type pointers?
And whose job is it to append this '\0'? Compiler's?
You forgot to dereference the pointer you get with b+i. It should be:
while (*(b + i) != '\0') // or while (b[i] != '\0') or while(b[i])
b + i just gets you an address, you have to dereference it to actually look at what the memory is pointing at and see if it's the NUL-terminator. The x[y] notation is equivalent to *(x + y).
Also don't forget to free the memory you allocated with malloc.
Dereferencing issue.
In the line (b+i) should be replaced with either:
*(b+i)
or
b[i]
Additionally, if you are just taking in strings, you should consider using fgets() instead of scanf, as it can help you avoid the user typing in too many characters and crashing your program.
Finally, you might consider using calloc() instead of malloc() as it automatically sets the contents of the array you allocate to be all-zeros rather than random garbage.
As an example:
#include <stdio.h>
#define MAX_BUFFER_LENGTH
int main(void) {
char a[MAX_BUFFER_LENGTH];
char *b;
fgets(a,MAX_BUFFER_LENGTH,stdin);
int i=0;
while(a[i]!='\0') {
printf("\n%c",a[i++]);
}
b=calloc(MAX_BUFFER_LENGTH,sizeof(char));
fgets(b,MAX_BUFFER_LENGTH,stdin);
i=0;
while(*(b+i)!='\0') {
printf("\n%c",*(b+i++));
}
// Done
return 0;
}
This is a much safer way to approach the problem you are solving.
Good luck!
I am writing a function which expands the string, str1 and stores it as str2. By expansion, I mean if str1 has "a-d", it should be stored in str2 as "abcd". I have written the following code. I get a debug error that stack around the variable str1 is corrupted.
Can someone please point out what's going wrong?
Thanks.
#include <stdio.h>
void expand(char s1[], char s2[]);
int main() {
char s1[] = "Talha-z";
char s2[] = "";
expand(s1, s2);
printf(s2);
}
void expand(char s1[], char s2[]) {
int i = 0;
int j= 0;
int k, c_next;
while ( s1[i] != '\0') {
switch (s1[i]) {
case ('-') :
c_next = s1[i+1];
for ( k = 1; k < c_next; k++) {
s2[j] = s1[i] + k;
j++;
}
break;
}
i++;
j++;
}
s2[j] = '\0';
}
You are not allocating sufficient memory for your target string (s2). But you are attempting to write to it, which means you will be writing into memory that you don't own, causing the corruption.
You will need to use dynamic allocation for s2 (i.e. by using malloc), but you will first need to calculate how much memory you need.
char s2[] = "";
This is equivalent to writing
char s2[1] = { '\0' };
It cannot hold more than a single character (or none at all, if the NUL terminator is required).
The problem is that when you initialize s2, you give it enough room for 1 character (i.e. the null terminating '\0'). Thus when you write into s2:
s2[j] = ...
there are no guarantees about what memory you're writing into.
To allocate memory for s2 dynamically, you need to use malloc. In other words, you need to figure out how much memory is required (i.e. by finding the length of the expanded string) and then give s2 that much memory, and finally fill it in via the procedure you have written.
The string s2 at present is on the stack for local variables for main() and is allocated only one byte for one character. When you call the function, it gets passed stack addresses for s1 and s2. The code is over-writing whatever is next to s2 on the stack of function main(). Hence, the error. Please use dynamic memory allocation as already suggested by Mr. Oli above.
Hope my explanation helps you.
I have written a program for concatenation two strings, and it is throwing segmentation fault during run time at line s1[i+j] = s2[j], in for loop..... And i am not able to figure out, why it is happening so.... Kindly coreect me, where am i going wrong.
char* concatenate(char *s1, char *s2)
{
int i,j=0;
for(i=0; s1[i] != '\0'; i++);
for(j=0; s2[j] != '\0'; j++)
{
s1[i+j] = s2[j];
}
s1[i+j] = s2[j];
return s1;
}
char *s1 = (char *) malloc(15);;
char *s2 ;
s1 = "defds";
s2 = "abcd";
s1 = concatenate(s1,s2);
// printf("\n\n%s\n\n",s1);
s1 = "rahul";
This line does not copy the string "rahul" into the buffer pointed to by s1; it reassigns the pointer s1 to point to the (not modifiable) string literal "rahul"
You can get the desired functionality by using your concatenate function twice:
char *s1 = (char *) malloc(15);
s1[0] = '\0'; // make sure the buffer is a null terminated string of length zero
concatenate(s1, "rahul");
concatenate(s1, "bagai");
Note that the concatenate function is still somewhat unsafe since it blindly copies bytes, much like strcat does. You'll want either to be very sure that the buffer you pass it is large enough, or to modify it to take a buffer length like strncat takes.
When you do s1 = "rahul"; you are overwriting the memory you just allocated. This line doesn't copy "rahul" to the malloc'ed area, it changes s1 to point to the string constant "rahul" and throws away the pointer to the malloc'ed memory.
Instead, you should use strcpy to copy the string to the malloc'ed area:
// s1 = "rahul";
strcpy(s1, "rahul");
This will fix your call to concatenate since s1 will now point to the correct 15-byte area of memory.
Alternatively, you could eschew the dynamic allocation and allocate+assign the initial string all at once:
char s1[15] = "rahul";
That will allocate 15 bytes on the stack and copy "rahul" into that space. Note a subtlety here. In this case it is in fact correct to use =, whereas it is incorrect when s1 is declared as char *s1.
One important debugging lesson you can learn from this is that when your program crashes on a particular line of code that doesn't mean that's where the bug is. Often you make a mistake in one part of your program and that mistake doesn't manifest itself in a crash until later on. This is part of what makes debugging such a delightfully frustrating process!
You don't have to write your own string concatenation, there are already functions in the standard libary to do this task for you!
#include <string.h>
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
In the second piece of code, you allocate a buffer of size 15 and then assign it to s1. Then you assign "rahul" to s1, which leaks the memory you just allocated, and assigns s1 to a 6-byte piece of memory that you likely cannot write to. Change s1 = "rahul"; to strcpy( s1, "rahul" ); and you might have better luck.
I agree with the other answers though, the concatenate function is dangerous.