I am going through K&R (2 ed.) to learn C as I've been trying to get a basis in lower-level languages to help my programming and also because I want to know C. The book is absolutely fantastic; however, a program they provided on pp. 29 (Sec 1.9 Character Arrays) does not compile. This is the code
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line size */
int getline(char line[], int maxline);
void copy(char to[], char from[]);
/* print 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 int 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;
}
When I run cc longest_line.c (that's what I called it) I get an error that getline has conflicting definitions as it was already defined in stdio.h. My question is, how do I resolve this/can I resolve this without giving getline a different name?
As #Olaf commented, getline() is standard POSIX,
K&R second edition is ansi 89 standard.
Just compile in ansi mode, to prevent the collision with POSIX libraries:
gcc -ansi source.c
Edit:
GodBot Link
This approach avoids your problem by not including the problematic header. Rather, it copies all the declarations needed in your implementation locally.
This is a very bad idea because the declarations of these functions may change without your knowledge in which case your code will pass or receive bad inputs
#define MAXLINE 1000 /* maximum input line size */
int getline(char line[], int maxline);
void copy(char to[], char from[]);
int printf(const char *format, ...);
int getchar(void);
/* print longest input line */
int 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 int s, return length */
int getline(char s[], int lim)
{
int c, i;
for (i = 0; i<lim-1 && (c=getchar())!=-1 && 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;
}
~
Related
I am getting these errors despite declaring the "getline" and "copy" function prototypes before main(). This program comes straight from the code in The C Programming Language so I'm unsure what the issue is and how to fix it.
#include <stdio.h>
int getline(char line[], int maxline);
void copy(char to[], char from[]);
int main()
{
}
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;
}
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
The exact errors produced by the compiler are:
string_reverser.c:4:5: error: conflicting types for 'getline'
int getline(char line[], int maxline);
^~~~~~~
In file included from string_reverser.c:1:0:
c:\mingw\include\stdio.h:650:1: note: previous declaration of 'getline' was here
getline (char ** __restrict__, size_t * __restrict__, FILE * __restrict__);
^~~~~~~
string_reverser.c:27:5: error: conflicting types for 'getline'
int getline(char s[], int lim)
^~~~~~~
In file included from string_reverser.c:1:0:
c:\mingw\include\stdio.h:650:1: note: previous declaration of 'getline' was here
getline (char ** __restrict__, size_t * __restrict__, FILE * __restrict__);
^~~~~~~
The POSIX function getline() is now a standard library function which is (already) declared in <stdio.h> (but wasn't standard when K&R was written).
Hence, you cannot re-declare the function a little differently in C language.
A workaround is to rename your getline function to something else, e.g. getline_new
The updated code is as below with this workaround, or you may want to switch to C++ that gives flexibility to have many functions with same name, but different arguments, including argument type (polymorphism concept)
#include <stdio.h>
int getline_new(char line[], int maxline);
void copy(char to[], char from[]);
int main()
{
}
int getline_new(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;
}
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
In the last line of copy function I have stored a '\0' at the end of the copied string, this was not originally in the code.
include <stdio.h>
#define MAXLINE 1000 /* maximum input line size */
int getline(char line[ ], int maxline);
void copy(char to[ ], char from[ ]);
/* print longest input line*/
int 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;
to[i] = '\0'; /*<-----Problematic Area*/
}
My question here is, whether the copied string already contains a '\0' at the end. If it is not so then is it a good practice to include it as I have done in the code.
The statement
while ((to[i] = from[i]) != '\0')
++i;
first assigns the value of from[i] to to[i] and then compares the assigned value to \0 - if it was the null terminator that was just copied, the loop ends.
Thus
to[i] = '\0';
is unnecessary, but not otherwise incorrect here.
However, having unnecessary code around is not good style because it makes refactoring and reasoning about the other code harder. Just the presence of that last assignment could then confuse a future reader into thinking that the loop in itself is not sufficient to properly terminate the string.
Additionally, should someone come and edit the code into
while ((*to++ = *from++));
as suggested by WhozCraig, they could then mistakenly think that they do need to add the null terminator, this time potentially writing out of bounds:
*to++ = 0;
I am fairly new to C, and I am working through Ritchie's and Kernighan's The C programming language, and I don't understand how the following code works:
#include <stdio.h>
#define MAXLINE 1000
int getline(char line[], int maxline);
void copy(char to[], char from[]);
int main()
{
int len;
int max;
char line[MAXLINE];
char longest[MAXLINE];
max = 0;
while((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0)
printf("%s", longest);
return(0);
}
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;
}
s[i] = '\0';
return(i);
}
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
What I don't get is how does the copy function affect anything without returning anything, I am used to Python where functions can only affect outwith themselves through return values, and I was under the impression C was the same.
I have tested the code and it does work.
The statement while ((to[i] = from[i]) != '\0') is actually an assignment disguised within the comparison.
It's a shorthand code that I personally find confusing, and you're proving that it infact is.
That copy function works through the magic of pointers.
In essence, pointers are basically a memory address that you can access like an array from the same program.
On a side note, Learn C the Hard way is, in my opinion, a better book.
He explains many concepts of C, and he also points out some flaws in that very same copy function you are asking about.
UPDATE
He actually removed his section on K&R C, because he believes that C is dead.
I think he is wrong, but, to each his own.
void copy(char to[], char from[]) is actually the same like void copy(char *to, char *from). So, two pointers are passed to the copy function. The function can change the destinations of the pointers. This mechanism is known as "call by reference".
(The copy function only needs to change the destination of the to-pointer, the destination of the from-pointer needs not to be changed. This can be made clearer with void copy(char *to, const char *from).)
New to programming, working through K&R. After inputting using the stdin, I press ^D to write EOF (i'm using linux), and... nothing happens. I'm still able to write to the console, and able to ^Z to suspend, but not able to use ^D. I expected my code to read the input and print all the lines longer than the requirement, and as I can't produce any output, I'm not sure where to begin diagnosing my problem.
/*
Exercise 1-17 in K&R: page 31 in book
Write a program to print all input lines that are longer than 80 characters
*/
# include <stdio.h>
# define MIN_LINE 5 /*change to 80 for final*/
# define MAX_LINE 20 /*change for final*/
int getline(char line[], int max);
void copy(char to[], char from[], int position);
int main()
{
char line[MAX_LINE];
int len = 0;
char print_register[MAX_LINE];
int reg_index = 0;
/*read length of line*/
while ((len = getline(line, MAX_LINE)) != EOF)
{
/*if len > 80; append to print-array*/
if (len > MIN_LINE)
{
copy(print_register, line, reg_index);
}
}
/*print the print-array*/
printf("%s", print_register);
return 0;
}
int getline( char line[], int max)
{
int i;
int c;
for (i = 0; (c = getchar()) != EOF && c != '\n' && i <= max; i++)
{
line[i] = c;
}
/* handle '\n' and EOF */
if (c == '\n')
{
line[i] = c;
i++;
}
line[i] = '\0';
return i;
}
void copy(char to[], char from[], int position)
{
int i;
while ((to[position] = from[i]) != '\0')
{
i++;
position++;
}
}
Your getline() function returns the length and not EOF. Hence the following statement should be replaced:
while ((len = getline(line, MAX_LINE)) != EOF)
The EOF should be replaced with 0:
while ((len = getline(line, MAX_LINE)) != 0)
you need to initialize the "i" value in copy function, if not it may take some unexpected value and getline() output is returning number of characters not EOF so you need to change while loop condition also.
Changes:
Original : while ((len = getline(line, MAX_LINE)) != EOF)
changed : while ((len = getline(line, MAX_LINE)) != 0)
void copy(char to[], char from[], int position)
{
// int i; Original
int i =0;
while ((to[position] = from[i]) != '\0')
{
i++;
position++;
}
}
if you initialize i=0 in copy function, you will get output.
So I'm trying to determine the longest line for a school assignment. Here is the code I think is of question. I don't understand why the "longest_line" prints fine in the while loop, but won't print outside the loop.
int main() {
int ch;
char line[MAXLINE] = { '\n' }; /* current input line */
char longest_line[MAXLINE] = { '\n' }; /* copy of longest line */
while ((ch = readline(line, MAXLINE)) != EOF) {
if (longest(line, longest_line))
copy(longest_line, line);
printf("Read Line: %s\n", line);
printf("Long Line: %s\n", longest_line);
}
printf("Print Long Line: %s\n", longest_line);
Here is the output:
calc L
copy
Read Line: sdafasdfsadfsadfs
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sadfs
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sdfasdfsafd
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sadfsdf
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sadfs
Long Line: sdafasdfsadfsadfs
calc L
Read Line:
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sfsafsdfsf
Long Line: sdafasdfsadfsadfs
Print Long Line:
It's like the longest_line gets erased after the loop, which doesn't make sense to me. Sorry I'm a newb. Thanks to the guy who knows the technical reason behind this anomaly.
Here is my entire program if you wish to run it: (I fixed the variables)
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#define MAXLINE 80 /* maximum input line size */
/* function declarations */
int readline( char line[], int max );
void copy( char to[], char from[] );
bool longest( char read_line[], char previous_line[] );
/* print longest input line */
int main() {
int ch;
char line[MAXLINE] = { '\n' }; /* current input line */
char longest_line[MAXLINE] = { '\n' }; /* copy of longest line */
while ((ch = readline(line, MAXLINE)) != EOF) {
if (longest(line, longest_line))
copy(longest_line, line);
printf("Read Line: %s\n", line);
printf("Long Line: %s\n", longest_line);
}
printf("Print Long Line: %s\n", longest_line);
return 0;
}
/* readline: read a line into s, return length */
int readline(char s[], int lim) {
int i = 0; // the current index
char c; // the current char
c = getchar();
while (c != '\n' && i < lim) {
s[i] = c;
i++;
c = getchar();
}
s[i] = '\0'; // final charachter of string
return c;
}
/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[]) {
int i;
for (i = 0; to[i] = from[i]; ++i);
printf("copy\n");
}
/* longest: Which line is the longest */
bool longest( char read_line[], char previous_line[] ) {
printf("calc L\n");
char ch;
int size_read = 0;
int size_previous = 0;
// determine length of read line
ch = read_line[size_read];
while (ch != '\0') {
ch = read_line[size_read];
++size_read;
}
// determine length of previous line
ch = previous_line[size_previous];
while (ch != '\0') {
ch = previous_line[size_previous];
++size_previous;
}
// determine longest line
if (size_read > size_previous)
return true;
else
return false;
}
I won't give the details away, but there are several places in the code where you fail to initialize variables, leading to undefined behaviour.