CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

strange thing with reversing a string
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
The Puma



Joined: 23 Apr 2004
Posts: 227
Location: The Netherlands

View user's profile Send private message

strange thing with reversing a string
PostPosted: Thu Oct 11, 2007 6:14 am     Reply with quote

I have this function to reverse a string
The string can hold max 10 chars

Let say: "1234567890"
After the reversing he outputs "=098765432"

Whats is wrong here??

Code:

void max7221_fill_char_buffer(char *buffer) {
   int i,j;
   char currentchar;
   char *msgptr,*rev_buffer;
   
   j=strlen(buffer);
   rev_buffer[j--]=0;
   for(i=0;i<strlen(buffer);i++,j--)
      rev_buffer[j]=buffer[i];
         
   memset(message,0x00,50);
   msgptr=&message[0];
   currentchar=*rev_buffer;
   while(currentchar) {
      memcpy(msgptr,font5x7[currentchar-0x20],5);
      msgptr+=5;
      currentchar=*(++rev_buffer);
   }
}


But if i only reverse a string that is lower than the 10 chars is going well
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Oct 11, 2007 6:32 am     Reply with quote

Where do you initialise rev_buffer? My guess is it is pointing to a random location in RAM and conflicting with other variables.
The Puma



Joined: 23 Apr 2004
Posts: 227
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Oct 11, 2007 7:36 am     Reply with quote

Can you give me a hint how i can change the code, so that it works?
rberek



Joined: 10 Jan 2005
Posts: 207
Location: Ottawa, Canada

View user's profile Send private message

PostPosted: Thu Oct 11, 2007 7:42 am     Reply with quote

ckielstra did give you a hint. Initialize rev_buffer.
The Puma



Joined: 23 Apr 2004
Posts: 227
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Oct 11, 2007 7:54 am     Reply with quote

But how??
Please help me
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Thu Oct 11, 2007 8:30 am     Reply with quote

OK, your first problem is that you think strlen returns the length of the string including the null termination char '\0' it does NOT so if you changed the code

Code:

j=strlen(buffer);
rev_buffer[j--]=0;

to
j=strlen(buffer);
rev_buffer[j+1] = 0;

That would fix the first problem.

Secondly and more imprtantly.
char *rev_buffer; needs to be changed to
char rev_buffer[MAX_SIZE];
where MAX_SIZE = strlen(buffer) + 1;

Hope that helps.

The Puma



Joined: 23 Apr 2004
Posts: 227
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 6:04 am     Reply with quote

I can't get it to work
Code:
void max7221_fill_dot_matrix_buffer(char *buffer) {
   int i,j;
   char reverse_buffer[10],*msgptr,currentchar;
   
   j=strlen(buffer);
   reverse_buffer[j--]=0;
   for(i=0;i<strlen(buffer);i++,j--)
      reverse_buffer[j]=buffer[i];
      
   memset(dot_matrix_buffer,0x00,50);
   msgptr=&dot_matrix_buffer[0];
   currentchar=*reverse_buffer;
   while(currentchar) {
      memcpy(msgptr,font5x7[currentchar-0x20],5);
      msgptr+=5;
      currentchar=*(++reverse_buffer);
   }
}


get the follwoing error:
Expecting LVALUE such as a variable name or * expression
(in line: currentchar=*(++reverse_buffer);)


How can i made this that the 4 four lines reverse the string (in buffer) to reverse_buffer?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 8:25 am     Reply with quote

[spam],
You did not react to Wayne's suggestions. This is impolite and it might have helped you.

Wayne_ wrote:
OK, your first problem is that you think strlen returns the length of the string including the null termination char '\0' it does NOT so if you changed the code

Code:

j=strlen(buffer);
rev_buffer[j--]=0;

to
j=strlen(buffer);
rev_buffer[j+1] = 0;


That would fix the first problem.
Sorry Wayne, the original code as posted is correct. You made a similar thinking error because an array starts counting at position 0, not at 1. For example, a string with length 10 would occupy 11 bytes in memory including the terminating zero. Strlen would return 10, writing a terminating 0 at rev_buffer[10] is then correct.

