1
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define SUCCESS 0
#define FAILURE -1
int str_rev(char **s, char **d){
  int count = 0;
  if(s == NULL || d == NULL){
   printf("\n Invalid address received! \n");
   return FAILURE;
  }
  else{
   while(**s != '\0'){
    **s++;count++;
   }
   while(count > 0){
    **d++ = **s--;count--;
   }
   **d = '\0';
   return SUCCESS;
  }
}
int main(){
 int ret_val = SUCCESS;
 char *a = "angus";
 char *b;
 b = malloc((strlen(a) * sizeof(*a)) + 1);
 ret_val = str_rev(&a,&b);
 if(ret_val == FAILURE){
   printf("\n String is not reversed! going to quit! \n");
   free(b);
   return FAILURE;
 }
 printf("\n b:%s \n",b);
 free(b);
 return SUCCESS;
}

I am writing a simple program without the use of predefined function for string reversal. But this throws me a segmentation fault. I beleive i'm accessing the correct memory address.

EDITED:

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define SUCCESS 0
#define FAILURE -1
int str_rev(char *s, char **d){
  int count = 0;
  if(s == NULL || d == NULL){
   printf("\n Invalid address received! \n");
   return FAILURE;
  }
  else{
   while(*s != '\0'){
    s++;count++;
   }
   s--;
   while(count > 0){
    printf("\n *s:%c \n",*s);   // prints the values correctly in the reverse order
    *(*d)++ = *s--;count--;
    printf("\n **d:%c \n",*((*d)-1)); // doesnt print the values, after the assignement
   }
   **d = '\0';
   printf("\n s:%s *d:%s \n",s,*d); // both s and d doesnt print the values copied
   return SUCCESS;
  }
}
int main(){
 int ret_val = SUCCESS;
 char *a = "angus";
 char *b,*x;
 b = malloc((strlen(a) * sizeof(*a)) + 1);
 x = b;
 if(b == NULL){
 }
 ret_val = str_rev(a,&b);
 if(ret_val == FAILURE){
   printf("\n String is not reversed! going to quit! \n");
   free(b);
   return FAILURE;
 }
 printf("\n b:%s \n",b);
 free(b);
 return SUCCESS;
}

I changed the code as above, as 'a' contains the string. hence a single pointer is enough to point to that location as no changes needs to be done. But even after this above change The contents in 's' are not getting copied to 'd'. And i'm getting a seg fault after printing "printf("\n b:%s \n",b);" .

Angus
  • 12,133
  • 29
  • 96
  • 151
  • Where is `ret` defined? –  Mar 09 '13 at 03:32
  • Where is a ; after `printf("\n b:%s \n",b)`? –  Mar 09 '13 at 03:33
  • 2
    `b = malloc(sizeof(b))` will allocate the space for `char *`. I presume you would need to have `b = malloc(strlen(a)+1)`. – Ganesh Mar 09 '13 at 03:34
  • @Angus Learn how use warnings displayed by your compiler and how to debug. All of these problem could be resolved with their usage. –  Mar 09 '13 at 03:36
  • To elaborate on @Ganesh's comment, `malloc(sizeof(b))` will allocate `sizeof(b)` bytes (probably 4 or 8 bytes depending on the system) since `b` is a pointer. Obviously, this isn't large enough to store a string longer than a few characters so `malloc(strlen(a)+1)` is correct. – shanet Mar 09 '13 at 03:36
  • What is the return value if it succeeds? – QuentinUK Mar 09 '13 at 03:39
  • Why so much indirection int str_rev(char *s, char *d); will do. – QuentinUK Mar 09 '13 at 03:40
  • Use char a[] = "angus"; and char b[sizeof a]; – QuentinUK Mar 09 '13 at 03:42
  • @Armin: I was executing the code in VMware. I could not copy and paste the code. So I was writing the code once again to post, where i missed to verify the syntax and the variable used. – Angus Mar 09 '13 at 03:54
  • @Quentin : Yes, that will do. but i want to try it through pointers. – Angus Mar 09 '13 at 03:55
  • I was going through pointers pdf.And tried the string reversal by myself without using in-built funcs. – Angus Mar 09 '13 at 04:14
  • @Angus Why you call `ret_val = str_rev(&a,&b);` `&a` if first argument is just `char*` in your second code you should call like `ret_val = str_rev(a,&b);` And problem is still with `d` Why do you make it `**` just `*` is sufficient I have answered with a running code. – Grijesh Chauhan Mar 09 '13 at 08:26

