string c program

Discussion in 'Mac Programming' started by jamesapp, May 24, 2008.

  1. jamesapp macrumors 6502a

    Joined:
    Mar 7, 2008
    #1
    i have two questions in this post:
    1.

    working on a program from a book.

    the program looks for a string, which happens to be "ould"
    the book gives as an example the lines:

    Ah Love! could you and I with Fate conspire
    To grasp this sorry Scheme of Things entire,
    Would not we shatter it to bits -- and then
    Re-mould it nearer to the Heart's Desire!

    the book says that the above lines should produce the following output:

    Ah Love! could you and I with Fate conspire
    Would not we shatter it to bits -- and then
    Re-mould it nearer to the Heart's Desire!

    the problem i have been having when i run the program, which compiled in terminal without any errors, is that when i enter a line and then press the enter key
    the computer immediatly repeats the line. i think the computer is not recognizing the newline character '\n'.
    here is my source file which i called string.c

    Code:
    #include <stdio.h>
    #define MAXLINE 1000 /* maiximum input line length */
    
    int getline(char line[], int max);
    int strindex(char source[], char searchfor[]);
    
    char pattern[] = "ould";  /* pattern to search for */
    
    /* find all lines matching pattern */
    main()
    {
      char line[MAXLINE];
      int found = 0;
      
      while (getline(line, MAXLINE) > 0) 
          if (strindex(line, pattern) >= 0) {
              printf("%s", line);
              found++;
          }
      return found;
    }
    
    /* getline: get line into s, return length */
    int getline(char s[], int lim)
    {
      int c, i;
      
      i = 0;
      while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
          s[i++] = c;
      if (c == '\n')
          s[i++] = c;
      s[i] = '\0';
      return i;
    }
    
    /* strindex: return index of t in s, -1 if none */
    int strindex(char s[], char t[])
    {
      int i, j, k;
      
      for (i = 0; s[i] != '\0'; i++) {
          for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++)
              ;
          if (k > 0 && t[k] == '\0')
              return i;
      }
      return -1;
    }
    
    is there a way to have the computer wait for EOF before printing the lines that contain the string "ould"?

    question #2.

    can someone help me turn a function into a program?

    i have a function from a book i am reading. it is supposed to reverse the string s in place. here is the function:

    Code:
    #include <string.h>
    
    /* reverse: reverse string s in place */
    void reverse(char s[])
    {
      int c, i, j;
      
      for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
           c = s[i];
           s[i] = s[j]
           s[j] = c;
      }
    }
    
    how would i go about turning this function into a executable file?
    what i want the program to do is take a character string,
    like i would type:
    abcd
    and the computer would respond with
    dcba

    any help would be appreciated.
     
  2. Doctor Q Administrator

    Doctor Q

    Staff Member

    Joined:
    Sep 19, 2002
    Location:
    Los Angeles
    #2
    That's the normal way a program works in a shell, when the input and output are from standard input (your keyboard) and standard output (your display).

    If you want to run your program, type your input, and not see your output until you are done, you could do any of these, but I'd recommend only the first.
    1. Run the program with the output going to a file, e.g.,
      Code:
      $ myprogram >myoutput.txt
      What you type:
      Ah Love! could you and I with Fate conspire
      To grasp this sorry Scheme of Things entire,
      Would not we shatter it to bits -- and then
      Re-mould it nearer to the Heart's Desire!​
      After it runs, you can display the output:
      Code:
      $ cat myoutput.txt
      What you hope to see in the file:
      Ah Love! could you and I with Fate conspire
      Would not we shatter it to bits -- and then
      Re-mould it nearer to the Heart's Desire!​
    2. Change the program so it outputs to a file, using fprintf() instead of printf(). It would have to determine a suitable output filename, which could be built into the program or passed to the program as an argument, e.g.,
      Code:
      $ myprogram myoutput.txt
      (type your input)
      $ cat myoutput.txt
      (see your results)
    3. Change the program so it collects the results and outputs them only when all input is complete. You'd need an array of strings or to allocate memory dynamically.
     
  3. ChrisA macrumors G4

    Joined:
    Jan 5, 2006
    Location:
    Redondo Beach, California
    #3
    Easy write a Main that calls the function. The example you posted does this.
     
  4. Doctor Q Administrator

    Doctor Q

    Staff Member

    Joined:
    Sep 19, 2002
    Location:
    Los Angeles
    #4
    The main program will of course call your reverse function. But on what string?

    You could have it call reverse() with a particular string, for example:
    Code:
    #include <stdio.h>
    #include <string.h>
    void reverse(char s[]) ;
    
    main()
    {
    char mystring[100] ;
    strcpy(mystring,"this is a test") ;
    printf("%s\n",mystring) ;
    reverse(mystring) ;
    printf("%s\n",mystring) ;
    }
    
    /* reverse: reverse string s in place */
    ...
    
    A more common solution is to have the main program call reverse on a string passed as an argument to the program. The main program is passed a count of arguments (usually called argc by programmers) and an array of argument as strings (usually called argv by programmers), with argv[0] being the name of the program and argv[1] being the first argument, if any.

    So you'd have a program like this:
    Code:
    main(int argc,char *argv[])
    {
    char mystring[100] ;
    
    if ( argc > 1 )
        {
        strlcpy(mystring,argv[1],sizeof(mystring));
        reverse(mystring) ;
        printf("%s\n",mystring) ;
        }
    }
    
    /* reverse: reverse string s in place */
    ...
    
    The program could be smarter than that. It could output a message if you forget to give an argument. It could loop through as many arguments as you give, reversing each one.

    I could explain more about why I used strlcpy() and why I used mystring instead of calling reverse(argv[1]) more directly, if you want more details.

    P.S. You need a semicolon after "s = s[j]" in reverse().
     
  5. jamesapp thread starter macrumors 6502a

    Joined:
    Mar 7, 2008
    #5
    what about blank spaces, the book calls them white spaces i think. could i modify the code to take into account blank spaces?
     
  6. Sander macrumors 6502

    Joined:
    Apr 24, 2008
    #6
    1. You can also type your text into a file using your favorite text editor, and "pipe" it into your program. Since your program already reads from standard input (stdin), you can easily do

    ./myprogram < myfile.txt

    Since your program also already outputs to standard output (stdout), you can redirect its output to another file too:

    ./myprogram < myfile.txt > myoutput.txt

    You get bonus points for making the specific string to look for an option to the program, so you can say

    ./skipifcontains ould < myfile.txt > myoutput.txt

    2. Please, everyone, the correct form for main() is either

    Code:
    int main(void) { /* ... */ }
    or

    Code:
    int main(int argc, char* argv[]) { /* ... */ }
     
  7. Doctor Q Administrator

    Doctor Q

    Staff Member

    Joined:
    Sep 19, 2002
    Location:
    Los Angeles
    #7
    "Whitespace" usually refers to spaces and tabs, and sometimes to spaces, tabs, and linebreaks.

    What do you mean by "take into account"? Are you saying that the pattern ould should match a line like this?
    According to this memo uld stands for Unit Load Device.​
    Or are you saying that the pattern ou ld it would match a line like this?
    Ah Love! could you and I with Fate conspire​
    Or Both?

    Just want to be clear what you are asking so we don't give the wrong advice.
     
  8. jamesapp thread starter macrumors 6502a

    Joined:
    Mar 7, 2008
    #8
    i was thinking of spaces in the reverse program.
     
  9. Doctor Q Administrator

    Doctor Q

    Staff Member

    Joined:
    Sep 19, 2002
    Location:
    Los Angeles
    #9
    Sorry, I should have realized that makes more sense.

    How to organize your program

    Removing blanks and reversing a string can be done independently and in either order, or all at once, e.g.,
    1. reverse string then remove blanks: gate man -> nam etag -> nametag
    2. remove blanks then reverse string: gate man -> gateman -> nametag
    3. reverse string and remove blanks in one pass: gate man -> nametag
    In case 1 and case 2, you can have your reverse() function do the reversing and define a separate remove_blanks() function for the other task, then call them in either order from your main() program. In case 3, you'd change your reverse() function to a reverse_and_remove_blanks() function that does both at once. (You don't really have to rename it, but that would make its purpose more clear.)

    Case 3 might save a few processor cycles, so if you are writing a critical piece of code that will run continuously for years, you might use that method. For all other reasons, case 1 or case 2 is much tidier; that's what I recommend.

    How to remove whitespace from a string

    There are two possible approaches, and either is OK:
    1. Copy the nonblank characters from the string to another string.
    2. Modify the string in place, by copying each character to the left as far as necessary.
    For #1, the general idea would be to do this:
    (a) Start with a source string.
    (b) Set a target string to be empty.
    (c) Go through the characters in the source string one by one.
    (d) For each character, if it's blank (or other "whitespace"), do nothing. If it's nonblank, copy it to the end of the target string, making the target string one character longer.
    (e) When you are done, the target string is the desired result.​
    The target string needs to end up with null character '\0' at the end, since that's how C knows where the end of a string is. You can do this as you go, in step (d), or just once when you are done, as part of step (e).

    For #2, the general idea is to go through the string and copy each character (including the trailing null) to the proper position within the string. For example, if the string mystring[] is set to "Mc in tosh" then you have
    mystring[0] = 'M'
    mystring[1] = 'c'
    mystring[2] = ' '
    mystring[3] = 'i'
    mystring[4] = 'n'
    mystring[5] = ' '
    mystring[6] = 't'
    mystring[7] = 'o'
    mystring[8] = 's'
    mystring[9] = 'h'
    mystring[10] = '\0'​
    and you want your program to use a loop that checks each character and then does these character copying operations:
    mystring[0] -> mystring[0]
    mystring[1] -> mystring[1]
    mystring[3] -> mystring[2]
    mystring[4] -> mystring[3]
    mystring[6] -> mystring[4]
    mystring[7] -> mystring[5]
    mystring[8] -> mystring[6]
    mystring[9] -> mystring[7]
    mystring[10] -> mystring[8]​
    which produces the string "Mcintosh". Notice that certain characters were skipped but the targets are all in sequence. You'll need either pointers or integer counters to keep track of where you are in each string.



    If you have decided which methods you want to use and could use more advice, I'll be glad to offer more specifics. As you can see, I try to explain a program's design choices without showing you the actual code. Annoying, eh? ;)
     
  10. jamesapp thread starter macrumors 6502a

    Joined:
    Mar 7, 2008
    #10
    one thing i will mention.
    how would i get the program to take into account white space.
    like:

    Code:
    abc d  
    
    would be entered,
    and after running the program the output would be:

    Code:
    d cba
    
     
  11. Doctor Q Administrator

    Doctor Q

    Staff Member

    Joined:
    Sep 19, 2002
    Location:
    Los Angeles
    #11
    That should require no extra work. Spaces are characters too, so that's already what should happen as you reverse the string. The program doesn't have to distinguish spaces from nonspaces if you aren't going to handle them differently.
     
  12. jamesapp thread starter macrumors 6502a

    Joined:
    Mar 7, 2008
    #12
    Code:
    james-collinss-macbook-pro:chap2 jamescollins$ ./reverse1.out abc d
    cba
    
    got the following from terminal when i went to run the program which i called reverse1.out i typed abc d as an argument. here is the source fiel:

    Code:
    #include <stdio.h>
    
    main(int argc,char *argv[])
    {
    char mystring[100] ;
    
    if ( argc > 1 )
        {
        strlcpy(mystring,argv[1],sizeof(mystring));
        reverse(mystring) ;
        printf("%s\n",mystring) ;
        }
    }
    
    /* reverse: reverse string s in place , function i want to turn into a program */
    void reverse(char s[])
    {
      int c, i, j;
      
      for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
           c = s[i];
           s[i] = s[j];
           s[j] = c;
      }
    }
    
     
  13. Doctor Q Administrator

    Doctor Q

    Staff Member

    Joined:
    Sep 19, 2002
    Location:
    Los Angeles
    #13
    The problem you are having is an issue with the shell in Terminal, not with your program. Your program expects to receive one argument, which is argv[1]. When you type
    abc d​
    you want the shell to pass the 4-letter string "abc d" to your reverse1.out program, but it's not doing that. Instead, the shell assumes you want to pass two arguments, the first one being the three-letter string "abc" and the second one being the one-letter string "d". So argv[1] is "abc" and argv[2] is "d".

    Luckily, you can solve the problem simply by telling the shell what you really mean. There are three ways to do this, and all of them are just as good. You can put the string in single quotes, put the string in double quotes, or put a \ (called an escape character) in front of the space. So your program should work as follows:
    Code:
    $ reverse1.out abc d
    cba
    
    $ reverse1.out 'abc d'
    d cba
    
    $ reverse1.out "abc d"
    d cba
    
    $ reverse1.out abc\ d
    d cba
    But don't take my word for it. Try them all!
     
  14. jamesapp thread starter macrumors 6502a

    Joined:
    Mar 7, 2008

Share This Page