getting output from a c program - c

I compiled the below program:
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */
int getline(char line[], int maxline);
void copy(char to[], char from[]);
/* print the longest input line */
main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s", longest);
return 0;
}
/* getline: read a line into s, return length */
int getline(char s[],int lim)
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
I tried to run it in bash shell:
gcc -o longest-line longest-line.c
./longest-line
And basically it turns into a running process (shows in result of ps aux) and the cursor just blinks. In the code, when the program is run and the getline function is called, it does 1000 iterations and the getchar is called each time to get input from the terminal in order to increment the counter if it's not end of file or newline. However, immediately there is no input in the terminal and when I start adding input and press the enter key:
$ ./longest-line
Hello World
Hello Again
Nothing happens. It's supposed to print the longest line.

The problem is that if you press '\n' from keyboard getline will always return 1 because of this statement
if (c == '\n') {
s[i] = c;
++i;
}
and the line while ((len = getline(line, MAXLINE)) > 0) will always be true.
But if you use a file as standard input it will work fine because of the EOF.
If you want it to work from keyboard input press Ctrl-D or Ctrl-Z to simulate an EOF.

So, on my compiler, I had to fix a few minor issues.
Generally, main should be written as int main() { ... } or int main(int argc, char **argv) { ... }.
getline() conflicts with a builtin function that gets pulled in from the #include <stdio.h>, so I simply renamed yours to getline_custom and also renamed all the usage points.
That being said, with these minor fixes, (which may not be required under your compiler), your program works correctly.
I believe your confusion is that the program won't print the longest line until after you've sent EOF. In bash, you can do this with CTRL+D.
Example:
[12:39pm][wlynch#watermelon /tmp] ./foo
test // Then I hit enter
longest line // Then I hit enter
short line // Then I hit enter
one more // Then I hit ctrl-D
longest line // This is output from the program.
Another Example:
If we use redirection, we can more easily see the difference between the input and output.
[12:42pm][wlynch#watermelon /tmp] printf "longest line\nshort line" | ./foo
longest line
or, using an input file:
[12:53pm][wlynch#watermelon /tmp] cat input.txt
longest line
short line
foo
blah
[12:53pm][wlynch#watermelon /tmp] cat input.txt | ./foo
longest line
On the other hand
If, on the other hand, you'd like the program to print the current longest line after each line of input, then we would need to change the code in this program.
Here's an example of that:
int main() {
int len = 0; /* current line length */
int max = 0; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
while ((len = getline(line, MAXLINE)) > 0) {
if (len > max) {
max = len;
copy(longest, line);
}
printf("Current longest line: %s", longest);
}
}

Related

K&R, find longest line, same code but not working?

I've just started to read K&R and on pages 32-33, there is a code that
finds the longest line among the inputs.
I nearly completely copy-pasted the code given in the book, just added some comment lines to make the code more understandable for me. But it isn't working.
Edit: I'm sorry for bad questioning. It seems the program does not act properly when I press Ctrl + Z, in order to terminate it. No matter how many lines I type and how many times I press Ctrl + Z, it just does nothing.
The following is my version of the code:
/* Find the longest line among the giving inputs and print it */
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */
int getLine(char line[], int maxLine);
void copy(char to[], char from[]);
int main(void) {
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here*/
max = 0;
/* getLine function takes all the input from user, returns it's size and equates it to the variable len
* Then, len is compared whether it's greater than zero because if there's no input, no need to do any calculation
* EDGE CASE
*/
while ((len = getLine(line, MAXLINE)) > 0)
/* If the length of input is larger than the previous max length, set max as the new length value and copy that input */
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line, EDGE CASE */
printf("%s", longest);
return 0;
}
/* Read a line into s, return length.
* Since the input length is unknown, there should be a limit */
int getLine(char s[], int lim) {
int c, i;
/* The loop's first condition is whether the input length is below the limit. EDGE CASE
* If it's not, omit the rest because it would cause a BUFFER OVERFLOW. Next, take the input as long as it's not an EOF command.
* Finally, if the input is end of line, finish the loop, don' take it.
*/
for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; i++)
s[i] = c;
if (c == '\n')
s[i++] = c;
s[i++] = '\0'; // always put a '\0' character to a string array ending, so that the compiler knows it's a string.
return i;
}
void copy(char to[], char from[]) {
int i = 0;
// This loop is readily assigns all chars from the source array to the target array until it reaches the ending char.
while ((to[i] = from[i]) != '\0')
++i;
}
Thanks in advance!
Okay, here's the error:
s[i++] = '\0'; // always put a '\0' character to a string array ending, so that the compiler knows it's a string.
This will cause it to terminate the string even for no input (when it got EOF directly), and since it increments i before returning it, getLine() will never return 0 and thus main() will never stop. Removing the ++ fixed it, for my simple test.
Also, the comment is misleading, the compiler doesn't know anything. The compiler is no longer around when the code runs; the in-memory format of strings is something that's needed to keep the run-time libraries happy since that's what they expect.

Terminating a c program when the user enters a blank line

Hi i am writing a program to count the number of lines the user enters, i have this code:
#include <stdio.h>
#include <string.h>
int readline(char line[], int max);
/* count lines in input */
main() {
int c, nl,max, i;
max = 99;
char line[100];
nl = 0;
while (( readline(line, max) != 0)){
++nl;
}
printf("%d\n", nl);
}
/* readline: read a line from standard input, return its length or 0
*/
int readline(char line[], int max)
{
if (fgets(line, max, stdin) == NULL)
return 0;
else
return strlen(line);
}
but i am not sure how to terminate the program and have "nl" printed to the screen, i am using the cygwin64 terminal to write and execute the program.
Thanks
size_t n;
while(fgets(line,max,stdin))
{
n = strlen(line);
if( n == 1 && line[n-1] == '\n')
{
//This is a empty line
}
}
Basically fgets() comes with a newline character and you can use this to confirm whether there was any input in the line or just a newline character was entered.
readline returns the text of the line read. A blank line returns
the
empty string. If EOF is encountered while reading a line, and the line
is empty, NULL is returned. If an EOF is read with a non-empty line,
it is treated as a newline.
So you can check for empty string.
Change the condition into like this,
while (( readline(line, max) <= 1)){
...
}
When you enter the empty new line then that new line will be placed in that array.
So it gives the strlen as 1.

Programmes won't run on Ubuntu 12.04 and Windows XP

Having installed Eclipse and CB, I encountered several projects that do not start properly. I assumed that it was because of the OS I used, that is why I switched to Ubuntu. However, some programmes I had tried to run still would not work correctly. For instance, this code from clc-wiki outputs nothing upon pushing Enter:
#include <stdio.h>
#define MAXLINE 40 /* maximum input line size */
int getlines(char line[], int maxline);
void copy(char to[], char from[]);
/* print longest input line */
int main()
{
int c;
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
max = 0;
while ((len = getlines(line, MAXLINE)) > 0) {
if (line[len-1] != '\n')
while ((c = getchar()) != EOF && c != '\n')
++len;
if (len > max) {
max = len;
copy(longest, line);
}
}
if (max > 0) { /* there was a line */
printf("Longest line with %d characters:\n", max);
printf("%s ...\n", longest);
}
return 0;
}
/* getline: read a line s, return length */
int getlines(char s[], int lim)
{
int c, i;
for (i = 0; i < lim-1 && (c = getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
The similar problem is faced, if we run it in XP. Nevertheless, everything is perfect, if we compile the very same code in ideone.
gcc and g++ are installed, as well as mingw for Windows.
Could you please tell me what the problem can be all about?
this code outputs nothing upon pushing Enter
That is the correct behavior of your code. It is designed to print nothing upon pushing Enter.
That code, in particular, requires an end-of-file indication. If your program reads from a file (as is the case on ideone), the end-of-file indication happens more-or-less automatically. If your program reads from the computer keyboard (as when you run it interactively), then you must provide an end-of-file indication.
To exercise the code you provided:
On Linux, from the keyboard, enter several lines of varying lengths, each followed by Enter. Then enter CONTROL-D on a line by itself.
On Windows, from the keyboard, enter several lines of varying lengths, each followed by Enter. Then enter enter CONTROL-Z on a line by itself.

What condition is causing this program to leave the for loop early due to a EOF character?

Go ahead and look to the bottom of this post for the actual question
I may be trying to understand the really simple things a bit too much, but I just cannot continue until I figure this out.
While reading K&R 1.9 Character Arrays, you come across an example program which takes input and determines which line was the longest, then it reprints it.
In order to understand the getline function of this program, I have modified it slightly to print some information during its progression. Now I have found some input which, once I understand, should greatly enhance my understanding of getchar().
On a side note, when I try to read source code from the libraries I get completely overwhelmed. For example I tried hunting down getchar() and ended up staring dumbfounded at a tower of 18 #endif somewhere on line 300ish of stddef.h. I am going to save that headache by discontinuing the pursuit of functions in stdio.h for the near future. Is it normal that the libraries are extremely hard to find something? Shouldn't the function exist as readable source, or do I just have my hopes up?
I will just go ahead and post the entire modified program from K&R for convenience sake:
#include <stdio.h>
#define MAXLINE 5 /* maximum input line length */
int getline(char line[], int maxline);
void copy(char to[], char from[]);
/* print the longest input line */
main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s\n", longest);
printf("INFO: max = %d\n", max);
printf("INFO: sizeof s[] = %d", sizeof longest);
return 0;
}
/* getline: read a line into s, return length */
int getline(char s[],int lim)
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i){
s[i] = c;
printf("INFO: s[%d] = %c\n", i, c);
if (c == '\n') {
printf("INFO: %d\n", i);
printf("INFO: s[%d] = \\n\n", i);
s[i] = c;
++i;}
}
s[i] = '\0';
return i;
}
/* copy: copy ’from’ into ’to’; assume to is big enough */
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
Here is some example input/output: I am using CodeBlocks and Windows 7
Finally, my question is why does the for loop in the getline() function leave the loop after it gets to F and therefore places the null terminator after F as \0
My hypothesis is that perhaps putting the EOF character shown as ^Z in the windows terminal, the array is truncated to a length of 4 characters plus a null terminator. It turns out if I put the EOF character inside a line to be read, the saved line s[] will only contain a maximum size of 5. What also confuses me is that the variable len will always be 0, is that because len is assigned during the while loop in main(), and does not have its value saved once that while loop is broken?
Something interesting to me, but probably not to experienced C users, is that the if statement right after the for loop in getline() can either be inside the for loop, or outside and it does not change the program. Interesting, because won't that mean that whether or not the for loop executes any code in the body, at the very least (c=getchar()) is executed?
Sorry the question is so wordy, I appreciate any helpful comments/answers.
Because MAXLINE is 5, and the getline function never reads more than MAXLINE - 1 characters.

small C program doesnt work

I tried to make a program that gets a user input(lines) and prints the longest line that is over 80 characters long. I made the program , but when i ran it , it outputed some very weird symbols. Could you please tell me what might be wrong with my code ?
#include <stdio.h>
#define MINLINE 80
#define MAXLINE 1000
int getline(char current[]);
void copy(char from[], char to[]);
int main(void)
{
int len; // current input line lenght
int max; // the lenght of a longest line that's over 80 characters
char current[MAXLINE]; // current input line
char over80[MAXLINE]; // input line that's over 80 characters long
while (len = (getline(current)) > 0) {
if (len > MINLINE) {
max = len;
copy(current, over80);
}
}
if (max > 0) {
printf("%s", over80);
}
else {
printf("No input line was over 80 characters long");
}
return 0;
}
int getline(char current[]) {
int i = 0, c;
while (((c = getchar()) != EOF) && c != '\n') {
current[i] = c;
++i;
}
if (i == '\n') {
current[i] = c;
++i;
}
current[i] = '\0';
return i;
}
void copy(char from[], char to[]) {
int i = 0;
while ((to[i] = from[i]) != '\0') {
++i;
}
}
Thank you very much for your help !
max can be not initialized if no long line is found. Using it in if (max > 0) is then undefined behavior.
This line:
while (len = (getline(current)) > 0) {
assigns the value of (getline(current)) > 0) to len, which is not what you want (len will be 0 or 1 afterwards.
EDIT: Just saw AusCBloke's comment, you should also check for both len > max and len > MINLINE or you'll just get the latest line longer than 80 chars, not the longest overall line.
You should also initialize max to 0, so it should be
max = 0;
while ((len = getline(current)) > 0) {
if ((len > MINLINE) && (len > max)) {
Other minor errors/tips:
The built in functions strcpy and strncpy do what your copy function does, there's no need to reinvent the wheel.
In your getline function, use MAXLINE to prevent buffer overflows.
Assuming that this is a homework, here's a hint: this piece of code looks very suspicious:
if (i == '\n') {
current[i] = c;
++i;
}
Since i represents a position and is never assigned a character, you are effectively checking if the position is equal to the ASCII code of '\n'.
Your copy method doesn't null terminate the string:
void copy(char from[], char to[]) {
int i = 0;
while ((to[i] = from[i]) != '\0') {
++i;
}
to[i] = '\0'
}
which probably explains the weird characters being printed.
You could use the builtin strcpy() to make life easier.
I can't test your code right now, but it may be caused by character arrays not being cleaned. Try memset-ing the char arrays to 0.
If you supply input data that has lines with more than 1000 characters you will overflow your fixed size buffers. By feeding in such input I was able to achieve the following output:
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
There are a number of problems with your code. Mostly they are due to wheel-reinvention.
int getline(char current[]);
You don't need to define your own, getline(), there is already one in stdio.h.
void copy(char from[], char to[]);
There are also a number of functions for copying strings in string.h.
It's also a good idea to initialise all 0f your variables, like this:
int len = 0; // current input line length
...this can prevent problems later, like comparisons to max when you haven't initialised it.
If you initialise max like this...
int max = MINLINE; // the length of a longest line that's over 80 characters
...then it's easier to do the length comparison later on.
char* current = NULL;
size_t allocated = 0;
If current is NULL, then getline() will allocate a buffer for storing the line, which should be freed by the user program. getline() also takes a pointer to a size_t, which contains the amount of bytes needed to store the line.
while (len = (getline(current)) > 0) {
Should be replaced by the following...
while ((len = getline(&current, &allocated, stdin)) > 0) {
...which updates and compares len to 0.
Now, instead of...
if (len > MINLINE) {
...you need to compare with the last longest line, which we initialised earlier...
if (len > max) {
...and then you're good to update max as you were...
max = len;
Where you called your copy() use strncpy(), which will prevent you writing over 1,000 characters into the allocated buffer:
strncpy(over80, current, MAXLINE);
Because we initialised max, you'll need to change your check at the end from if (max > 0) to if (max > MINLINE).
One more tip, changing the following line...
printf("No input line was over 80 characters long");
...to...
printf("No input line was over %d characters long", MINLINE);
...will mean that you only have to change the #define at the top of the file to increase or decrease the minimum length.
Don't forget to...
free(current);
...to prevent memory leaks!

Resources