Thread: Zed Shaw Learn C The Hard Way - Extra Credit 15.3

  1. #1
    Registered User Fauveboy's Avatar
    Join Date
    Apr 2014
    Posts
    42

    Zed Shaw Learn C The Hard Way - Extra Credit 15.3

    I hope I can clearly state my problem here.
    I’m on another "extra credit" exercise of Zed Shaws Learn C the Hard Way. It asked to use fewer functions than what the exercise originally starts with hinting at the relevance of the "can_print_it" function. So I've commented out the original code at tried to work how to reduce it to just the functions "print_arguments" and "Print_letters". I’m going to copy and paste the second question of the exercise, it says:

    2. Have print_arguments figure how long each argument string is using the strlen function, and then passthat length to print_letters. Then, rewrite print_letters so it only processes this fixed length anddoesn’t rely on the '\0' terminator.

    So again I've commented out any original code so its all still there and tried to use the strlen function.

    I've approached this by writing out in normal English to myself on some A4 what I think is happening throughout the chain of functions and I was going to type this out below if it not to tedious for people so I can be chased up on any incorrect logic.

    The main function takes the argument count and argument vector. This is passed to the function print arguments which takes the arguments in the same way passing the the values through a for loop. The print_letters function is called at the end of this for-loop the argument of print_letters function "argv[i]" is counting through the characters.
    At this point I've commented it out for now but this is where I've tried to use strlen. When you uncomment this part is does actually print out the length of each string (vector) but when I try to replace the '\0' character in the for-loop in print_letters with the variable length its quite frankly doesn't work! Is that because its out of scope?.....The last part you can see I've taken what "can_print_it" was doing and tried to place that with the for-loop of the print_letters function but it doesn't manage to print anything out, I thats what I cant work out.

    So just to clarify
    - I can't work out how to send to values of the variable length in print_arguments function to replace the null character in the for-loop of the print_letters function.
    - I can't see why the printf statement at the end of the for-loop in the print_letters function doesn't print out what I'm trying to return from isalpha || isblank.

    Sorry about the length of this post I’m keen to understand this so I wanted to make sure I can explain everything I needed.

    Thank you very much in advance!

    Code:
    #include <stdio.h>#include <ctype.h>
    
    
    // forward declarations
    //int can_print_it(char ch);
    int  print_letters(char arg[]);
    
    
    void print_arguments(int argc, char *argv[])
     {
        int i = 0;
        int length;    
    
    
        for(i = 0; i < argc; i++){
        
    //        length = strlen(argv[i]);  //in print_letters turning a 
        //    printf(" Length is %d \n", length);
    
    
            print_letters(argv[i]); //does "i" arrive as "char arg"
            
        }
     }
    
    
    int print_letters(char arg[])
     {
        int i = 0;
    
    
        for(i = 0; arg[i] != '\0'; i++) {
            char ch = arg[i];
            }    
            //if(can_print_it(ch) {
                 //printf(" '%c' ==%d ", ch, ch);
            return isalpha (ch) || isblank(ch) ; 
                printf("'%c' == %d ", ch, ch);
                    
    
    
        printf("\n");    
        return 0;
         }
    
    
    
    
    // }
    
    
    //int can_print_it(char ch)
    //    {
    //    return isalpha(ch) || isblank(ch);
    //     }
    
    
    
    
    
    
    
    
    int main(int argc, char *argv[])
     {
        print_arguments(argc, argv);
        return 0;
     }
    Last edited by Fauveboy; 08-26-2014 at 11:09 AM.

  2. #2
    Registered User
    Join Date
    May 2009
    Posts
    3,674
    You need to learn to indent your code, correctly; then the problem would likely be visible.

    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    
    // forward declarations
    //int can_print_it(char ch);
    int  print_letters(char arg[]);
    
    
    void print_arguments(int argc, char *argv[])
    {
        int i = 0;
        int length;
    
    
        for(i = 0; i < argc; i++)
        {
    
    //        length = strlen(argv[i]);  //in print_letters turning a
            //    printf(" Length is %d \n", length);
    
    
            print_letters(argv[i]); //does "i" arrive as "char arg"
    
        }
    }
    
    
    int print_letters(char arg[])
    {
        int i = 0;
    
    
        for(i = 0; arg[i] != '\0'; i++)
        {
            char ch = arg[i];
        }
        //if(can_print_it(ch) {
        //printf(" '%c' ==%d ", ch, ch);
        return isalpha (ch) || isblank(ch) ;
        printf("'%c' == %d ", ch, ch);
    
    
    
        printf("\n");
        return 0;
    }
    
    
    
    
    // }
    
    
    //int can_print_it(char ch)
    //    {
    //    return isalpha(ch) || isblank(ch);
    //     }
    
    
    int main(int argc, char *argv[])
    {
        print_arguments(argc, argv);
        return 0;
    }
    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    3,674
    FYI: The return keyword means the function returns that value; therefore code after a return is executed in a function is NOT ran.

    Edit: I suggest reading about "program flow" because you do NOT understand program flow as related to return statements.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,446
    Have print_arguments figure how long each argument string is using the strlen function, and then passthat length to print_letters.
    You need to modify the print_letters() function so you can pass the length of the string into it as a parameter. You would then use this parameter in the condition section of the for(; loop.

    Jim

  5. #5
    Registered User
    Join Date
    Jan 2012
    Posts
    5
    Alternatively, examine the methodology described here: Variable Argument Lists in C and C++ - Cprogramming.com

  6. #6
    Registered User Fauveboy's Avatar
    Join Date
    Apr 2014
    Posts
    42
    Thank you for your responses so far.


    So, I've indented the code as Tim S explained which has helped as its tidier now.


    Jims suggestion was quite clear to me. I have now modified print_letters() but the compiler is now complaining that theres an "implicit declaration of function 'strlen'" but from what I've been taught I can't see where to correct that?


    However, when I run the code the first printf in the for loop of print_arguments does print out the sentence " Length is 6" in this case as there're six characters in the command line instruction ./ex14. However still, Tim S also mentioned what the return function is for and I am getting the "warning: control reaches end of non-void function" …I know somethings not right here although its still not clear to me what value I need to return from print_letters for the complier not to warn me. I'm not sure if its the return function issue alone or something else I've not yet applied to have the printf in print_letters not format the data from isalpha and isblank and ultimatly have all the code perform as it should.

    Once again thanks in advance!

    If it can be made clear to me and where I'am going wrong can be set straight its very much appreciated, cheers!

    Code:
    #include <stdio.h>
    #include <ctype.h>
     
     
    // forward declarations
    //int can_print_it(char ch);
    int  print_letters(char arg[], int arglength);
     
     
    void print_arguments(int argc, char *argv[])
    {
         int i = 0;
         int length;
     
     
         for(i = 0; i < argc; i++)
         {
     
              length = strlen(argv[i]);  
              printf(" Length is %d\n", length);
     
     
              print_letters(argv[i], length); //does "i" arrive as "char arg"
     
         } 
    }
     
     
    int print_letters(char arg[], int arglength)
    {
         int i = 0;
    
    
         for(i = 0; arg[i] != arglength; i++) {
              char ch = arg[i];
        
              //if(can_print_it(ch) {
              //printf(" '%c' ==%d ", ch, ch);
              return isalpha(ch) || isblank(ch) ;
              printf("'%c' == %d ", ch, ch);
         }  
     
     
         printf("\n");
        
    }
     
     
     
     
    // }
     
     
    //int can_print_it(char ch)
    //    {
    //    return isalpha(ch) || isblank(ch);
    //     }
     
     
    int main(int argc, char *argv[])
    {
         print_arguments(argc, argv);
         return 0;
    }

  7. #7
    Registered User
    Join Date
    May 2010
    Posts
    4,446
    Jims suggestion was quite clear to me. I have now modified print_letters() but the compiler is now complaining that theres an "implicit declaration of function 'strlen'" but from what I've been taught I can't see where to correct that?
    You need to include the proper header file for that function, you may want to Google "strlen" and see if you can figure out what file needs to be included.

    I am getting the "warning: control reaches end of non-void function"
    Look at your print_letters() function, you promised the compiler that you would return an int from this function, did you? Why are you trying to return something from this function? Where are you trying to use anything returned from this function? Perhaps you shouldn't be returning anything from this function?

    Do you know that there are ways to print the entire string at once, without the need for you to loop through the string and print each character?

    Do you know when the program encounters a return statement the function immediately returns to the calling function, effectively stopping any loop and ignoring everything after the return?

    Jim

  8. #8
    Registered User Fauveboy's Avatar
    Join Date
    Apr 2014
    Posts
    42
    Thanks Jim.


    So I've been able to think about the return function I previously used and as you can see from the code I've made the appropriate changes, as its clear to me now that its not required for print_letters().


    I get no compiling errors now. However there is one single issue I have left to understand regarding this exercise.

    2. Have print_arguments figure how long each argument string is using the strlen function, and then pass that length to print_letters. Then, rewrite print_letters so it only processes this fixed length and doesn’t rely on the '\0' terminator.

    I've tried this a few ways and this is what I am going with. Quite frankly I am confused but I think thats due to the fact that I am stuck for knowledge here. I've replaced '\0' with arglength but I know this is not going to work due to its value being the wrong type? Its an integer rather than a terminator character.

    Does this exercise actually applying a better design, would it be more efficient without the '\0'? I can't see where to correct this. When I run the code It prints out a mess of letters…

    What I've described above is my main concern but Im yet to find out how to print an entire string without the for loop which you mentioned is possible.

    Code:
    #include <stdio.h>
    #include <ctype.h>
    #include <string.h> 
     
    // forward declarations
    //int can_print_it(char ch);
    void  print_letters(char arg[i], int arglength);
     
    void print_arguments(int argc, char *argv[])
    {
         int i = 0;
         int length;
     
         for(i = 0; i < argc; i++)
         {
     
              length = strlen(argv[i]);  
              printf(" Length is %d\n", length);
     
              print_letters(argv[i], length); //does "i" arrive as "char arg"
         } 
    }
     
     
    void print_letters(char arg[i], int arglength)
    {
    //     int i = 0;
    
    
         for(; arg[i] != arglength; i--) {//entire string at once without for loop?
              char ch = arg[i];
        
              if(isalpha(ch) || isblank(ch)){ 
                   printf("'%c' == %d ", ch, ch);
              }
         }  
     
         printf("\n");
    
    
    }
     
     
    int main(int argc, char *argv[])
    {
         print_arguments(argc, argv);
         return 0;
    }

  9. #9
    Registered User
    Join Date
    May 2010
    Posts
    4,446
    You need to start by fixing all your compiler errors and warnings. Here are the messages my compiler issues when compiling your code:

    /home/jim/Working/c_homework/main.c|7|error: ‘i’ undeclared here (not in a function)|
    /home/jim/Working/c_homework/main.c|9|warning: no previous declaration for ‘print_arguments’ [-Wmissing-declarations]|
    /home/jim/Working/c_homework/main.c||In function ‘print_arguments’:|
    /home/jim/Working/c_homework/main.c|20|error: type of formal parameter 1 is incomplete|
    /home/jim/Working/c_homework/main.c|25|error: ‘i’ undeclared here (not in a function)|
    /home/jim/Working/c_homework/main.c||In function ‘print_letters’:|
    /home/jim/Working/c_homework/main.c|30|error: ‘i’ undeclared (first use in this function)|
    /home/jim/Working/c_homework/main.c|30|note: each undeclared identifier is reported only once for each function it appears in|
    /home/jim/Working/c_homework/main.c|25|warning: unused parameter ‘arg’ [-Wunused-parameter]|
    /home/jim/Working/c_homework/main.c|9|confused by earlier errors, bailing out|
    ||=== Build finished: 5 errors, 2 warnings (0 minutes, 0 seconds) ===|
    You really need to review your notes and your textbook for information on how to create and use functions that have arrays as parameters.

    Compare your print_arguments() function implementation, which is correct, with your print_arguments() function. Look closely at the array parameter. Do you notice any difference?



    Jim

  10. #10
    Registered User Fauveboy's Avatar
    Join Date
    Apr 2014
    Posts
    42
    I don't how I posted that code with so many compiling errors to it, that was a mistake. Well I really have got no compiling errors now!

    I am doing my best.

    I think I've seen the difference I needed to understand (hence no compiling errors) but when I run the code its still executes scrambled words? From the sources available to me I can't understand whats confusing to code at this late stage, beside what I explained about substituting the character null '\0' with arglength but otherwise Im kind of scrambled myself.

    Code:
     
    
    #include <stdio.h>
    #include <ctype.h>
    #include <string.h> 
      
    // forward declarations
    //int can_print_it(char ch);
    void  print_letters(char arg[], int arglength);
      
    void print_arguments(int argc, char *argv[])
    {
         int i = 0;
         int length;
      
         for(i = 0; i < argc; i++)
         {
      
              length = strlen(argv[i]);  
              printf(" Length is %d\n", length);
      
              print_letters(argv[i], length); 
         } 
    }
      
      
    void print_letters(char arg[], int arglength)
    {
         int i = 0;
     
     
         for( i = arglength; arg[i] != arglength; i--) { //entire string at once without for loop?
              char ch = arg[i];
         
              if(isalpha(ch) || isblank(ch)){ 
                   printf("'%c' == %d ", ch, ch);
              }
         }  
      
         printf("\n");
     
     
    }
      
      
    int main(int argc, char *argv[])
    {
         print_arguments(argc, argv);
         return 0;
    }

  11. #11
    Registered User
    Join Date
    Jun 2011
    Posts
    4,509
    I'm not completely sure what you're trying to accomplish, but looking at this:

    Code:
    for( i = arglength; arg[i] != arglength; i--)
    Can you explain what you think this is doing?

    (For bonus points, try printing out the value of 'i' in that loop.)

  12. #12
    Registered User Fauveboy's Avatar
    Join Date
    Apr 2014
    Posts
    42
    Thanks you all for your responses, I've got it now. I wanted to use strlen to get the length of the length of the command argument and use that as the comparison in the for loop, heres the working code;

    Code:
    #include <stdio.h>
    #include <ctype.h>
    #include <string.h> 
      
    // forward declarations
    //int can_print_it(char ch);
    void  print_letters(char arg[], int arglength);
      
    void print_arguments(int argc, char *argv[])
    {
         int i = 0;
         int length;
      
         for(i = 0; i < argc; i++)
         {
      
              length = strlen(argv[i]);  
              printf(" Length is %d\n", length);
      
              print_letters(argv[i], length); //does "i" arrive as "char arg"
         } 
    }
      
      
    void print_letters(char arg[], int arglength)
    {
         int i = 0;     
     
         for(i = 0; i <= arglength; i++) {//entire string at once without for loop?
              char ch = arg[i];
    	
              if(isalpha(ch) || isblank(ch)){ 
                   printf("'%c' == %d ", ch, ch);
              
              }
         }  
      
         printf("\n");
     
     
    }
      
      
    int main(int argc, char *argv[])
    {
         print_arguments(argc, argv);
         return 0;
    }

  13. #13
    Registered User
    Join Date
    Jun 2011
    Posts
    4,509
    Very nice.

    Code:
    for(i = 0; i <= arglength; i++)
    I would recommend changing the test condition to less-than (rather than less-than or equal-to).

    For instance, if arg contains "test" (for which "strlen()" would return 4), you'd only want to print indices 0 through 3.

    arg[0] == 't'
    arg[1] == 'e'
    arg[2] == 's'
    arg[3] == 't'
    arg[4] == '\0' // doesn't need to be printed

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 08-25-2014, 02:48 AM
  2. Learn C The Hard Way
    By talin in forum C Programming
    Replies: 4
    Last Post: 06-03-2013, 12:06 AM
  3. Help - Car Rite Rental (extra credit)
    By mmourot in forum C++ Programming
    Replies: 5
    Last Post: 10-13-2011, 07:00 AM
  4. Please help me with this Extra Credit program
    By DenisGFX in forum C Programming
    Replies: 10
    Last Post: 05-19-2002, 01:48 AM
  5. is C++ really hard to learn
    By Shy_girl_311 in forum C++ Programming
    Replies: 11
    Last Post: 11-11-2001, 12:15 PM

Tags for this Thread