Thread: How to fix a string overflow?

  1. #1
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193

    How to fix a string overflow?

    Good afternoon. I started a new program called expand which expands a-e to
    abcde (KnR exercise) however I've been doing this since I began to code:

    Code:
    #ifndef MAXSIZE  
      #endif MAXSIZE 1000 
    #endif
    or similar to control the size of the string. But I know a person can overflow it with 1001 chars. So, what's the definitive way to fix this problem?

    the program I'm starting to code :

    edit:

    Why can't I oblige the input of two letters and an hyphen with that do-while ?

    Code:
     
    
    #include <stdio.h> 
    #include <string.h> 
    #include <ctype.h> 
    #include <stdlib.h> 
    
    #ifndef ALPHA
       #define ALPHA 26
    #endif   
    
    #ifndef MAXSIZE 
       #define MAXSIZE 1000
    #endif   
    
    void justLetters(char*);
    void expand(char*, char*);
    
    void justLetters(char* s)
    { 
      int i, j;
      
      for(i = 0, j = 0; i < strlen(s); i++) 
      { 
        if(isalpha( (unsigned char) s[i]) )
         s[j++] = s[i];        
      }
      s[j] = '\0';            
    }     
    
    void expand(char* s, char* result) 
    { 
       int i;
       char alphabet[ALPHA] = "abcdefghijklmnopqrstuvwxyz";    
       justLetters(s);
       printf("The string is %s\n", s);   
    }     
    
    int main(void) 
    { 
      char *s = malloc(MAXSIZE * sizeof(char));    
      char *result = malloc(MAXSIZE * sizeof(char));
      
      do { 
      printf("Enter two letters separated by hyphens: ");
      if(fgets(s, MAXSIZE, stdin))
       printf("You entered: %s", s);
      } while((!isalpha( (unsigned char) s[0]) ) && (s[1] != '-') &&
               (!isalpha( (unsigned char) s[2]) ) );
                  
      
      expand(s, result); 
      
      free(s);
      free(result);
      return 0;
    }
    Last edited by thames; 11-13-2012 at 11:24 AM.

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Is this the do/while you have questions about?
    Code:
      do {
      printf("Enter two letters separated by hyphens: ");
      if(fgets(s, MAXSIZE, stdin))
       printf("You entered: %s", s);
      } while((!isalpha( (unsigned char) s[0]) ) && (s[1] != '-') &&
               (!isalpha( (unsigned char) s[2]) ) );
    But either way why are you casting the character to an unsigned character?

    Jim

  3. #3
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    > So, what's the definitive way to fix this problem?
    There isn't one definitive way to fix it, but probably the most common involves putting a check to ensure you don't exceed the bounds in any loop you use on that string. Perhaps:
    Code:
    while (i < MAXLINE && s[i] != '\0')  // while i is within bounds, and we haven't hit the null terminator
    // similar version with for loop
    for (i = 0; i < MAXLINE && s[i] != '\0'; i++)
    Or, alternatively, you can put an if statement in the loop that breaks out when the limit is reached:
    Code:
    while (s[i] != '\0') {
        if (i < MAXLINE) {
            break;
        }
    }
    I usually prefer putting a fundamental condition like that in the loop condition itself, but sometimes, if your logic for incrementing i is a little complicated, the if/break solution ends up cleaner.

  4. #4
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    But either way why are you casting the character to an unsigned character?
    another mate from this forum told me I should cast a char if I decided to use an "is" or "to" function.

    edit: yes, that do-while.
    Last edited by thames; 11-13-2012 at 04:34 PM.

  5. #5
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    There is no need to cast the char to an unsigned char. Just use the char.

    Jim

  6. #6
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    Quote Originally Posted by jimblumberg View Post
    There is no need to cast the char to an unsigned char [when using the is* or to* functions]. Just use the char.
    Is there is a chance the value falls outside the range of unsigned char, the cast prevents Undefined Behaviour.
    The range of a char (on some implementations) includes negative numbers: the range of unsigned char never includes negative numbers.

  7. #7
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Quote Originally Posted by jimblumberg View Post
    There is no need to cast the char to an unsigned char. Just use the char.
    n1570.pdf: 7.4.1:
    In all cases the argument is an int, the value of which shall be
    representable as an unsigned char or shall equal the value of the macro EOF. If the
    argument has any other value, the behavior is undefined.
    If you're using an implementation where char is signed it's likely they'll be passing a negative non-EOF value to those functions, which yields undefined behaviour according to that above quotation. It's necessary to cast the char value to an unsigned char before you cast it to an int in such a scenario.

  8. #8
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    Code:
    #include <stdio.h> 
    #include <string.h> 
    #include <ctype.h> 
    #include <stdlib.h> 
    
    #ifndef ALPHA
       #define ALPHA 26
    #endif   
    
    #ifndef MAXSIZE 
       #define MAXSIZE 20
    #endif   
    
    static int nLetters;
    
    int justLetters(char*);
    void expand(char*, char*);
    void shellsort(char*, int);
    
    void shellsort(char* a, int n) 
    { 
       int gap, i, j, temp;
       
       for(gap = nLetters/2; gap > 0; gap /= 2) 
        for(i = gap; i < nLetters; i++)     
          for(j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap) 
          { 
             temp = a[j];
             a[j] = a[j + gap];
             a[j + gap] = temp; 
          }       
    }     
    
    
    int justLetters(char* s)
    { 
      int i, j;
      
      for(i = 0, j = 0; i < strlen(s); i++) 
      { 
        if(isalpha( (unsigned char) s[i]) )
        { 
           s[j++] = s[i];        
           nLetters++;
        }    
      }
      s[j] = '\0';            
      return nLetters;
    }     
    
    void expand(char* s, char* result) 
    { 
       int c;
       nLetters = justLetters(s);
       shellsort(s, nLetters);
       printf("The expanded string is ");
       for(c = s[0]; c <= s[nLetters - 1]; c++) 
         putchar(c);
       putchar('\n');  
    }     
    
    int main(void) 
    { 
      char *s = malloc(MAXSIZE * sizeof(char));    
      char *result = malloc(MAXSIZE * sizeof(char));
      
      do { 
        printf("Enter n letters separated by hyphens: ");
        fgets(s, MAXSIZE, stdin);
       } while(strlen(s) > MAXSIZE); 
       
      printf("You entered: %s\n", s);
      expand(s, result); 
      
      free(s);
      free(result);
      return 0;
    }
    Is it just my impression or the do-while limited the input to the MAXSIZE I coded instead of obliging me to input again?

    Code:
     
    ./expand
    Enter n letters separated by hyphens: a-c-d-b-q-t-y-u-x-d-e-f-f-q-a-b-c-h-j-k-l-paaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    You entered: a-c-d-b-q-t-y-u-x-d
    The expanded string is abcdefghijklmnopqrstuvwxy

  9. #9
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    The only time a value will fall outside the range of a char will be if you use actually use an int for the parameter. Since you are passing a char, there is no way you will have problems since the function is defined as int isalpha(int), therefore the cast is unnecessary in this instance.

    Jim

  10. #10
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    Quote Originally Posted by jimblumberg View Post
    The only time a value will fall outside the range of a char will be if you use actually use an int for the parameter. Since you are passing a char, there is no way you will have problems since the function is defined as int isalpha(int), therefore the cast is unnecessary in this instance.

    Jim
    I think you missed the part where the value of the int "shall be representable as an unsigned char". A char might contain a negative value on implementations where char is signed, and that does not fulfill the requirement.

  11. #11
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    Quote Originally Posted by jimblumberg View Post
    The only time a value will fall outside the range of a char will be if you use actually use an int for the parameter. Since you are passing a char, there is no way you will have problems since the function is defined as int isalpha(int), therefore the cast is unnecessary in this instance.

    Jim
    Not all the world's a vax. Some people have names like José or Zoë or ...
    Last edited by qny; 11-13-2012 at 05:36 PM.

  12. #12
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    I'm trying to do the complete exercise of KnR i.e. deal with things like:

    a-z0-9

    I coded two shellsorts: one for integers and the other for chars to deal with this problem.

    datastructures.h

    Code:
     
      int binsearch(int, int*, int); 
      void swap(int*, int*);
      void Shellsort(int*, int); /* please note the uppercase - it's the integer shellsort */
    shellsort.c

    Code:
     
    
    #include "../Headers/datastructures.h"
    #include <stdio.h> 
    
    void Shellsort(int* a, int n) 
    { 
       int gap, i, j, temp;
       
       for(gap = n/2; gap > 0; gap /= 2)
         for(i = gap; i < n; i++) 
           for(j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap) 
           { 
             temp = a[j];
             a[j] = a[j + gap];
             a[j + gap] = temp;
           }              
    }
    expand.c

    Code:
     
    
    #include <stdio.h> 
    #include <string.h> 
    #include <ctype.h> 
    #include <stdlib.h> 
    #include "Headers/datastructures.h"
    #include "DataStructures/shellsort.c"
    
    #ifndef ALPHA
       #define ALPHA 26
    #endif   
    
    #ifndef MAXSIZE 
       #define MAXSIZE 20
    #endif   
    
    static int nLetters, nDigits;
    static int  digits[MAXSIZE];
    static char letters[MAXSIZE];
    
    void lettersdigits(char*);
    void expand(char*);
    void shellsort(char*, int);
    
    void shellsort(char* a, int n) 
    { 
       int gap, i, j, temp;
       
       for(gap = nLetters/2; gap > 0; gap /= 2) 
        for(i = gap; i < nLetters; i++)     
          for(j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap) 
          { 
             temp = a[j];
             a[j] = a[j + gap];
             a[j + gap] = temp; 
          }       
    }     
    
    void lettersdigits(char* s)
    { 
      int i, j, z; 
      
      for(i = 0, j = 0, z = 0; i < strlen(s); i++) 
      { 
        if(isalpha( (unsigned char) s[i]) )
        { 
           letters[j++] = s[i];        
           nLetters++;
        }
        if(isdigit(s[i]))
        { 
          digits[z++] = s[i];
          nDigits++;      
        }         
      }
      letters[j] = '\0';
      digits[z] = '\0';            
    }     
    
    void expand(char* s) 
    { 
       int c;
       lettersdigits(s);
       shellsort(letters, nLetters);
       Shellsort(digits, nDigits);
       printf("The expanded string is ");
       for(c = letters[0]; c < s[nLetters]; c++) 
         putchar(c);
       for(c = digits[0]; c < s[nDigits]; c++)
         putchar(c);    
       putchar('\n');  
    }     
    
    int main(void) 
    { 
      char *s = malloc(MAXSIZE * sizeof(char));    
      
      do { 
        printf("Enter letters and digits separated by hyphens: ");
        fgets(s, MAXSIZE, stdin);
      } while(strlen(s) > MAXSIZE); 
       
      printf("You entered: %s\n", s);
      expand(s); 
      
      free(s);
      
      return 0;
    }
    output:

    Code:
     
    ./expand
    Enter letters and digits separated by hyphens: a-z0-9
    You entered: a-z0-9
    
    The expanded string is abcdefghijklmnopqrstuvwxy0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxy
    Code:
     
    
    ./expand
    Enter letters and digits separated by hyphens: a-z
    You entered: a-z
    
    The expanded string is abcdefghijklmnopqrstuvwxy
    
    
     !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`
    edit:

    I fixed the two for's:

    Code:
      
      for(c = letters[0]; c < letters[nLetters]; c++) 
         putchar(c);
       for(c = digits[0]; c < digits[nDigits]; c++)
         putchar(c);
    but now I get:

    Code:
     
     ./expand
    Enter letters and digits separated by hyphens: a-z0-9
    You entered: a-z0-9
    
    The expanded string is
    Last edited by thames; 11-13-2012 at 06:50 PM.

  13. #13
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193

    Question

    I fixed the program rewriting the for's:

    Code:
     
    for(c = letters[0]; c <= letters[nLetters - 1]; c++) 
         putchar(c);
       for(c = digits[0]; c <= digits[nDigits - 1]; c++)
         putchar(c);
    but I still don't understand why the other for doesn't work. because I thought

    Code:
     
    c <= letters[nLetters - 1] 
    c < letters[nLetters]
    were semantically and logically equivalents. Weren't they? I'm really puzzled:

    considering nLetters equals to 3:

    Code:
     
    c <= letters[2]  -  0 1 2
    c < letters[3]    -  0 1 2

  14. #14
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    It depends on the data of the char.

    Maybe you mean this
    Code:
    #include <string.h>
    
    int main(void)
    {
        int array[5]={0,1,2,3,4};
        int i;  
    
        for( i = 0 ; i < 5 ; i++ )
            printf("%d\n",array[i];
    
        for( i = 0 ; i <= 4 ; i++ )
            printf("%d\n",array[i];
       
        return 0;
    }

  15. #15
    Tears of the stars thames's Avatar
    Join Date
    Oct 2012
    Location
    Rio, Brazil
    Posts
    193
    Code:
     It depends on the data of the char
    how come? why didn't it work for my example?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. int overflow
    By nimitzhunter in forum C++ Programming
    Replies: 9
    Last Post: 12-12-2010, 01:36 AM
  2. overflow...?
    By Tool in forum C Programming
    Replies: 10
    Last Post: 12-23-2009, 03:41 PM
  3. Overflow
    By valthyx in forum C Programming
    Replies: 14
    Last Post: 06-01-2009, 04:41 PM
  4. String overflow behaviour
    By Morgan in forum C Programming
    Replies: 15
    Last Post: 10-10-2003, 02:37 AM
  5. Replies: 7
    Last Post: 01-02-2002, 09:16 PM

Tags for this Thread