C language FOR Loop ending condition

Discussion in 'Programmer's Corner' started by eblc1388, Dec 31, 2009.

  1. eblc1388

    Thread Starter Senior Member

    Nov 28, 2008
    1,542
    102
    Hi all, need some help in understanding the following.

    In the following C code, pString is a normal character string ended with null and is passed as pointer into the SendString function, which extracts one byte and calls the SerialOut_To_PC function.

    How does the FOR loop inside the SendString function knows when to stop? Or how to interpret *a as an ending condition?

    Code ( (Unknown Language)):
    1.  
    2. //*******************************
    3. // RS232 Send string (unsigned)
    4. //*******************************
    5. void SendString(unsigned char* pString)
    6. {
    7.  unsigned char *a;
    8.  
    9.  for(a=pString;*a;a++)
    10.     SerialOut_To_PC(*a);
    11. }
    12.  
    13. // This is how the SendString is called to send the string in quotes
    14.  
    15. SendString("ABCDE_MNOPQ\0");
    16.  
    17.  
    18.  
     
    Last edited: Dec 31, 2009
  2. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    A for loop continues while the second expression evaluates to true. The loop will end when *a = 0; i.e., you reach a null character.
     
  3. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    I believe the explicit null character \0 at the end of your string is redundant. The C compiler appends a null character when the string is stored in memory.

    It is the null character that terminates the processing of the string. However, I think that a better means of coding the FOR loop would be to use the LEN() function to define the length of your string.

    Example: for(a=pString;strlen(pString);a++)

    You will need to include the header file "string.h" to make the function call to strlen() available.


    hgmjr
     
    Last edited: Dec 31, 2009
  4. eblc1388

    Thread Starter Senior Member

    Nov 28, 2008
    1,542
    102
    That's it. Thanks.

    Yes, the compiler should automatically append a \0 to a string constant.

    I'm just reading through codes by others. Perhaps the author places one more NULL in order to be sure, just in case.

    Thanks again, gentlemen.
     
  5. Papabravo

    Expert

    Feb 24, 2006
    10,135
    1,786
    As written this loop would be infinite since tha value of pString is not changed therefore strlen(pString) would always evaluate to a non zero constant for any non-null string pointed at by pString. You could fix the problem by saying
    Code ( (Unknown Language)):
    1.  
    2. for(a=pString; strlen(a); a++)
    3.  
    This requires a function call and some considerable processing at each iteration of the loop. In the evaluation of expressions there is an implicit test for zero (FALSE) or non-zero (TRUE), but you can always improve the clarity of your code by making the comparison explicit as in
    Code ( (Unknown Language)):
    1.  
    2. for(a=pString; *a != '\0'; a++)
    3.  
    This method has the advantage of being both clear and effcient.

    Many people actually use the macro preprocessor to #define the following:
    Code ( (Unknown Language)):
    1.  
    2. #define FALSE  0
    3. #define TRUE   !0
    4.  
     
  6. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Good catch Papabravo.

    hgmjr
     
  7. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    That's clumsy for a heap of reasons. pString is already a temporary variable that has cost RAM so there no need to copy it to another temp var. You could do this;

    Code ( (Unknown Language)):
    1.  
    2. //*******************************
    3. // RS232 Send string (unsigned)
    4. //*******************************
    5. void SendString(unsigned char* pString)
    6. {
    7.   while(*pString)
    8.   {
    9.     SerialOut_To_PC(*pString);
    10.     pString++;
    11.   }
    12. }
    13.  
    That saves 2 RAM (by removing the need for a 16bit pointer) but the compiler will still be doing the indirect addressing twice so it will still be slow like the example above it.

    Code ( (Unknown Language)):
    1.  
    2. //*******************************
    3. // RS232 Send string (unsigned)
    4. //*******************************
    5. void SendString(unsigned char* pString)
    6. {
    7.   unsigned char temp;
    8.   while(1)
    9.   {
    10.     temp = *pString;
    11.     if(temp) SerialOut_To_PC(temp);
    12.     else break;    
    13.     pString++;
    14.   }
    15. }
    16.  
    This costs 1 RAM but only needs to do the indirect addressing once and then tests and passes only a char var so it will be much faster executing and smaller code than either example especially on a microcontroller (which is probable considering the "Serial_out_to_PC").
     
  8. AlexR

    Well-Known Member

    Jan 16, 2008
    735
    54
    Given that any half-decent compiler will perform extensive optimisation you may as well write your source as clearly and concisely as possible and leave it up to the compiler of turn it into efficient code.
    You will probably find that even though your source uses pointers the compiler will translate these to direct addressing in the final assembly version of the code so personally I would go with you #2 option.
    I.E.
    Code ( (Unknown Language)):
    1. void SendString(unsigned char* pString)
    2. {
    3.   while(*pString)
    4.   {
    5.     SerialOut_To_PC(*pString);
    6.     pString++;
    7.   }
    8. }
     
Loading...