Wayne_ wrote:
Secondly and more imprtantly.
char *rev_buffer; needs to be changed to
char rev_buffer[MAX_SIZE];
where MAX_SIZE = strlen(buffer) + 1;
This is an important bug and [spam] did not fix it, the reverse_buffer size is still 10 instead of 11.
I want to extend on this a bit more. It is good coding practice to avoid the use of 'magic numbers', i.e. don't use hard coded numbers. In your small function here you have the hard coded numbers 10, 50 and 5. The big risk you are running here is that you change the size of one such number in one place in your program but forget to change it in another place. Replace the hard coded numbers by a meaningful #defined name.

Another potential problem: You are using the strlen function to get the length of the input buffer, but there is no test on the input buffer being too long. This could cause your program to overwrite other data in RAM.

The [spam] wrote:
get the follwoing error:
Expecting LVALUE such as a variable name or * expression
(in line: currentchar=*(++reverse_buffer);)
This one is strange, it looks like you have found a limitation (bug) in the CCS compiler. The compiler complains about the '++reverse_buffer' part. I tried it both in v3.249 and 4.057 and both compiler versions don't allow calculations on the buffer address. This is not good, but I have to say it is an ugly coding style to want to change a buffer's base address. A more elegant solution is to change currentchar into a pointer and then change this pointer instead.

A final remark: Even in a small program it is good practice to add a little comment about what is going on. And when you copy code from other people it is polite to give them credits (add a link to the original code in your program).

Code:
#define DOT_MATRIX_BUFFER_SIZE  50
#define FONT_SIZE               5
#define MAX_REV_BUF_SIZE        (DOT_MATRIX_BUFFER_SIZE / FONT_SIZE)  // 50 / 5 = max 10 characters

void max7221_fill_dot_matrix_buffer(char *buffer)
{
   int i,j;
   char reverse_buffer[MAX_REV_BUF_SIZE+1],*msgptr;
   char *currentchar;     // Changed into a pointer

   // Reverse the string sequence.
   // Code supplied by asmallri in http://www.ccsinfo.com/forum/viewtopic.php?t=23498
   j=strlen(buffer);
   if (j > MAX_REV_BUF_SIZE)    // Added a test for buffer overflow
     j = MAX_REV_BUF_SIZE;
   reverse_buffer[j--]=0;
   for(i=0;i<strlen(buffer);i++,j--)
      reverse_buffer[j]=buffer[i];
   
   // Clear the matrix buffer.
   memset(dot_matrix_buffer, 0x00, DOT_MATRIX_BUFFER_SIZE);

   //Copy the reversed string to the matrix buffer.
   msgptr = &dot_matrix_buffer[0];    // Here you have msgptr for same reason we
                                      // had to make currentchar into a pointer.
                                      // Looks like you had this problem before...?
   currentchar = &reverse_buffer[0];
   while(*currentchar)
   {
      memcpy(msgptr, font5x7[*currentchar-0x20], FONT_SIZE);
      msgptr+=5;
      currentchar++;
   }
}


Note: You can optimize this function by removing the reverse and walking the input buffer from back to front.
Ttelmah
Guest







PostPosted: Tue Oct 23, 2007 9:00 am     Reply with quote

Not allowing the base address to be changed, is correct 'C',not a limitation in CCS.
Key to remember, is that 'rev_buffer', is _not_ a variable holding a pointer, but is a shortcut (the name of an array is it's address). Since it is not a variable, it can't itself be incremented.

In K&R, the paragraph about this says:

"There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a, and pa++ are sensible operations. But an array name is a _constant_, not a variable: constructions like a=pa or a++ or pa=&a are illegal."

If you want to increment the address, then you need to declare:

char rev_buffer[MAX_SIZE];
char *buff_address;

Then add:

buff_address=rev_buffer;

and increment 'buff_address', not 'rev_buffer.

Best Wishes
The Puma



Joined: 23 Apr 2004
Posts: 227
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 9:01 am     Reply with quote

Ok, thz so far,

but how can i rewrite that code so that the fontdata (5 bytes) are not placed on position 0 of the string, but on position 49


An example:
0x36, 0x49, 0x49, 0x49, 0x7F // 0x42, B

The data for the letter B must be place on postion 49

Code:
   msgptr=&dot_matrix_buffer[0];
   currentchar=*buffer;
   while(currentchar) {
      memcpy(msgptr,font5x7[currentchar-0x20],MAX_FONT_SIZE);
      msgptr+=MAX_FONT_SIZE;
      currentchar=*(++buffer);
   }
}
The Puma



