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 );
}
Related
According to this:
strcpy vs strdup,
strcpy could be implemented with a loop, they used this while(*ptr2++ = *ptr1++). I have tried to do similar:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
for(char *src="abcdef\0";(*des++ = *src++););
printf("%s\n",des);
}
But that prints nothing, and no error. What went wrong?
Thanks a lot for answers, I have played a bit, and decided how best to design the loop to see how the copying is proceeding byte by byte. This seems the best:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(7);
for(char *src="abcdef", *p=des; (*p++=*src++); printf("%s\n",des));
}
In this loop
for(char *src="abcdef\0";(*des++ = *src++););
the destination pointer des is being changed. So after the loop it does not point to the beginning of the copied string.
Pay attention to that the explicit terminating zero character '\0' is redundant in the string literal.
The loop can look the following way
for ( char *src = "abcdef", *p = des; (*p++ = *src++););
And then after the loop
puts( des );
and
free( des );
You could write a separate function similar to strcpy the following way
char * my_strcpy( char *des, const char *src )
{
for ( char *p = des; ( *p++ = *src++ ); );
return des;
}
And call it like
puts( my_strcpy( des, "abcdef" ) )'
free( des );
You are incrementing des so naturally at the end of the cycle it will be pointing past the end of the string, printing it amounts to undefined behavior, you have to bring it back to the beginning of des.
#include <stdio.h>
#include <stdlib.h>
int main(){
int count = 0;
char *des = malloc(10);
if(des == NULL){
return EXIT_FAILURE; //or otherwise handle the error
}
// '\0' is already added by the compiler so you don't need to do it yourself
for(char *src="abcdef";(*des++ = *src++);){
count++; //count the number of increments
}
des -= count + 1; //bring it back to the beginning
printf("%s\n",des);
free(dest); //to free the allocated memory when you're done with it
return EXIT_SUCCESS;
}
Or make a pointer to the beginning of des and print that instead.
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
if(des == NULL){
return EXIT_FAILURE; //or otherwise handle the error
}
char *ptr = des;
for(char *src="abcdef";(*des++ = *src++);){} //using {} instead of ;, it's clearer
printf("%s\n",ptr);
free(ptr) // or free(dest); to free the allocated memory when you're done with it
return EXIT_SUCCESS;
}
printf("%s\n",des); is undefined behavior (UB) as it attempts to print starting beyond the end of the string written to allocated memory.
Copy the string
Save the original pointer, check it and free when done.
const char *src = "abcdef\0"; // string literal here has 2 ending `\0`,
char *dest = malloc(strlen(src) + 1); // 7
char *d = dest;
while (*d++ = *src++);
printf("%s\n", dest);
free(dest);
Copy the string literal
const char src[] = "abcdef\0"; // string literal here has 2 ending `\0`,
char *dest = malloc(sizeof src); // 8
for (size_t i = 0; i<sizeof src; i++) {
dest[i] = src[i];
}
printf("%s\n", dest);
free(dest);
You just need to remember the original allocated pointer.
Do not program in main. Use functions.
#include <stdio.h>
#include <stdlib.h>
size_t strSpaceNeedeed(const char *str)
{
const char *wrk = str;
while(*wrk++);
return wrk - str;
}
char *mystrdup(const char *str)
{
char *wrk;
char *dest = malloc(strSpaceNeedeed(str));
if(dest)
{
for(wrk = dest; *wrk++ = *str++;);
}
return dest;
}
int main(){
printf("%s\n", mystrdup("asdfgfd"));
}
or even better
size_t strSpaceNeedeed(const char *str)
{
const char *wrk = str;
while(*wrk++);
return wrk - str;
}
char *mystrcpy(char *dest, const char *src)
{
char *wrk = dest;
while((*wrk++ = *src++)) ;
return dest;
}
char *mystrdup(const char *str)
{
char *wrk;
char *dest = malloc(strSpaceNeedeed(str));
if(dest)
{
mystrcpy(dest, str);
}
return dest;
}
int main(){
printf("%s\n", mystrdup("asdfgfd"));
}
You allocate the destination buffer des and correctly copy the source string into place. But since you are incrementing des for each character you copy, you have moved des from the start of the string to the end. When you go to print the result, you are printing the last byte which is the nil termination, which is empty.
Instead, you need to keep a pointer to the start of the string, as well as having a pointer to each character you copy.
The smallest change from your original source is:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
char *p = des;
for(char *src="abcdef";(*p++ = *src++););
printf("%s\n",des);
}
So p is the pointer to the next destination character, and moves along the string. But the final string that you print is des, from the start of the allocation.
Of course, you should also allocate strlen(src)+1 worth of bytes for des. And it is not necessary to null-terminate a string literal, since that will be done for you by the compiler.
But that prints nothing, and no error. What went wrong?
des does not point to the start of the string anymore after doing (*des++ = *src++). In fact, des is pointing to one element past the NUL character, which terminates the string, thereafter.
Thus, if you want to print the string by using printf("%s\n",des) it invokes undefined behavior.
You need to store the address value of the "start" pointer (pointing at the first char object of the allocated memory chunk) into a temporary "holder" pointer. There are various ways possible.
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*des++ = *src++) ; );
des = temp;
printf("%s\n",des);
free(des);
}
Alternatives:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*des++ = *src++) ; );
printf("%s\n", tmp);
free(tmp);
}
or
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*tmp++ = *src++) ; );
printf("%s\n", des);
free(des);
}
Side notes:
"abcdef\0" - The explicit \0 is not needed. It is appended automatically during translation. Use "abcdef".
Always check the return of memory-management function if the allocation succeeded by checking the returned for a null pointer.
Qualify pointers to string literal by const to avoid unintentional write attempts.
Use sizeof(char) * 10 instead of plain 10 in the call the malloc. This ensures the write size if the type changes.
int main (void) instead of int main (void). The first one is standard-compliant, the second not.
Always free() dynamically allocated memory, since you no longer need the allocated memory. In the example above it would be redundant, but if your program becomes larger and the example is part-focused you should free() the unneeded memory immediately.
I am trying to append a string t in a string s using pointers.
#include<stdio.h>
#include "my_functions.h"
int main(void)
{
char* s = "H"; /*First string*/
char* t = "W"; /*String to be appended*/
char* buff; /*used to store the initial value of s pointer*/
buff = s;
while(*s != '\0')
{
s++;
}
/*At the end of the loop I will get a memory add where string s
ends*/
/*Start appending second string at that place*/
char* temp; /*Creating a temporary pointer to store content
value of second string*/
temp = t;
t = s; /*t now points to the new starting position for
appending operation*/
*t = *temp; /*------ERROR-------*/
/*Rest is to just print the whole appended string at
once*/
s = buff;
while(*s!='\0')
{
printf("%c\t",*s);
s++;
}
printf("Works Fine");
return 0;
}
I am not getting any output on the terminal, nor any errors. The Idea is to change the content of new location of t which is '\0' to the content of t to be appended that is 'W'. I am a noob. Any suggestions? Where Am I wrong?
I suggest you to study this code:
char *strcat(char *dest, const char *src)
{
char *ret = dest;
while (*dest)
dest++;
while (*dest++ = *src++)
;
return ret;
}
Obviously the input parameter dest MUST be a pointer that points a memory area at least big as the sum of the two strings length (pointed by dest and src) + 1 byte (the 0 terminator).
//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';
}
I have written this function to transfer count number of characters from source string to destination string from right. I am passing string to src, NULL to dst and the count value to function
If i send input string as "Stack overflow" and count as 4 i want the o/p string as "flow". But here my o/p string is always empty, can u pls tell what is wrong in my logic. pls
char *Rprint(const char *src, char *dst, int count)
{
int i = 0;
char *ret = NULL;
while(*src!= '\0')
src++;
dst = malloc(sizeof(char) * (count + 1));
ret = dst;
dst = dst + (count + 1);
while(count)
{
*dst++ = *src--;
count--;
}
*dst++ = '\0';
//return ret;
printf("String:%s \n", ret);
}
I expect you meant to do this:
*dst-- = *src--;
I don't like the way you are doing this, but that should get you on track without me suggesting that you completely rewrite your code.
You should not null-terminate the string afterwards, because you have already copied the terminator. You are copying your string from the end to the beginning (ie reverse-copy), but confusing it with the more usual forward-copy.
Be careful with your loop condition. You might have an off-by-one error there. Same with adding count+1 to dst. I think you should only add count.
Oh, and don't forget to return a value from your function!
Here is the working code , based on your original approach , but with few corrections.
#include <stdio.h>
void Rprint(const char [], char [], int );
int main()
{
char buff[50] = "stack overflow";
char cut [50];
Rprint(buff,cut,5);
puts(cut);
}
void Rprint(const char src[], char dst[], int count)
{
while(*src!= '\0')
src++;
src = src - count;
while(count--)
*(dst++) = *(src++);
*(dst++) = '\0';
}
I am writing a C program in Unix and cannot figure out how to set an array element to NULL. I need to be able to do this to remove multiple characters from a string.
You can't assign null to specific char array index as value represented by that index is char instead of pointer. But if you need to remove specific character from given string, you can implement this as follows
void removeChar(char *str, char garbage) {
char *src, *dst;
for (src = dst = str; *src != '\0'; src++) {
*dst = *src;
if (*dst != garbage) dst++;
}
*dst = '\0';
}
Test Program
#include<stdio.h>
int main(void) {
char* str = malloc(strlen("abcdef")+1);
strcpy(str, "abcdbbbef");
removeChar(str, 'b');
printf("%s", str);
free(str);
return 0;
}
output
acdef
If you have a char[], you can zero-out individual elements using this:
char arr[10] = "foo";
arr[1] = '\0';
Note that this isn't the same as assigning NULL, since arr[1] is a char and not a pointer, you can't assign NULL to it.
That said, that probably won't do what you think it will. The above example will produce the string f, not fo as you seem to expect.
If you want to remove characters from a string, you have to shift the contents of the string to the left (including the null terminator) using memmove and some pointer arithmetic:
Example:
#include <stdio.h>
#include <string.h>
int removechars(char *str, size_t pos, size_t cnt) {
size_t len = strlen(str);
if (pos + cnt > len)
return -1;
memmove(str + pos, str + pos + cnt, len - pos - cnt + 1);
return 0;
}
Then use it like so:
char str[12] = "hello world";
if (removechars(str, 5, 4) == 0) /* remove 4 chars starting at str[5] */
printf("%s\n", str); /* hellold */
If you're talking about an array of pointers (say char **), you'd just say array[element] = NULL;. But it sounds as though you really want to just truncate a string (char *), in which case you'd actually want to write string[index] = '\0', where \0 is the null byte. But, as far as I know, 0, '\0', and NULL are all equivalent and equal to 0 (please correct me if I'm wrong). Of course, for clarity, you should use 0 for numbers, '\0' for chars and strings, and NULL for pointers.