Can't figure out why I am getting strange output - c

I'm pretty novice. I've been working through the K&R C programming book, and one of the exercises was to write a program that prints any input lines that are longer than 80. Here's my code:
include <stdio.h>
#define MAXLINE 1000
int getaline(char line[], int maxline);
int main()
{
int i, c;
char line[MAXLINE];
if ((c = getaline(line, MAXLINE)) > 80){
for (i =0; i < MAXLINE; ++i)
if (c != '\0')
printf("%c", line[i]);
printf("\n");
}
}
/* reads a line into S, returns the length of that line */
int getaline(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;
}
So I'll pipe a line longer than 80 chars to the compiled program. Here's the output:
cat input.txt | ./a.out
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
??i?F???4?w??>&Y?_???xf?7U?h#?
??i??7U?v??i??7U??7U?(?7U?#?
H??i?8?7U??7U?
It prints the line, but it gives all this anomalous output. I tried to figure out why, but I just can't seem to find why.
However, I am pretty sure that the problem lies in the getaline function.
Any help would be greatly appreciated! :)

You are confusing c with the current character.
Try this, change this
for (i =0; i < MAXLINE; ++i)
with
for (i = 0 ; i < c ; ++i)
and the check should be
if (line[i] != '\0')
instead of
if (c != '\0')
your getaline() function returns, i the position of the last character read, you are comparing it with the null termination byte.
Also if you are null terminating the string, why don't you just
printf("%s\n", line);
this code should work
#include <stdio.h>
#define MAXLINE 1000
int getaline(char line[], int maxline);
int main()
{
int i, c;
char line[MAXLINE];
if ((c = getaline(line, MAXLINE)) > 80)
printf("%s\n", line);
return 0; // you must return from main()
}
/* reads a line into S, returns the length of that line */
int getaline(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;
}

You're checking c as though it were a character, when it's the line-length count; it will never be equal to \0, so you keep pringting.
if ((c = getaline(line, MAXLINE)) > 80){
// c now equals, let's say, 81
for (i =0; i < MAXLINE; ++i)
// c is still 81, we never fail
if (c != '\0')
printf("%c", line[i]);
printf("\n");
}
Consider this instead:
if (getaline(line, MAXLINE) > 80) {
for (i =0; i < MAXLINE; ++i)
{
c = line[i];
if (c != '\0')
printf("%c", c;
else
break;
}
printf("\n");
}

Replace
for (i =0; i < MAXLINE; ++i)
if (c != '\0')
printf("%c", line[i]);
by
for (i =0; i < c; ++i)
printf("%c", line[i]);

Related

Why is this C program printing line longer than MAXLINE?

The program should print all the input lines which length is longer than MINLINE 5 and shorter than MAXLINE 10. Ref. K&R book exercise 1.17
#include <stdio.h>
#define MAXLINE 10
#define MINLINE 5
int getlines(char lines[], int maxline);
int main()
{
int length;
char lines[MAXLINE];
while ((length = getlines(lines, MAXLINE)) > 0)
{
if (length > MINLINE)
printf("%s", lines);
}
return 0;
}
int getlines(char lines[], int maxline)
{
int i, c;
for (i = 0; i < maxline - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
{
lines[i] = c;
}
if (c == '\n')
{
lines[i] = c;
++i;
}
lines[i] = '\0';
return i;
}
Desired outpur should be like this :-
Hello\n
Hello\n
hi\n
excuseMe\n
excuseMe\n
longLineNotToBePrinted\n
done
done
but unexpectedly the program printing lines that are far longer than MAXLINE and sometimes printing those omitting some trailing characters.
For starters this function
int getlines(char lines[], int maxline)
{
int i, c;
for (i = 0; i < maxline - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
{
lines[i] = c;
}
if (c == '\n')
{
lines[i] = c;
++i;
}
lines[i] = '\0';
return i;
}
has undefined behavior because it can store the character '\0' at position maxline that is outside the array lines that has the valid range of indices [0, maxline).
As for your question about the output then if you entered a text that is greater than maxline then the function will return a string that does not contain the new line character '\n'. So the next string will be outputted in the same line.
/* Updated code. Now it is working fine.
Problems were both in main() function and in the function getlines().
#include <stdio.h>
#define MAXLINE 10
#define MINLINE 5
int getlines(char lines[], int maxline);
main()
{
int length;
char lines[MAXLINE];
while ((length = getlines(lines, MAXLINE)) > 0)
{
if (length > MINLINE)
{
/* As the input line can be longer than MAXLINE and in that case there will be no '\n' escape sequence to be stored in the lines[MAXLINE] array so we have used the if block to flow the control in such a way that when the input line is longer than MAXLINE, the output string will be printed manually with a '\n' *newline character. */
if (length > MAXLINE)
printf("%s\n", lines);
else
printf("%s", lines);
}
}
return 0;
}
int getlines(char lines[], int maxline)
{
int i, j, c;
i = 0;
for (j = 0; (c = getchar()) != EOF && c != '\n'; ++j)
{
/* In the for loop this time we didn't use the condition 'j < maxline
-1' as getchar() needs to read the whole input line no matter it's length(can be greater than MAXLINE), rather we have used the 'j < maxline -1' condition as a nested if block inside the for loop. While doing this to keep the getchar() function busy reaching the last input character no matter how long the line is we have used two variable i and j to overcome the problem in such a way that i will be used to store characters in the lines[MAXLINE] array, while j will be increased untill it reaches the end of the line. */
if (j < maxline - 1)
{
i = j;
lines[i] = c;
++i;
}
}
if (c == '\n')
{
if (j < maxline - 1)
{
lines[i] = c;
++i;
++j;
}
else
++j;
}
lines[i] = '\0';
return j;
}

