Thread: Help with progamming assignment

  1. #1
    I'm a computer snoopfrogg's Avatar
    Join Date
    Feb 2019
    Posts
    29

    Help with progamming assignment

    I am working on a program that ask the following:

    Write a program that replace repeated three characters in a string by the character followed by 3. For example, the string aabccccaaabbbbcc would become aabc3ca3b3cc. When there are more than three repeated characters, the first three characters will be replaced by the character followed by 3. You can assume the string has only lowercase letters (a-z).

    Your program should include the following function:
    Code:
    void replace(char *str, char *replaced);
    The function expects str to point to a string, replaced represents the string storing the replaced string. For example, if the str is helllo, the function will store hel3o in replaced.

    1) Name your program repeated_chars.c.
    2) Assume input is no longer than 1000 characters.
    3) The replace function should use pointer arithmetic (instead of array subscripting). In other words, eliminate the loop index variables and all use of the [] operator in the function.
    4) To read a line of text, use the read_line function (the pointer version) in the lecture notes.

    I have the program working correctly but it doesn't follow number 3. Here's what my code looks like:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define SIZE 1000 // forgive me for I have sinned
    
    int read_line(char *str, int n);
    void replace(char *str, char *replaced);
    
    int main(){
    
        char str[SIZE + 1];
        char replaced[SIZE + 1];
    
        printf("Please enter a word: ");
        read_line(str, SIZE);
    
        replace(str, replaced);
        printf("Output: %s", replaced);
        return 0;
    }
    
    void replace(char *str, char *replaced){
    
        int i, j = 0;
    
        // loop till end of the first line
        for(i = 0; *(str + i) !=  '\0'; i++){
            //check the first, second and third characters in the string
            if((*(str + i) == *(str + (i + 1))) && (*(str + i) == *(str + (i + 2)))){
                // replace the character
                *(replaced + j) = *(str + i);
                j++;
                // assign 3 to the replaced string
                *(replaced + j) = '3';
                j++;
                i += 2; // increment the index of the original string
            }
            else{
                *(replaced + j) = *(str + i);
                j++;
            }
        }
        // terminates string
        *(replaced + j) = '\0';
    }
    
    int read_line(char *str, int n){
    
        int ch;
        int i = 0;
    
        while((ch = getchar()) != '\n'){
            if(i < n){
                *str++ = ch;
                i++;
            }
        }
        *str = '\0'; // terminates string
        return i; // number of characters stored
    }
    How do I go about eliminating the loop index to get the same output that I'm looking for? I'm assuming I have to use a pointer in my for loop, but I'm not entirely sure if that's correct. I'm hoping someone can give me some references to point me in the right direction.

    Also, here is the shell script we're using to test our inputs
    Code:
    # try_repeated is a Unix shell script that will be used to test project 5.
    # To use the script, copy it into the same directory as your scource file
    # Set execute permission for the file by issuing the command:
    # chmod +x try_repeated
    # Compile your program, producing a.out as the executable
    # To run the script, type 
    # ./try_repeated
    # The user input from the script will not be shown on the screen.
    # Compare the results from your program with the expected results on the test cases.
    echo '===================================================='
    #
    ./a.out <<-EndOfInput
    topssecret
    EndOfInput
    echo '----------------------------------------------------'
    echo 'Expected:'
    echo 'Enter a word: topssecret'
    echo 'Output: topssecret'
    #
    echo '===================================================='
    #
    ./a.out <<-EndOfInput
    fleeenow
    EndOfInput
    echo '----------------------------------------------------'
    echo 'Expected:'
    echo 'Enter a word: fleeenow'
    echo 'Output: fle3now'
    #
    echo '===================================================='
    #
    ./a.out <<-EndOfInput
    asssasssinate
    EndOfInput
    echo '----------------------------------------------------'
    echo 'Expected:'
    echo 'Enter a word: asssasssinate'
    echo 'Output: as3as3inate'
    echo '===================================================='
    #
    ./a.out <<-EndOfInput
    defendddd
    EndOfInput
    echo '----------------------------------------------------'
    echo 'Expected:'
    echo 'Enter a word: defendddd'
    echo 'Output: defend3d'
    echo '===================================================='
    Sorry for the long post... Thank you in advance!

  2. #2
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    You won't get exact code since that looks like an exam question of sorts but here is an inefficient version if such a function off the top of my head
    Code:
    //psuedo code
    int count = 0
    while *str++
      if strcmp str, replace == 0
        *(++str) = 3
          tmp = str; tmps = str;
          for ++tmpd, ++tmps, ++tmps; *tmps; ++tmp, ++tmps
            tmpd = tmps

  3. #3
    I'm a computer snoopfrogg's Avatar
    Join Date
    Feb 2019
    Posts
    29
    Quote Originally Posted by awsdert View Post
    You won't get exact code since that looks like an exam question of sorts but here is an inefficient version if such a function off the top of my head
    Code:
    //psuedo code
    int count = 0
    while *str++
      if strcmp str, replace == 0
        *(++str) = 3
          tmp = str; tmps = str;
          for ++tmpd, ++tmps, ++tmps; *tmps; ++tmp, ++tmps
            tmpd = tmps
    is tmp declared as a char *tmp? I know what you posted was psuedo code. I'm just trying to make sense of it.

  4. #4
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,738
    You can just increment the str and replaced pointers. It's essentially the same thing (assuming you don't want to reuse the original pointers, of course).
    Devoted my life to programming...

  5. #5
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by snoopfrogg View Post
    is tmp declared as a char *tmp? I know what you posted was psuedo code. I'm just trying to make sense of it.
    My post got deleted, anyways yes, it is taking what was originally a char* after all and is then used to modify which therefore renders const inapplicable here

  6. #6
    I'm a computer snoopfrogg's Avatar
    Join Date
    Feb 2019
    Posts
    29
    Quote Originally Posted by GReaper View Post
    You can just increment the str and replaced pointers. It's essentially the same thing (assuming you don't want to reuse the original pointers, of course).
    I incremented the str and replaced pointers but I still can figure out how to fix my for loop. All the expected outputs are correct, but I would like to eliminate the loop index to get the same output.

    Here's what my function looks like now:

    Code:
    void replace(char *str, char *replaced){
    
        int i;
    
        // loop till end of the first line
        for(i = 0; *(str + i) !=  '\0'; i++){
    
            //check the first, second and third characters in the string
            if((*(str + i) == *(str + (i + 1))) && (*(str + i) == *(str + (i + 2)))){
                
                // replace the character
                *(replaced++) = *(str + i);
                // assign 3 to the replaced string
                *(replaced++) = '3';
                i += 2; // increment the index of the original string
            }
            else{
                *(replaced++) = *(str + i);
            }
        }
        // terminates string
        *(replaced++) = '\0';
    }

  7. #7
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,738
    You only increment the replaced pointer though. Instead of incrementing the loop index, increment the str pointer, and you will no longer need the index.
    Devoted my life to programming...

  8. #8
    I'm a computer snoopfrogg's Avatar
    Join Date
    Feb 2019
    Posts
    29
    Quote Originally Posted by GReaper View Post
    You only increment the replaced pointer though. Instead of incrementing the loop index, increment the str pointer, and you will no longer need the index.
    Would it be easier for me to use a while loop in this situation?

  9. #9
    I'm a computer snoopfrogg's Avatar
    Join Date
    Feb 2019
    Posts
    29
    I tried using a while loop in the replaced function to see if that would produce the same output. With that being said, my output is incorrect.

    If I input defendddd, the output is defend3ddd instead of defend3d. I think my issue is in my if statement.

    Here's what my code looks like now:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define SIZE 1000 
    
    int read_line(char *str, int n);
    void replace(char *str, char *replaced);
    
    int main(){
    
        char str[SIZE + 1];
        char replaced[SIZE + 1];
    
        printf("Please enter a word: ");
        read_line(str, SIZE);
    
        replace(str, replaced);
        printf("Output: %s", replaced);
        return 0;
    }
    
    void replace(char *str, char *replaced){
        
        int i = 0;
    
        while(*str != '\0'){
            //check the first, second and third characters in the string
            if((*(str + i) == *(str + (i + 1))) && (*(str + i) == *(str + (i + 2)))){
                // replace the character
                *(replaced++) = *(str++);
                // assign 3 to the replaced string
                *(replaced++) = '3';
                i += 2; // increment the index of the original string
            }
            else{
                *(replaced++) = *(str++);
                
            }
        }
        // terminates string
        *(replaced++) = '\0';
    }
    
    
    int read_line(char *str, int n){
    
        int ch;
        int i = 0;
    
        while((ch = getchar()) != '\n'){
            if(i < n){
                *str++ = ch;
                i++;
            }
        }
        *str = '\0'; // terminates string
        return i; // number of characters stored
    }
    Pointer arithmetic isn't my strong suite, and I'm trying to better understand my mistakes. Thanks

  10. #10
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Why are you complicating the comparison with manual compare? I actually gave you the right function for this situation and its usage

  11. #11
    I'm a computer snoopfrogg's Avatar
    Join Date
    Feb 2019
    Posts
    29
    I figured it out! I believe my assumption about my if statement being the problem was correct!

    Here's what my code looks like now:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define SIZE 1000 
    
    int read_line(char *str, int n);
    void replace(char *str, char *replaced);
    
    int main(){
    
        char str[SIZE + 1];
        char replaced[SIZE + 1];
    
        printf("Please enter a word: ");
        read_line(str, SIZE);
    
        replace(str, replaced);
        printf("Output: %s", replaced);
        return 0;
    }
    
    void replace(char *str, char *replaced){
    
        while(*str != '\0'){
            //check the first, second and third characters in the string
            if(*(str) == *(str + 1) && (*(str) == *(str + 2))){
                // replace the character
                *(replaced++) = *(str++);
                // assign 3 to the replaced string
                *(replaced++) = '3';
                str += 2; // increment the index of the original string
            }
            else{
                *(replaced++) = *(str++);
                
            }
        }
        // terminates string
        *(replaced++) = '\0';
    }
    
    
    int read_line(char *str, int n){
    
        int ch;
        int i = 0;
    
        while((ch = getchar()) != '\n'){
            if(i < n){
                *str++ = ch;
                i++;
            }
        }
        *str = '\0'; // terminates string
        return i; // number of characters stored
    }

  12. #12
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Still problematic... Consider if str points to string with a single character: "a". When your code do:
    Code:
    if(*(str) == *(str + 1) && (*(str) == *(str + 2)))
    Then (str+2) will point to "garbage"...

    Tips:

    1 - s[i] is the same thing as *(s+i). So if you feel more confortable to create a routine using [] operador, do it, later you can change to pointer expressions easily.

    2 - There is no need to use parentesis on *(replaced++) or *(str++). Pos-increment have greater precedence than indirection... This is the same as *replaced++ or *str++. You must use parentesis only if you want to post-increment the value pointed, as in (*str)++.

  13. #13
    I'm a computer snoopfrogg's Avatar
    Join Date
    Feb 2019
    Posts
    29
    Quote Originally Posted by flp1969 View Post
    Still problematic... Consider if str points to string with a single character: "a". When your code do:
    Code:
    if(*(str) == *(str + 1) && (*(str) == *(str + 2)))
    Then (str+2) will point to "garbage"...
    Do you mind explaining this, please?

  14. #14
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    he means you're assuming that at the point you start comparing str values str will have at least 3 characters but this only proves true in a test scenario when you control the input and even then once the string pointer increments to a point where there are 2 or less characters it will segfault when trying to compare

  15. #15
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Quote Originally Posted by awsdert View Post
    he means you're assuming that at the point you start comparing str values str will have at least 3 characters but this only proves true in a test scenario when you control the input and even then once the string pointer increments to a point where there are 2 or less characters it will segfault when trying to compare
    Probably not "seg fault" because the granularity of data segment (or rodata, or stack) is 4 KiB, but definitively "garbage".

    @snoopfrog, when you declare and initiailze an array as:
    Code:
    char s[] = "a";
    This array has 2 bytes only. It is the same as:
    Code:
    char s[] = { 'a', '\0' };
    If you do:
    Code:
    char *p = s;
    When you do an indirect access with * operador adding an offset of 2, like *(p+2), you are referencing something, but not an element of the array s.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. The C Progamming Language Excercise 5-4
    By mekadir in forum C Programming
    Replies: 7
    Last Post: 09-03-2015, 07:05 AM
  2. Help for my assignment!
    By 110abbidi in forum C Programming
    Replies: 5
    Last Post: 08-09-2012, 11:25 PM
  3. Replies: 4
    Last Post: 01-08-2012, 05:31 AM
  4. Replies: 3
    Last Post: 04-26-2009, 08:54 AM
  5. new to c progamming any one can help
    By manalidris in forum C Programming
    Replies: 1
    Last Post: 05-13-2002, 05:05 AM

Tags for this Thread