Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

jamesapp

macrumors 6502a
Original poster
Mar 7, 2008
544
0
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.
 

Doctor Q

Administrator
Staff member
Sep 19, 2002
40,095
8,366
Los Angeles
is there a way to have the computer wait for EOF before printing the lines that contain the string "ould"?
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.
 

Doctor Q

Administrator
Staff member
Sep 19, 2002
40,095
8,366
Los Angeles
can someone help me turn a function into a program?
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().
 

jamesapp

macrumors 6502a
Original poster
Mar 7, 2008
544
0
what about blank spaces, the book calls them white spaces i think. could i modify the code to take into account blank spaces?
 

Sander

macrumors 6502a
Apr 24, 2008
521
67
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[]) { /* ... */ }
 

Doctor Q

Administrator
Staff member
Sep 19, 2002
40,095
8,366
Los Angeles
what about blank spaces, the book calls them white spaces i think. could i modify the code to take into account blank spaces?
"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.
 

Doctor Q

Administrator
Staff member
Sep 19, 2002
40,095
8,366
Los Angeles
i was thinking of spaces in the reverse program.
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? ;)
 

jamesapp

macrumors 6502a
Original poster
Mar 7, 2008
544
0
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
 

Doctor Q

Administrator
Staff member
Sep 19, 2002
40,095
8,366
Los Angeles
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.
 

jamesapp

macrumors 6502a
Original poster
Mar 7, 2008
544
0
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;
  }
}
 

Doctor Q

Administrator
Staff member
Sep 19, 2002
40,095
8,366
Los Angeles
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!
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.