I have encountered segmentation error when attempting to replace the tabs from entered strings with spaces

I have experienced some problem with segmentation when I'm learning through C, my aim is to swap the tabs in the program with spaces:
I have used the get_line template and modified the code to suit the situation. Here is the whole coded solution:
#include <stdio.h>
#define MAXLINE 1000
char line[MAXLINE];
char detabline[MAXLINE];
int get_line(void);
int main(void){
int len;
int i;
int nt = 0;
extern char detabline[];
extern char line[];
while ((len = get_line()) > 0){
for (i = 0; i < len; ++i){
if (line[i] == '\t'){
printf("%s", " ");
}
else{
printf("%s", line[i]);
}
}
}
return 0;
}
int get_line(void){
int c, i, nt;
nt = 0;
extern char line[];
for (i = 0; i < (MAXLINE - 1) && (c = getchar()) != EOF && ((c != '\t') || (c != '\n')); ++i){
line[i] = c;
}
if (c == '\n'){
line[i] = c;
++i;
}
else if (c == '\t'){
++nt;
}
line[i] = '\0';
return i;
}
The problem is to locate which memory isn't allocated correctly. I may have some redundant code in the solution by the way.
regarding:
for (i = 0; i < (MAXLINE - 1) && (c = getchar()) != EOF && ((c != '\t') || (c != '\n')); ++i){
this expression:
(c != '\t')
will result in no tab character ever being in the line[] array.
this expression:
(c != '\n')
will result in no newline character sequence ever being in the line[] array.
then, due those expressions, the line[] array will not be updated (ever again) when a tab or a newline is encountered due to those expressions causing an early exit from the for() loop
The following proposed code:
cleanly compiles
performs the desired functionality
and now, the proposed code:
#include <stdio.h>
#define MAXLINE 1000
char line[MAXLINE];
int main(void)
{
int i = 0;
int ch;
while ( i< MAXLINE-1 && (ch = getchar()) != EOF && ch != '\n' )
{
if ( ch == '\t')
{
line[i] = ' ';
}
else
{
line[i] = (char)ch;
}
i++;
}
printf( "%s\n", line );
}
Post a comment if you want further details about the proposed code.

How to fix segmentation fault: 11 compiler error

I have been learning from the C Programming Language book (K&R) and was writing one of the exercises that removes trailing blanks from an input. I understand that a segmentation fault is at some level a problem having to do with accessing memory that is not accessible, but I have read through this code several times and can't find the error. I would like it very much if someone could help find this error and tell me how to discover errors like this in the future.
#include <stdio.h>
#define MAXLINE 1000
#define CHAR 0 /*character definition*/
#define TRAIL 1 /*determines whether program is in a trailing blank*/
int getinput(char input[], int max);
int trailrem(char input[], char copyto[]);
int len;
int main() {
char line[MAXLINE]; /*current line*/
char newline[MAXLINE];
int i, c, newreturn; /*integer counter, character holder, current line length, and trailrem return value*/
int len;
while((len = getinput(line, MAXLINE)) > 0) {
newreturn = trailrem(line, newline);
for(i = 0; i <= newreturn; ++i)
printf("\n%c\n", newline[i]);
}
}
int getinput(char input[],int max) {
int i, c, line;
for(i = 0; (c = getchar()) != EOF && c != '\n' && c < (max-1); ++i)
input[i] = c;
if(c == '\n') {
input[i] = c;
++i;
}
input[i] = '\0';
return i;
}
int trailrem(char input[], char copy[]) {
int i, j, minusin, state, r;
for(i = len; input[i] != EOF && i >= 0; --i) {
if(input[i] =='\n')
state = TRAIL;
else if((input[i] == ' ' && state == TRAIL) ||( input[i] == '\t' && state == TRAIL))
++minusin;
else if(state == TRAIL && (input[i] != ' ' || input[i] != '\t'))
state = CHAR;
for(j = (r = len-minusin); state == CHAR; --j){
copy[j-2] = input[i];
}
}
copy[r] = '\0';
copy[r-1] = '\n';
return r;
}
So many problems in your code. But the main problem is, you have a global len
int len;
And a local len in the main function.
You are initializing len in main function like this:
while((len = getinput(line, MAXLINE)) > 0)
So the local len is updated. But the global len is still 0.
You are expecting that, you will get the updated value of len in trailrem method but you don't. In trailrem() you will get len equal to 0!
for(i = len; input[i] != EOF && i >= 0; --i)
So i is 0 too. And hence, copy[r-1] = '\n'; will crash, because r-1 can be negative.
Other problems: (BLUEPIXY and WhozCraig mentioned in the comment).
for(i = 0; (c = getchar()) != EOF && c != '\n' && c < (max-1); ++i)
here, c < (max-1) should be i < (max-1).
++minusin; in trailrem function where minusin is uninitialized.

Only print input lines longer than 10 characters (ANSI C)

So I'm writing a practice program in C which has the purpose of taking user input and then after EOF is reached, it reads back the input but only lines that were longer than 10 characters.
I am on Linux, so EOF is Ctrl + D, but, if an input line is longer than 10, it prints when I push enter, rather than waiting until EOF is reached.
here is my code:
#define MAXSIZE 1000
#define SIZE 10
int checklen(char line[], int index);
int main()
{
char currentline[MAXSIZE];
int i = 0;
while ((currentline[i] = getchar()) != EOF){
if (currentline[i] == '\n'){
if (checklen(currentline, i) > SIZE){
printf("%s", currentline);
}
}
++i;
}
return 0;
}
int checklen(char line[], int index)
{
int i;
for (i=index; line[i] != '\n'; ++i){
;
}
return i;
}
EDIT: I have been trying to figure it out for quite a while now with no luck. I'm not really understanding what you guys are saying and everything but we'll get there eventually :)
I have since rewritten the code but it is still not working.
#include <stdio.h>
#define MAX 1000
#define SIZE 10
void examine(char input[], int index);
int main()
{
int i=0;
char input[MAX];
char output[MAX];
//take user input and store it in our input string
while ((input[i] = getchar()) != EOF){
++i;
}
//put a null byte at the end of input[]
input[i+1] = '\0';
//examine line by line until end of string (null byte)
for (i=0; input[i] != '\0'; ++i){
if (input[i] == '\n'){
examine(input, i);
}
}
return 0;
}
void examine(char input[], int index)
{
//decrement through input[] until \n or start [0] is reached
int i=0;
for (i=0; ((input[index] != '\n') || (index > 0)); ++i){
--index;
}
//if line is bigger than 10 chars, print it
if (i>SIZE){
for (; input[index+1] != '\n'; ++index){
putchar(input[index]);
}
}
//otherwise, return
return;
}
rewrote it. was actually really easy. here is the code:
/*this program takes keyboard input from the user until EOF
and prints out their input excluding lines less than or equal to LINESIZE*/
#include <stdio.h>
#define MAX 2000
#define LINESIZE 10
void checkprint(char line[]);
int main()
{
char input[MAX];
char line[MAX];
int i, i2;
i2 = 0;
//take input until EOF (Ctrl + D)
for (i=0; (input[i]=getchar()) != EOF; ++i){
;
}
//add null byte to end of string
input[i+1] = '\0';
//basic formatting for aesthetics
putchar('\n');
//copy a line into line[] from input[] until NULL byte reached
for (i=0; input[i] != '\0'; ++i){
line[i2] = input[i];
++i2;
//if end of line, call checkprint
if (input[i] == '\n'){
checkprint(line);
i2=0;
}
}
return 0;
}
void checkprint(char line[])
{
int i;
//find the length of the line
for (i=0; line[i] != '\n'; ++i){
;
}
//if longer than LINESIZE, print it
if (i > LINESIZE){
putchar('\n');
for (i=0; line[i] != '\n'; ++i){
putchar(line[i]);
}
}
}
#include <stdio.h>
#define MAX 1000
#define SIZE 10
void examine(char input[], int index);
int main(void){
char input[MAX];
// char output[MAX];
int i, ch;
for(i=0; i< MAX - 1 && (ch = getchar()) != EOF; ++i)
input[i] = ch;
input[i] = '\0';
for (i=0; input[i] != '\0'; ++i){
if (input[i] == '\n'){
examine(input, i);
}
}
examine(input, i);//for '\0'
return 0;
}
void examine(char input[], int index){
int i;
if(index == 0) return ;
for (i=1; index - i >= 0 && input[index-i] != '\n'; ++i)
;
--i;
if (i > SIZE){
while(i>0)
putchar(input[index - i--]);
putchar('\n');
}
return;
}
buffer's size 11 version.
#include <stdio.h>
#define SIZE 10
void print(char ch){
static char buf[SIZE+1];
static index = 0, over = 0;
int i;
if(over){
putchar(ch);
if(ch == '\n')
over = 0;
return ;
}
if(ch == '\n'){
index = 0;
} else {
buf[index++] = ch;
if(index == SIZE + 1){
for(i=0;i<index;++i){
putchar(buf[i]);
}
index = 0;
over = 1;
}
}
}
int main(void){
int ch;
while((ch = getchar()) != EOF){
print(ch);
}
return 0;
}
//simple is to use the fgets

