C reverse string help

Hai,

I'm having problems with an assignment in C. Im supposed to write a program that takes a string and reverse it, and im not allowed to use standard functions for reversing the string.
Anyways, here's what i've come up with.
PHP:
int strnlen(char *str){
    
    char *p = str;
    
    while(*p != '\0')
               p++;
               
               return p-str;
    }
    

char *swapstring(char *strptr){
     
     int len = strnlen(strptr);
     
     char array[len];
     
     char *str_start = strptr;
     
     char *str_end = &strptr[len-1];
      
     char *t = array; 
     char *m = array;
     char temp;
     
     while(*t++ = *str_start++ != '\0');
     
     for(int i=0; i<len/2; i++){
             m[i] = *(str_end--);
             }
     
          
               
                  
}

My problem is the actual swapping of letters inside the for loop

any ideas?
 
You can swap letters just like anything else: using a temporary variable. So...
Code:
char* p1 = ...;  // These two pointers are assumed to point to something valid and meaningful.
char* p2 = ...;

char temp = *p1;
*p1 = *p2;
*p2 = temp;

I'm not sure if your code isn't overly complicated. Try drawing a string of even length -- like this: [font=monospace]|C|o|d|i|n|g|[/font]. How would you reverse it? Try to think of it just like that, a bunch letters on a paper.

You don't need to draw a flowchart or make some pseudocode or whatnot (you may, if you want to) -- but imagine and realise what you're doing. You can use your fingers to better visualise pointers in the code. (I'm guilty of doing that myself.) Once you have it for even-length strings think what will change with odd-length strings (if anything) and then code it.

Well, at least this is the approach that usually works for me. :)
 
Oxyd said:
You can swap letters just like anything else: using a temporary variable. So...
Code:
char* p1 = ...;  // These two pointers are assumed to point to something valid and meaningful.
char* p2 = ...;

char temp = *p1;
*p1 = *p2;
*p2 = temp;

I'm not sure if your code isn't overly complicated. Try drawing a string of even length -- like this: [font=monospace]|C|o|d|i|n|g|[/font]. How would you reverse it? Try to think of it just like that, a bunch letters on a paper.

You don't need to draw a flowchart or make some pseudocode or whatnot (you may, if you want to) -- but imagine and realise what you're doing. You can use your fingers to better visualise pointers in the code. (I'm guilty of doing that myself.) Once you have it for even-length strings think what will change with odd-length strings (if anything) and then code it.

Well, at least this is the approach that usually works for me. :)

Hi,

I think i made things more complicated than they had to be.

This is alot simpler
PHP:
for(int i=0; i<len/2; i++){
            *str_start++ = *str_end--;

However, if i try to print the string by using puts(*str_start)
the compiler gives the error message 'invalid conversion from char to *const char'

why is that?
 
Business_Woman said:
However, if i try to print the string by using puts(*str_start)
the compiler gives the error message 'invalid conversion from char to *const char'

why is that?

I'm fairly sure it is "const char*", not "*const char".

Also, it appears that the type of str_start is char*, is that correct? Then the type of "*str_start" will be char -- you just dereferenced a pointer to a char, and that gives you a char. But puts expects its only argument to be a pointer to a char -- one that points to the beginning of a string.

So: Get rid of the * there.
 
Business_Woman said:
However, if i try to print the string by using puts(*str_start)
the compiler gives the error message 'invalid conversion from char to *const char'

why is that?

Because you are passing a char where you should have passed a pointer to const char. This would be correct: "puts((const char *)str_start);".
 
If you write puts(*str_start) you should "give character, which pointed by str_start", not "give pointer to string". So i think you must call puts(str_start)
 
For a sanity check instead of fixing your code i think if you take a peek at how I did it might help; I think your confused on what pointers really are. Its a common misconception that pointers are simply arrays and yes they can be used in similar ways but the meaning is much deeper but anyways take a look at this:

//only function i use was printf just to print the result :)

Code:
#include <stdio.h>

int main( int argc, char *argv[] )
{
	const char *string_to_revers= "hello World!";

	unsigned int len= 0, i=0;
	while( string_to_revers[i] != '\0' )
		{
			++i; ++len;
		}

	char buffer[ len ]; i= len;
	unsigned int idx= 0;
	while( string_to_revers[i-1] >= 0 )
		{
			buffer[ idx ]= string_to_revers[ i-1 ];
			idx++; i--;
		}
	buffer[ idx ]= '\0';

	printf("buffer = <%s>!\n", buffer);

	return 0;
}
 
Alt said:
I believed you cant do this in C
Code:
char buffer[ len ];

Sure you can :) Give it a go. some examples:

int bla[ size ];

or you can do

int *bla= calloc( size, sizeof(int) );

or if you want a string

char *str= malloc( sizeof(char)*length ); or you could use calloc again but then if your only going to have small amounts of data.