6 Answers6

4

In addition to memory allocation problem also second problem in your code:

First
after your copy loop:

   while(count > 0){
    **d++ = **s--;count--;
   }

You do not terminate d string ny null

add

**d= '\0';

Second: after your first loop

   while(**s != '\0'){
    **s++;count++;
   }

You copy from Null do destination first char become '\0' then how you can print using %s

you should decrements s to point back to last char instead of null char. by --s.

Third

memory allocation do like:

 char *a = "angus";
 char *b;
 b = malloc(strlen(a)*sizeof(*a) + 1);

don't forget to free() memory for b

Four
Next is you forgot to return return SUCCESS; from str_rev()

Firth

you are passing pointer to pointer that change the b and 's' value it self in calling function. When you call with &s and modifies s then no string points to "angus" string.

Do like below I coded you logic using single pointer instead.

int str_rev(char *s, char *d){
  int count = 0;
  if(s == NULL || d == NULL){
   printf("\n Invalid address received! \n");
   return FAILURE;
  }
  else{
   while(*s != '\0'){
    s++;
    count++;
   }
   count;
   --s;
   while(count > 0){
    *d = *s;
   // printf("\n %c %c", *d, *s);
    d++ ;
    s--;
    count--;
   } 
   *d = '\0';
  }
  return SUCCESS;
}

in main just call as:

ret_val = str_rev(a, b);

EDIT: Second Code

I notice you are not happy with my suggestion to use single pointer for both!

Well in your second (EDIT) there are some repeating errors:

(1): From function str_rev() your again forgot to return SUCCESS.
(2): Your syntax for str_rcv function is int str_rev(char *s, char **d), first argument is char* but in main() you call it like ret_val = str_rev(&a,&b); that is wrong incompatibly pointer assignment. you should call like:

ret_val = str_rev(a, &b); 

(3): IMPORTANT FOR YOU: In second argument you are passing &b Where as in str_rev() function you are updating d pointer hence updating b to which you allocated memory through malloc(), You can't do that!
This will cause an error also: memory clobbered before allocated block

You should rectify your code to call like this: (read comments please)

 b = malloc((strlen(a) * sizeof(*a)) + 1);
 if(b == NULL){
   return FAILURE; // added this line too 
 }
 char* x = b;  // first assign b to x, notice x and b are of 
               // same type char*
 ret_val = str_rev(a,&x);  // know pass &x instead of &b 

(4): although my previous code also working get new version too:

#define SUCCESS 0
#define FAILURE -1
int str_rev(char *s, char **d){
  int count = 0;
  if(s == NULL || d == NULL){
   printf("\n Invalid address received! \n");
   return FAILURE;
  }
  else{
   while(*s != '\0'){
    s++;count++;
   }
   s--;
   while(count > 0){   
    *(*d)++ = *s--;
    printf("\n *s:%c And **d: %c\n",*(s+1), *((*d)-1));  // for bug finding 
                             // because s decremented and d incremented  
     count--;

   }
   **d = '\0';

   return 0;
  }
}

the main function():

int main(){
 int ret_val = SUCCESS;
 char *a = "angus";
 char *b;
 b = malloc((strlen(a) * sizeof(*a)) + 1);
 if(b == NULL){
   return -1;
 }
 char* x = b;
 ret_val = str_rev(a,&x);
 if(ret_val == FAILURE){
   printf("\n String is not reversed! going to quit! \n");
   free(b);
   return FAILURE;
 }
 printf("\n b:%s \n",b);
 free(b);
 return SUCCESS;
}

Its working Output is:

 *s:s And **d: s

 *s:u And **d: u

 *s:g And **d: g

 *s:n And **d: n

 *s:a And **d: a

 b:sugna 