Why do I get - 'function' : not all control paths return a value in C

I am trying to learn the basics of C using 'The C Programming Language - Brian Kernighan and Dennis Ritchie'
I've created this basic program to try out functions and storing a string, but for some reason getline keeps keeps returning an error. Im using Visual Express 2010 and I keep getting a ''getline' : not all control paths return a value'
I've picked it over and over but just cant see the problem,
#include<stdio.h>
#define MAXLINE 1000
#define LINEWIDTH 80
int getline(char line[], int maxline);
main(){
int length;
int max;
char line[MAXLINE];
max = 0;
while((length = getline(line, MAXLINE)) >0)
if (length>max){
max=length;
}
if(max>0)
printf("%s",line);
return 0;
}
int getline(char line[], int maxline){
int c, i;
for(i = 0; i<maxline-1 && (c=getchar())!=EOF && c!='\n'; i++){
line[i] = c;
if (c=='\n'){
line[i] = c;
++i;
}
line[i] ='\0';
return i;
}
}
One problem is that you've not copied the code from p29 of K&R Second Edition accurately.
The getline() function there is:
int getline(char s[], int lim)
{
int c, i;
for(i = 0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; i++) // -- No brace! {
s[i] = c;
if (c=='\n') {
s[i] = c;
++i;
}
s[i] ='\0';
return i;
// Brace not needed }
}
I've reinstated the original parameter names (s and lim) in place of your line and maxline.
There's a specialized version of getline() on p32 with no arguments. There's a slightly compressed version of the code above on p69. There's another implementation on p165 in terms of fgets().
Because your function is not returning anything when it doesn't enter the for loop.
Update it as :
int getline(char line[], int maxline){
int c, i;
for(i = 0; i<maxline-1 && (c=getchar())!=EOF && c!='\n'; i++){
line[i] = c;
if (c=='\n'){
line[i] = c;
++i;
}
line[i] ='\0';
return i;
}
return 0; #return some appropriate value when doesn't enter in for loop.
}
int getline(char line[], int maxline)
{
int i = 0, c;
for(; i < maxline-1 && (c=getchar())!=EOF && c!='\n'; i++)
line[i] = c;
if (c == '\n')
s[i++] = c;
line[i] = '\0';
return i;
}
This should be enough. The code had unneeded brace due to which it would have returned the value in the first iteration, if it had executed.

Resources