Joined: 23 Apr 2004
Posts: 227
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 9:56 am     Reply with quote

Ttelmah wrote:
Not allowing the base address to be changed, is correct 'C',not a limitation in CCS.
Key to remember, is that 'rev_buffer', is _not_ a variable holding a pointer, but is a shortcut (the name of an array is it's address). Since it is not a variable, it can't itself be incremented.

In K&R, the paragraph about this says:

"There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a, and pa++ are sensible operations. But an array name is a _constant_, not a variable: constructions like a=pa or a++ or pa=&a are illegal."

If you want to increment the address, then you need to declare:

char rev_buffer[MAX_SIZE];
char *buff_address;

Then add:

buff_address=rev_buffer;

and increment 'buff_address', not 'rev_buffer.

Best Wishes

I did't understand it anymore

Can you me a working reserve code for above procedure
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 10:12 am     Reply with quote

I don't understand anymore either. I gave you a compilable version of your function. I don't know the input or output requirements of your function, but have you tested my code and what did you see going wrong?
The Puma



Joined: 23 Apr 2004
Posts: 227
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 10:17 am     Reply with quote

ckielstra wrote:
I don't understand anymore either. I gave you a compilable version of your function. I don't know the input or output requirements of your function, but have you tested my code and what did you see going wrong?

It is very simple:
I pass a string. lets say DEMO
now the passing string (in char buffer) must reversed

Code:
void max7221_fill_char_buffer(char *buffer) {
   char currentchar;
   char *msgptr;
   

  HERE MUST THE REVERSE CODE


   memset(message,0x00,MAX_DOT_MATRIX_BUFFER_SIZE);
   msgptr=&message[0];
   currentchar=*buffer;
   while(currentchar) {
      memcpy(msgptr,font5x7[currentchar-0x20],MAX_FONT_SIZE);
      msgptr+=MAX_FONT_SIZE;
      currentchar=*(++buffer);
   }
}
The Puma



Joined: 23 Apr 2004
Posts: 227
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 11:40 am     Reply with quote

I have now this and it works
Can i optimise this ?

Maybe some advise

Code:
void max7221_fill_dot_matrix_buffer(char *buffer) {
   int i,j;
   char temp,*msgptr,currentchar;
   
   for(i=0,j=strlen(buffer)-1;i<j;i++,j--) {
      temp=buffer[i];
      buffer[i]=buffer[j];
      buffer[j]=temp;
   }
   memset(dot_matrix_buffer,0x00,MAX_DOT_MATRIX_BUFFER_SIZE);
   msgptr=&dot_matrix_buffer[0];
   currentchar=*buffer;
   while(currentchar) {
      memcpy(msgptr,font5x7[currentchar-0x20],MAX_FONT_SIZE);
      msgptr+=MAX_FONT_SIZE;
      currentchar=*(++buffer);
   }
}
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Oct 23, 2007 12:29 pm     Reply with quote

The [spam] wrote:
I have now this and it works
Can i optimise this ?
Get rid of the lines reversing the buffer, you can do this in the copy-loop by reading the input buffer backwards (from the end to start).

Code:
void max7221_fill_dot_matrix_buffer(char *buffer) {
   int8 i;
   char *msgptr, currentchar;
   int8 MsgLength;
   
   memset(dot_matrix_buffer,0x00,MAX_DOT_MATRIX_BUFFER_SIZE);

   MsgLength = strlen(buffer);
   msgptr=&dot_matrix_buffer[0];
   for (i=0; i<MsgLength; i++)
   {
      currentchar=buffer[MsgLength - i - 1];
      memcpy(msgptr,font5x7[currentchar-0x20],MAX_FONT_SIZE);
      msgptr+=MAX_FONT_SIZE;
   }
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group