You might as well use he stack so you don't have to worry about freeing the data.
 
Whoo didnt know that... Its uses stack and i can dynamically allocate arrays and not free() it? Have this method some limits (size, another func calling, threading) ?
 
Alt said:
Whoo didnt know that... Its uses stack and i can dynamically allocate arrays and not free() it? Have this method some limits (size, another func calling) ?

You have to be very careful about using the stack its only designed for small amounts of data.

So I'll go over dynamic allocation first:

Absolutely anything you use any of the: malloc/calloc/realloc you need/should free since you have allocated it memory.

Even if this means you have a:

Code:
struct linkedlist {
  void* data;
  struct linkedlist *next;
}

Where you would allocated memory to your data then you would allocated memory to a struct to get a node then allocate memory to the next link. You need to be careful in free this.

Ergo you should go backwards since if you simply get the head list and free it you don't have access to the member data or next and if you need to free all of it you'll have to iterate to the end etc.

This is why its generaly frowned upon as a practice to use lumps of data all over the show a better implementation of lists or stacks is to use:

Code:
struct list_node {
  void **array;
  unsigned int length, size;
}

Where you would:

Code:
struct list_node *head= (struct list_node*)
  malloc( sizeof(struct list_node) );

//init it to 10 elements for now...
head->array= (void**) calloc( 10, sizeof(void*) );
head->length= 0; head->size= 10;

// to add in data
char *mydata= "some string...";

if( head->length < head->size ) {
  head->array[ head->length ]= mydata;
  head->length++
}
else {
  struct list_node *t = crl_realloc( head->array,
    (head->size*2) * sizeof(void*) );
  head->array= t;
  head->size= (head->size*2);
  head->array[ head->length ]= mydata;
  head->length++;
}

Then to free this you simply iterate through the array and then free each element then free the array and free the struct. That way you only have one struct to manage! This is something most tutorials really dont show people and its the most important ideas to get across.

just for reference i'll show you how to free that:

Code:
struct list_node *list....;

unsigned int idx= 0;
for( ; idx<(list->length); ++idx )
  {
    void* t= list->array[ idx ];
    if( t )
      {
        free( t );
        // this next step is important practice to have!
        list->array[ idx ]= NULL;
      }
  }
free( list->array );
free( list );

// this is something you should do if your freeing code in a project:

#define <prefix>_free( ptr )	 \
	assert( ptr );           \
	free( ptr );             \
	ptr= NULL;

This is good reference for new programmers to C
http://www.yolinux.com/TUTORIALS/C++MemoryCorruptionAndMemoryLeaks.html

Then if your using stack memory this is quite confusing and really you have to treat the symbol scope as the call stack goes. As in if your using a recent GCC this should give you a warning:

Code:
int* some_functor( void )
{
  int x = 2+3-7; //doesnt matter i just need a local
  return &(x);
}

Should give you its return the address of a local variable. This is because this can/will go out of scope once you pop out of this function and you will get memory corruption.

This is where the notion of pointers really comes to light, if you get the memory corruption like this where you cannot address this and you still try and access it you will get buffer overflow into other areas of allocated memory. Since these things are null terminated like strings '\0';

I hope this gives some ideas on how to think about it. If anything it just takes a hell of alot of playing around with and you'll get it :).

I <3 C its really one of the most perfect languages there is since your completely free to do anything you could imagine with it!

Have fun hacking.
 
  • Thanks
Reactions: Alt
I just though for the sake of completnss i would upload a better string reversal mine was unsafe and wrong lol.


Code:
#include <stdio.h>

int main( int argc, char *argv[] )
{
  const char * string_to_reverse= "HelloWorld!";

  int length= 0, idx= 0;
  while( string_to_reverse[idx] != '\0' )
    {
      idx++; length++;
    }

  char buf[ length ]; idx= length-1;
  int i= 0;
  while( idx >= 0 )
    {
      buf[ i ]= string_to_reverse[ idx ];
      idx--; i++;
    }
  buf[ i ]= '\0';

  printf("origional string <%s> after reverse <%s>!\n",
         string_to_reverse, buf );

  return 0;
}
 
Code:
#include <stdio.h>
#include <string.h>

void r_string(char *, char *);

int main (){

char str1[200];
char str2[200];

printf("Please input a string: ");

fgets(str1, sizeof(str1), stdin);

char *p_str1 = strchr(str1, '\n');

*p_str1 = '\0';

p_str1 = (char *) &str1;

char *p_str2 = (char *) &str2;

printf("This your input: %s\n", str1);

r_string(p_str1, p_str2);

printf("This is your reversed input: %s\n", str2);

return 0;

}

void r_string(char *p, char *y){

int i = 0;

    while ( *p !='\0' ){

       p++;
       i++;

    }

    for(; i >= 0; i--){

    p--;
    *y = *p;
    y++;

    }

}

my 2 cents
 
Back
Top