Here your running code at Codpad

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • I have corrected my code, with your comments, but still getting the segmentation fault. – Angus Mar 09 '13 at 04:11
  • @Angus I know problem is by passing pointer to pointer your are changing `b` to point null so I think blank print means nothing – Grijesh Chauhan Mar 09 '13 at 04:12
  • @Angus Sorry but there is number of bugs in your code I mention each almost also corrected your code Please find my updated code: and its running actually see: [Codepad](http://codepad.org/xNGaN5xF) – Grijesh Chauhan Mar 09 '13 at 04:57
  • Thanks. The above code will be good if the strings are in an array. I have the strings in a pointer variable and i want to reverse and store it in another pointer variable. – Angus Mar 09 '13 at 05:20
  • @Angus I also reverse and stored in another array while original string `s` intact. Which above code means? My and your ?...Let me know if you need more help... – Grijesh Chauhan Mar 09 '13 at 05:22
  • @Angus Please read my updated answer again get an code for second part – Grijesh Chauhan Mar 09 '13 at 08:55
  • @Gireesh : That was a perfect working code you have done. Thanks for explaining it very neatly. I have a doubt in the 3 and 4 th points. Why do we need to declare an extra pointer *x and make it to point the memory what b is pointing and put the strings through that pointer. why cant we do it with b.(But when we try to change the memory loc pointed by b, we are getting a seg fault) – Angus Mar 09 '13 at 10:53
  • and the 2nd doubt is, in printf(), when tried to print *(*d)-- or (*(*d)--) , it was not printing the values, when modified it to *((*d)-1) , its prinitng the values. Isnt *(*)d--,*((*d)--) is equal to *((*d)-1)? – Angus Mar 09 '13 at 11:06
  • 1
    @Angus for the point (3) You were trying to modify `b` to which you have allocated memory. that is not allowed. Please read this also [*Memory Clobbering Error*](http://stackoverflow.com/questions/6571455/memory-clobbering-error) this example and your code produce having same reason for memory-Clobbering -Error. – Grijesh Chauhan Mar 09 '13 at 13:13
  • 1
    @Angus (2) after copy `s` into `d` at expression `*(*d)++ = *s--;` you should not modify `d` and `s` Remember `-- and ++` operator will change `d` to point back to previous location that is the reason I used `*(s+1), *((*d)-1)`, And **NO** `i++` not equal to `i + 1` but `i++` is equal to `i = i + 1` similarly `*((*d)--)` is **NOT** equal to `*((*d)-1)`! – Grijesh Chauhan Mar 09 '13 at 13:18
3

Here:

**s++

you are incrementing the char ** s. This alters it to point to the next char * which is not meaningful in your program.

Because of operator precedence, **s++ is the same as (*(*(s++)). Which is to say, it returns the value of the char pointed to by the char * pointed to by s, and as a side-effect increments s to point to the 'next' char * (which isn't well-defined because you do not have an array of char *s).

A typical idiom in C string manipulation is *p++, which is the same as (*(p++)). This returns the value of the char pointed to by p and as a side effect sets p to point to the next char, which would be the next character in the string. To do the same with a char ** one must write *(*p)++, or more explicitly (*((*p)++)).

Also, it is not necessary to use char **s to reverse a string; it can be done with only char *s.

Samuel Edwin Ward
  • 6,526
  • 3
  • 34
  • 62
  • No buddy notice your answer but your answer most important I think! – Grijesh Chauhan Mar 09 '13 at 03:47
  • 1
    @GrijeshChauhan I disagree. Samuel's answer identifies undefined behaviour that occurs before the undefined behaviour you've identified. They're both undefined behaviour, so they're equally important. – autistic Mar 09 '13 at 04:11
  • Samuel: Perhaps it'd be a good idea to explicitly explain that the `s++` in `**s++` is evaluated before the `**`'s. – autistic Mar 09 '13 at 04:17
  • @modifiablelvalue, I don't like the phrase "evaluated before" in this context, but I'll expand on operator precedence; thanks. – Samuel Edwin Ward Mar 09 '13 at 04:38
  • @GrijeshChauhan, personally I think the most important part of my answer that almost all the others lack is the fact that Angus is making things difficult for himself by using pointers to pointers in a situation where mere pointers are sufficient and more elegant. – Samuel Edwin Ward Mar 09 '13 at 04:57
  • @SamuelEdwinWard Sorry I couldn't read comments. Yes although you might made an mistake but your point was really important. I believe you are correct. – Grijesh Chauhan Mar 09 '13 at 05:00
  • @SamuelEdwinWard : your comments made me to understand what mistake i'm doing with the operator precedence while handling a pointer to a pointer, but using *((*s)--). throws aborted message. – Angus Mar 09 '13 at 05:23
  • @modifiablelvalue Sorry I couldn't read your comment at that time. Please revisit Samuel Edwin Ward's answer he explained quit a good. – Grijesh Chauhan Mar 09 '13 at 05:26
  • @SamuelEdwinWard I corrected the code with single pointer but correcting solution for `**` here is [my incomplete](http://codepad.org/htURiPg7) if you can find time improve it. – Grijesh Chauhan Mar 09 '13 at 05:29
  • @SamuelEdwinWard I would be most upset if `*p++` were to *return*. – autistic Mar 09 '13 at 06:14
  • @modifiablelvalue, yes, I suppose you would be upset if it were to perform the operation performed by the keyword of that spelling. If I'm not mistaken you have the ability to suggest an edit, so I invite you to clean up my phrasing and reap the +2 reputation reward for doing so. – Samuel Edwin Ward Mar 09 '13 at 06:27
1

In this line

b = malloc(sizeof(b));

sizeof(b) is just the size of a pointer and that is not ehough to fit a whole string.

Either pass the size you want to malloc

b = malloc(42);
b = malloc(strlen(a) + 1);

or change b into an array instead of a pointer

char b[42];

Other than that, I would highly recommend learing to use tools like gdb or valgrind to debug these segmentation faults. At the least they will tell you what line is segfaulting and just that will help a lot.

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • `malloc(sizeof(42))` is invalid — you cannot take the size of something that isn't a variable. `malloc(42)` is what you mean. – Matt Patenaude Mar 09 '13 at 03:37
  • @MattPatenaude: Oops. Thats what I get for copy-pasting :) – hugomg Mar 09 '13 at 03:37
  • Still getting seg_fault after the change – Angus Mar 09 '13 at 04:11
  • @MattPatenaude, to be a bit pedantic, you can take the `sizeof` a type (_e.g._: `sizeof(unsigned long)`). Also, `sizeof(42)` works in gcc (it returns the size of an int as I would expect) although I'm not sure if that's an extension. – Samuel Edwin Ward Mar 09 '13 at 05:03
  • @MattPatenaude This comes from the C11 standard: The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant. – autistic Mar 09 '13 at 06:18
  • @MattPatenaude Is `42` an expression? If so, then you can indeed take the size of it. In fact, it's often a great idea to use an expression as a `sizeof` operand. Consider `foo *bar = malloc(foo *);`. If I were to change the type of `bar`, then I would need to change the malloc argument in order to ensure the code behaves correctly. Would I have to change the malloc argument in `foo *bar = malloc(sizeof *bar);`? – autistic Mar 09 '13 at 06:21
  • Well I guess you learn something new every day! Was unaware compilers would use the type of such an "ambiguous" expression, but I guess since pretty much everything falls back to a plain old `int` in C, it's not that ambiguous after all, is it? – Matt Patenaude Mar 09 '13 at 06:57
0

Change ret = str_rev(&a,&b); to ret_val = str_rev(&a,&b);

Breavyn
  • 2,232
  • 16
  • 29
0

Please find a reworked function as below

int str_rev(char **sinp, char **dout){
    int count = 0;
    char *s = *sinp; // Dereference the starting address of source
    char *d = *dout; // Dereference the starting address of destination

    if(s == NULL || d == NULL){
        printf("\n Invalid address received! \n");
        return FAILURE;
    }
    else{
        while(*s != '\0'){
            *s++;count++;
        }
        s--; // Requires a decrement as it is pointing to NULL

        while(count > 0){
             *d++ = *s--;
             count--;
        }
    }
    *d = '\0'; // Need a NULL terminator to convert it to string
    return SUCCESS; // Requires a return as all branches of function should return values
}
Ganesh
  • 5,880
  • 2
  • 36
  • 54
0
char str[] = "hello";
char *foo = foo;

*foo++ is the equivalent to *(foo++), not (*foo)++. foo++ causes foo to point to the next char.

char str[] = "hello";
char *foo = str;
char **bar = &foo;

**bar++ is the equivalent to **(bar++);, not (**bar)++. bar++ causes bar to point to the next char *... Do you see a problem?

(*bar)++ causes foo to point to the next char. consider what you'd be doing to your caller's a and b variables in ret_val = str_rev(&a,&b);, (*s)++; and (*d)++.

autistic
  • 1
  • 3
  • 35
  • 80