I'm trying to copy a string str into str using pointers. i think this can be achieved using a single pointer itself. whenever i run my code im getting str1 to display but with excessive unwanted garbage characters. please help. provide some insights
#include<stdio.h>
void main()
{
char str[10];
char str1[10];
printf("Enter a string");
scanf("%s",str);
char *p;
char *q;
int len=0,i=0;
p=&str;
q=&str;
while (*p!='\0')
{
len=len+1;
p=p+1;
}
printf("%d",len);
printf("\n");
while (len>0)
{
str1[i]=*q;
len=len-1;
}
printf("%s",str1);
}
str1[i] is always the same element because you never increment i. Thus all the other elements remain untouched and there is never an opportunity for the null terminator of q to be copied over.
Then, when you print it, the program has undefined behaviour.
It would probably be better to loop i from 0 to len.
You should also consider initialising your arrays with = {}, so that they contain nulls in the first place.
Furthermore, your scanf is extraordinarily unsafe as it performs no bounds checking.
Here you have an example:
char *mystrcpy(char *dest, const char *src)
{
char *saveddest = dest;
while(*src)
{
*dest++ = *src++;
}
*dest = 0;
return saveddest;
}
or
char *two_in_one_strcpy_strlen(char *dest, const char *src, size_t *len)
{
char *saveddest = dest;
*len = 0;
while(*src)
{
*dest++ = *src++;
*len++;
}
*dest = 0;
return saveddest;
}
Related
#include<stdio.h>
void my_strconcat(char*, char*);
int main()
{
char s1[] = "HelloGoodMorningEveryone1";
char s6[] = "How";
printf("String Concatenate Start! \n");
my_strconcat(s1, s6);
printf("s1:%s s6:%s \n", s1, s6);
return 0;
}
void my_strconcat(char *src, char *dest)
{
while(*dest)
dest++;
while(*src) {
*dest++ = *src++;
}
*dest = '\0';
}
output:
String Concatenate Start!
s1:elloGoodMorningEveryone1 s6:HowHelloGoodMorningEveryone1
Your destination buffer does not have any space left for storing the concatenated result. So, inside the function, you're essentially overrunning the allocated memory, creating undefined behavior.
You need to allocate enough space to the destination buffer, like
char s6[128] = "How";
so that it's able to store the concatenated result, before you try to store the result.
I was trying to implement a string copy function using pointers as shown below:
#include <stdio.h>
#include <stdlib.h>
void copyStringPtr(char *from, char *to);
int main()
{
char strSource[] = "A string to be copied.";
char strDestination[50];
copyStringPtr(strSource, strDestination); // Doesn't work.
return 0;
}
void copyStringPtr(char *src, char *dst)
{
printf("The destination was\t:\t%s\n", dst);
// for(; *src != '\0'; src++, dst++)
// *dst = *src;
while(*src) // The null character is equivalent to 0, so when '\0' is reached, the condition equals to 0 or false and loop is exited.
*dst++ = *src++;
*dst = '\0';
printf("The source is\t\t:\t%s\n", src);
printf("The destination is\t:\t%s\n\n", dst);
}
The expected output is :
The destination was :
The source is : A string to be copied.
The destination is : A string to be copied.
But the output I'm getting is :
The destination was :
The source is :
The destination is :
As it can be seen, even the source doesn't seem to have the initialized value. What am I doing wrong here?
One issue is that you're not initializing char strDestination[50];. Thus it doesn't represent a valid string and when you try to print it here:
printf("The destination was\t:\t%s\n", dst);
It is undefined behavior. You can initialize it like this:
char strDestination[50] = {'\0'};
This explicitly sets the first char to '\0', making it a valid string. And the rest of the array is then default-initialized to '\0' anyway.
Also, after the while loop, your src and dst will point to the null terminator at the end of the strings, so when you print them, it prints nothing. Instead, keep a copy of the original pointers and print those instead:
void copyStringPtr(char *src, char *dst)
{
char* srcOriginal = src;
char* dstOriginal = dst;
...
printf("The source is\t\t:\t%s\n", srcOriginal);
printf("The destination is\t:\t%s\n\n", dstOriginal);
}
Just take a backup of the original pointers before doing the increment. The reason you lose those pointers is, as part of the iteration in the while the start address of the string is lost and the printf() function does not know where the string starts. Since both the original pointers point at \0 at the end of the loop, the printf() function does not see a an actual string to print up-to
You can even make these backup pointers const to disallow modifications made to them.
void copyStringPtr(char *src, char *dst)
{
printf("The destination was\t:\t%s\n", dst);
/*
* backing up the original source/desination
* pointers
*/
const char *b_src = src; const char *b_dst = dst;
while(*src) // The null character is equivalent to 0, so when '\0' is reached, the condition equals to 0 or false and loop is exited.
*dst++ = *src++;
*dst = '\0';
printf("The source is\t\t:\t%s\n", b_src);
printf("The destination is\t:\t%s\n\n", b_dst);
}
Also as noted in Blaze's answer calling printf() on a uninitialized character array invokes undefined behavior.
I just had to make a minor modification as follows:
#include <stdio.h>
#include <stdlib.h>
void copyStringPtr(char *from, char *to);
int main()
{
char strSource[] = "A string to be copied.";
char strDestination[50];
copyStringPtr(strSource, strDestination); // Doesn't work.
printf("The source is\t\t:\t%s\n", strSource);
printf("The destination is\t:\t%s\n\n", strDestination);
return 0;
}
void copyStringPtr(char *src, char *dst)
{
const char *srcOriginal = src;
const char *dstOriginal = dst;
printf("The destination was\t:\t%s\n", dstOriginal);
// for(; *src != '\0'; src++, dst++)
// *dst = *src;
while(*src) // The null character is equivalent to 0, so when '\0' is reached, the condition equals to 0 or false and loop is exited.
*dst++ = *src++;
*dst = '\0';
}
And it worked just fine. As pointed out by #Jabberwocky in his comment, the pointers *src and *dst in copyStringPtr had moved to the end of the character string and was pointing to the NULL terminator.
#include <stdio.h>
#include <stdlib.h>
void copyStringPtr(char *from, char *to);
int main()
{
char strSource[] = "A string to be copied.";
char strDestination[50] = {0};
copyStringPtr(strSource, strDestination);
return 0;
}
void copyStringPtr(char *src, char *dst)
{
char const *const dstOriginal = dst;
if (!src || !dst){
return;
}
printf("The source is\t\t:\t%s\n", src);
while(src && *src)
*dst++ = *src++;
*dst = '\0';
printf("The destination is\t:\t%s\n\n", dstOriginal );
}
i wrote this code without looking on the net and having a look in the builtin.
how can remove that temp variable and write directly in one of the variable passed in strcat12()?
#include <stdio.h>
char temp[]="";
int strlen12(char *str) {
int count = 0;
while(*str) {
count++;
str++;
}
return count;
}
char strcat12(char *str, char *str2) {
int i = 0;
int l = strlen12(str);
while(*str) {
temp[i++] = *str;
str++;
}
while(*str2) {
temp[l++] = *str2;
str2++;
}
}
The code has some errors and some place on which it can comply with standard.
strlen function returns the length of the string. Better would be if you return size_t and parameter is of type const char*.
Now strcat doesn't behave the way you implemented it. What happens then? Standard says
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. If copying takes place between objects that overlap, the behavior is undefined.
Returns
The strcat function returns the value of s1.
char * mystrcat(char *dest, const char *src)
{
size_t i=0,j=0;
while( dest[i] ) i++ ;
while( src[j] ) { dest[i+j] = src[j]; j++; }
dest[i+j] = '\0';
return dest;
}
The same way strlen() returns size_t.
size_t strlen(const char *s){
size_t len = 0;
for( ; s[len] ; len++ )
;
return len;
}
Now the problems in your code
char temp[]="" this is an one length string containing only the single character \0.
This is not a good idea to have a function that will fill one of the char array when called with 2 strings. This side effect is not desirable and it is not reusable.
char strcat12(char *str, char *str2) You are supposed to return a char but you returned nothing.
char strcat12(char *str, char *str2) Again why do you want to return a char?
Now if you are using a global variable why do you even need to return anything as far as the code is given. void strcat12(char *str, char *str2) will be ok.
A slightly better idea can be that you will return a char* which will contain the concatenated string. What I mean by this is you will allocate memory and return pointer to that memory and the memory holds concatenated string.
regarding your question: how can remove that temp variable and write directly in one of the variable passed in strcat12()?
to write directly into the parameter 'str', the array pointed to by 'str' must be long enough to hold the contents of both parameters + the terminating NUL byte.
Then the variable temp[] does not need to be referenced.
here is one way to implement the strcat12() function:
char * strcat12(char *dest, const char *src)
{
size_t i;
for (i = 0; dest[i]; i++);
for (size_t j = 0; src[j]; j++)
dest[i+j] = src[j];
dest[i+j] = '\0';
return dest;
}
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}else{
printf("Error");
}
return copy;
}
int main(int argc, char * argv[]){
char str[] = "Input string";
char * input;
input = removeChar(str,'g');
printf("%s\n", input);
free(input);
return 0;
}
I don't know why every time I try to run it ,it always says uninitialized variable and sticks in the strcpy line and printf line.
Basically this function is to take a string, and a character and removes the that character from the string (because I am learning malloc so that's why I wrote the function like this).
After the while loop do:
copy[j] = '\0';
to NULL-terminate your string; that way it can work with methods coming from <string.h>, which assume that the string is nul-terminated.
PS: One warning you should see is about not returning copy in your function in any case, because now if the condition of the if statement is wrong, your function won't return something valid, so add this:
return copy;
at the end of your function (which is now corrected with your edit).
Other than that, the only warning you should still get are for the unused arguments of main(), nothing else:
prog.c: In function 'main':
prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
While you copy over bytes from str to copy, you don't add a terminating null byte at the end. As a result, strcmp reads past the copied characters into unitialized memory, possibly past the end of the allocated memory block. This invokes undefined behavior.
After your while loop, add a terminating null byte to copy.
Also, you never return a value if the if block at the end is false. You need to return something for that, probably the copied string.
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
// add terminating null byte
copy[j] = '\0';
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}
// always return copy
return copy;
}
You never initialised input and the some compilers don't notice,
that the the value is never used before the line
input = removeChar(str, 'g');
in your code. So they emit the diagnostic just to be sure.
strcpy(str, copy)
gets stuck in your code, as copy never got a closing 0 byte and
so depends on the nondeterministic content of your memory at the
moment of the allocation of the memory backing copy, how long strcpy
will run and if you get eventually a SIGSEGV (or similar).
strcpy will loop until it finds a 0 byte in your memory.
For starters to remove a character from a string there is no need to create dynamically a character array and then copy this array into the original string.
Either you should write a function that indeed removes the specified character from a string or a function that creates a new string based on the source string excluding the specified character.
It is just a bad design that only confuses users. That is the function is too complicated and uses redundant functions like malloc, strlen, strcmp and strcpy. And in fact it has a side effect that is not obvious. Moreover there is used incorrect type int for the length of a string instead of the type size_t.
As for your function implementation then you forgot to append the terminating zero '\0' to the string built in the dynamically allocated array.
If you indeed want to remove a character from a string then the function can look as it is shown in the demonstrative program.
#include <stdio.h>
char * remove_char(char *s, char c)
{
char *p = s;
while (*p && *p != c) ++p;
for ( char *q = p; *p++; )
{
if (*p != c) *q++ = *p;
}
return s;
}
int main( void )
{
char str[] = "Input string";
puts(str);
puts(remove_char(str, 'g'));
return 0;
}
The program output is
Input string
Input strin
If you are learning the function malloc and want to use it you in any case should try to implement a correct design.
To use malloc you could write a function that creates a new string based on the source string excluding the specified character. For example
#include <stdio.h>
#include <stdlib.h>
char * remove_copy_char(const char *s, char c)
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p != c) ++n;
}
char *result = malloc(n + 1);
if (result)
{
char *q = result;
for (; *s; ++s)
{
if (*s != c) *q++ = *s;
}
*q = '\0';
}
return result;
}
int main( void )
{
char *str = "Input string";
puts(str);
char *p = remove_copy_char(str, 'g');
if ( p ) puts(p );
free(p);
return 0;
}
The program output will be the same as above.
Input string
Input strin
Pay attention to the function declaration
char * remove_copy_char(const char *s, char c);
^^^^^^
In this case the source string can be a string literal.
char *str = "Input string";
//a function that copies one string to another
copy(char *,char*);
main()
{
char one[20],two[20];
printf("enter two sentences \n\n");
gets(one);//first string
gets(two);//second string
copy(one,two);
printf("%s",two);
}
copy(char *s1,char *s2)
{
while(*s1!='\0')
{
s2=s1;
s1++;
s2++;
}
s2='\0';
}
what wrong with the above program ? why the string 'one' is not getting copied to string 'two'?please explain with the help of pointer
It's because this:
s2 = s1;
changes the pointer s2 so that it points to the content of s1.
What you want to do is copy the content:
*s2 = *s1;
A decent compiler should also have given you a warning on this line:
s2 = '\0';
since you're assigning a char to a char *. It should be:
*s2 = '\0';
Enacting those changes, the function would then be (including using some, IMNSHO, better variable names):
void copy (char *from, char *to) {
while (*from != '\0') {
*to = *from;
from++;
to++;
}
*to = '\0';
}
Or, once your brain has been warped by several decades of C use like mine :-)
void copy (char *from, char *to) {
while (*to++ = *from++);
}
#include <stdio.h>
#include <string.h> /* for strchr */
void copy(const char *, char*); /* use void to return nothing */
int main(void) /* main() is not valid */
{
char one[20], two[20];
char *ptr;
printf("enter two sentences \n\n");
/* gets is deprecated, use fgets in order to avoid overflows */
fgets(one, sizeof one, stdin);
/* fgets leaves a trailing newline, remove it */
if ((ptr = strchr(one, '\n'))) *ptr = '\0';
fgets(two, sizeof two, stdin); /* why? is gonna be replaced by one */
copy(one, two);
printf("%s\n", two);
return 0;
}
void copy(const char *s1, char *s2) /* s1 is not modified, use const */
{
while(*s1 != '\0')
{
*s2 = *s1; /* Don't assign addresses, assign values */
s1++;
s2++;
}
*s2 = '\0';
}