C programming language excercise1-18 - c

Hi guys i am reading The C programming language by Kernighan and Ritchie and trying to solve along the questions. This program is supposed to eliminate all the blanks and tabs from the end of the input lines but its not working.
I have added comments to the section of code i am having problems with
#include <stdio.h>
#define MAXLINE 1000
int getline(char line[], int max);
void copy(char to[], char frm[]);
int main(void) {
int maxLen=0;
int currLen;
char line[MAXLINE];
char longestLine[MAXLINE];
while((currLen=getline(line,MAXLINE)) > 0){
if(currLen > maxLen){
maxLen = currLen;
copy(longestLine, line);
}
}
if(maxLen>0){
printf("%d\n", maxLen);
printf("%s", longestLine);
}
return 0;
}
int getline(char line[], int max){
int c,i;
for(i=0;i<max-1 && (c=getchar())!=EOF && c!='\n';i++){
line[i] = c;
}
if(c == '\n'){
/* This is the logic i added to take care of the trailing
spaces and tabs. Rest of the program is same as the book
Its still counting spaces at the end of line when variable maxLen is
printed in the main function, would like to know if the logic is
erronous*/
while(line[i] == ' ' || line[i] == '\t'){
i--;
}
line[i]=c;
++i;
}
line[i] = '\0';
return i;
}
void copy(char to[], char from[]){
int i=0;
while((to[i]=from[i])!='\0'){
++i;
}
}

As far as i can tell, your program is returning the longest line entered, and does not eliminate blanks or tabs.
you are welcome to see the solution the link below:
solution to 1-18
I hope this helped
good luck

First, let's take a look at your output:
if(maxLen>0){
printf("%d\n", maxLen);
printf("%s", longestLine);
}
This part isn't in any loop and does not contain any loop, so it prints just one line. However, the program should print all the lines. Therefore, your code that prints lines should be in a loop similar to the code that gets a line. They could be in the same loop, like this:
while there is text left
get line
removing the spaces
print line
end loop
Or in different loops. Actually, I think you misunderstood the exercise, because it's printing the longest one, and that cleary seems to be your intention going by your code.
Deleting the whitespace
It seems that this is where you're trying to delete the whitespace:
while(line[i] == ' ' || line[i] == '\t'){
i--;
}
Note that the i you're using here is not the i from this line:
for(i=0;i<max-1 && (c=getchar())!=EOF && c!='\n';i++){
Instead, it's the i from this line:
int c,i;
This is because in for(i=0; ... you're defining another i so that one is in scope for the loop. The first i isn't touched in that loop and is still uninitialized when you try to delete the whitespace. So line[i] is undefined behavior and will most likely just crash your program. And even if it doesn't, it will just read a rubbish value, see if it coincidentally translates to ' ' or '\t' and then either not do anything, or decrease i and try again.
My suggestion to you is that you should try to solve the exercise incrementally. The task can be split in multiple parts:
Removing trailing whitespace from a line
Reading in the input
Do one after another. First, you write a program that takes one hardcoded line and removes the trailing whitespace and prints it. Then, when that works, you modify it to work with not one line, but with all the input lines. This way you don't have multiple parts that aren't working, but instead you can focus on doing one part at a time. It's easier to write software this way.

Thanks for your help guys. Problem was with the value of i in function getLine. Here is the solution:
int getline(char line[], int max){
int c,i;
for(i=0;i<max-1 && (c=getchar())!=EOF && c!='\n';i++){
line[i] = c;
}
i--; /* This line is the fix, value of i is incremented before termination of the
loop, so decrement it to point to the last character in the array */
while(line[i] == ' ' || line[i] == '\b'){
i--;
}
if(c == '\n'){
line[i]=c;
++i;
}
line[i] = '\0';
return i;
}

Related

Kernighan and Ritchie C exercise 1-16

I tried to implement a solution for the exercise on the C language of K&R's book. I wanted to ask here if this could be considered a legal "solution", just modifying the main without changing things inside external functions.
Revise the main routine of the longest-line program so it will
correctly print the length of arbitrary long input lines, and as much
as possible of the text.
#include <stdio.h>
#define MAXLINE 2 ////
int get_line1(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;
}
int main()
{
int len;
int max = MAXLINE;
char line[MAXLINE];
int tot = 0;
int text_l = 0;
while ((len = get_line1(line, max)) > 0) {
if (line[len - 1] != '\n') {
tot = tot + len;
}
if (line[1] == '\n' || line[0] == '\n') {
printf("%d\n", tot + 1);
text_l = text_l + (tot + 1);
tot = 0;
}
}
printf("%d\n", text_l);
}
The idea is to set the max lenght of the string considered for the array line ad 2.
For a string as abcdef\n , the array line will be ab. Since the last element of the array is not \n (thus the line we are considering is not over), we save the length up until now and repeat the cycle. We will get then the array made of cd, then ef and at the end we will get the array of just \n. Then the else if condition is executed, since the first element of this array is\n, and we print the tot length obtained from the previous additions. We add +1 in order to also consider the new character \n. This works also for odd strings: with abcdefg\n the process will go on up until we reach g\n and the sum is done correctly.
Outside the loop then we print the total amount of text.
Is this a correct way to do the exercise?
The exercise says to “Revise the main routine,” but you altered the definition of MAXLINE, which is outside of main, so that is not a valid solution.
Also, your code does not have the copy or getline routines of the original. Your get_line1 appears to be identical except for the name. However, a correction solution would use identical source code except for the code inside main.
Additionally, the exercise says to print “as much as possible of the text.” That is unclearly stated, but I expect it means to keep a buffer of MAXLINE characters (with MAXLINE at its original value of 1000) and use it to print the first MAXLINE−1 characters of the longest line.

C Program won't remove comments that take up the whole line

So I'm working through the K&R C book and there was a bug in my code that I simply cannot figure out.
The program is supposed to remove all the comments from a C program. Obviously I'm just using stdin
#include <stdio.h>
int getaline (char s[], int lim);
#define MAXLINE 1000 //maximum number of characters to put into string[]
#define OUTOFCOMMENT 0
#define INASINGLECOMMENT 1
#define INMULTICOMMENT 2
int main(void)
{
int i;
int isInComment;
char string[MAXLINE];
getaline(string, MAXLINE);
for (i = 0; string[i] != EOF; ++i) {
//finds whether loop is in a comment or not
if (string[i] == '/') {
if (string[i+1] == '/')
isInComment = INASINGLECOMMENT;
if (string[i+1] == '*')
isInComment = INMULTICOMMENT;
}
//fixes the problem of print messing up after the comment
if (isInComment == INASINGLECOMMENT && string[i] == '\0')
printf("\n");
//if the line is done, restates all the variables
if (string[i] == '\0') {
getaline(string, MAXLINE);
i = 0;
if (isInComment != INMULTICOMMENT)
isInComment = OUTOFCOMMENT;
}
//prints current character in loop
if(isInComment == OUTOFCOMMENT && string[i] != EOF)
printf("%c", string[i]);
//checks to see of multiline comment is over
if(string[i] == '*' && string[i+1] == '/' ) {
++i;
isInComment = OUTOFCOMMENT;
}
}
return 0;
}
So this works great except for one problem. Whenever a line starts with a comment, it prints that comment.
So for instance, if I had a line that was simply
//this is a comment
without anything before the comment begins, it will print that comment even though it's not supposed to.
I thought I was making good progress, but this bug has really been holding me up. I hope this isn't some super easy thing I've missed.
EDIT: Forget the getaline function
//puts line into s[], returns length of that line
int getaline(char s[], int lim)
{
int c, i;
for (i = 0; i < lim-1 && (c = getchar()) != '\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
There are many problems in your code:
isInComment is not initialized in function main.
as pointed by others, string[i] != EOF is wrong. You need to test for end of file more precisely, especially for files that do not end with a linefeed. This test only works if char type is signed and EOF is a valid signed char value. It will nonetheless mistakenly stop on a stray \377 character, which is legal in a string or in a comment.
When you detect the end of line, you read another line and reset i to 0, but i will be incremented by the for loop before you test again for single line comment... hence the bug!
You do not handle special cases such as /* // */ or // /*
You do not handle strings. This is not a comment: "/*", nor this: '//'
You do not handle \ at end of line (escaped linefeed). This can be used to extend single line comments, strings, etc. There are more subtle cases related to \ handling and if you really want completeness, you should handle trigraphs too.
Your implementation has a limit for line size, this is not needed.
The problem you are assigned is a bit tricky. Instead of reading and parsing lines, read one character at a time and implement a state machine to parse escaped linefeeds, strings, and both comment styles. The code is not too difficult if you do it right with this method.
if (string[i] == '\0') {
getaline(string, MAXLINE);
i = 0;
if (isInComment != INMULTICOMMENT)
isInComment = OUTOFCOMMENT;
}
When you start a new line, you initialize i to 0. But then in the next iteration:
for (i = 0; string[i] != EOF; ++i)
i will be incremented, so you'll begin the new line with index 1. Therefore there is a bug when the line begins with //.
You can see that it solves the problem if you write instead:
if (string[i] == '\0') {
getaline(string, MAXLINE);
i = 0;
if (isInComment != INMULTICOMMENT)
isInComment = OUTOFCOMMENT;
}
though it's usually considered as bad style to modify for loop indices inside the loop. You may redesign your implementation in a more readable way.

K&R Exercise 1-20 The Programming Language 2nd edition

What should i do in this program. I cant understand.
The question is as : Write a program detab that replaces tabs in the input with the proper number
of blanks to space to the next tab stop. Assume a fixed set of tab stops, say every n columns.
Should n be a variable or a symbolic parameter?
I started by replacing the tabs ('\t') with space (' ').
But i guess this is the wrong approach.
please suggest ?
and btw what should n be? variable or symbolic parameter?
code so far:
#include<stdio.h>
#define TAB 5
int main() {
int i, c;
while((c = getchar()) != EOF) {
if(c == '\t') {
for(i = 0; i < TAB; ++i)
putchar(' ');
} else
putchar(c);
}
return 0;
}
In all the questions posted for this exercise i couldn't understand the meaning.
This is my final code, please tell me if it has any problems / bugs. I think it is working as it should..
thanks to #Nit, #Chrono Kitsune , #dasblinkenlight and all the others who helped.
#include<stdio.h>
#define TAB 8
int main() {
int c, count = 0, space = 0;
while((c = getchar()) != EOF) {
if(c == '\t') {
space = (TAB - (count % TAB));
while(space > 0){
putchar(' ');
count++;
space--;
}
}
else{
putchar(c);
++count;
}
if(c == '\n')
count = 0;
}
return 0;
}
What you are doing is not what the exercise wants you to do: rather than inserting a fixed number of spaces for each tab, you should be inserting a different number of spaces depending on how much has been printed on the line so far.
It does not matter how you take the number of spaces per tab - the way you made it a preprocessor constant is perfectly fine. However, rather than producing TAB spaces regardless of where the '\t' has been found, you program needs to count how much "regular" characters have been printed, and count how many spaces are needed when it sees '\t'.
Make a variable count for characters printed so far. Initialize it to zero, and then reset it back to zero each time you see a '\n' character. When you call putchar, also make count++.
Now when you see a tab '\t' compute how far you are form the next tab stop. The expression for that is
TAB - (count % TAB)
That is how many spaces you need to print.
This should be enough information for you to go back and fix your program - I think you need to write only five additional lines of code (not counting lines for curly braces that you would need to insert) in order to finish this exercise.
The first step is to understand the problem. As I read it over and over for several times at first I couldn't understand what exactly it wants me to do. It's because some concepts weren't clear or familiar to me before I searched for more information about tab. First, what is a tab and what is a tab stop exactly? A tab is a character represented by the escape sequence \t in many contexts. Just like other characters such as letters or digits, it's a character, but with special usage, so it's not a wide space or 4 or 8 spaces as it appears to be. Being displayed like a wide space or 4 or 8 spaces is just what it's designed for, which aligns each tab-delimited group of texts on multiple lines to make the region look like a table, but underneath on the level the software sees it's just a character. Tab stops are positions on the line where the cursor goes when the Tab key is pressed. These positions are fixed on the line according to the width or number of characters (or columns, all referring to the same concept) with which the Tab character is displayed. For example, on Windows Notepad the default width for Tab is 8 characters, and when you type Tab key the cursor would move behind the 8th, 16th, 24th... character. You can type 0s on the first line to see the effect more clearly:
00000000000000000000000000000000
Ivan Hello World
This is a table
delimited by tab
Now reading the problem over again it's clear to me that it's about replacing the Tab characters with spaces while maintaining the original table look. Then you can start writing your code to calculate how many spaces are needed for each Tab. Here's my complete code for this exercise:
#include <stdio.h>
#define MAX_LENGTH 1000
#define LINE_NUM 100
#define TAB_WIDTH 8
int readLine(char line[], int maxLength);
void copy(char from[], char to[]);
void detab(char line[], char result[]);
main() {
printf("Input: \n");
char lines[LINE_NUM][MAX_LENGTH];
char line[MAX_LENGTH];
char result[MAX_LENGTH];
int lineId = 0, length = 0;
while ((length = readLine(line, MAX_LENGTH)) != 0) {
detab(line, result);
copy(result, lines[lineId]);
lineId++;
}
printf("Output: \n");
for (int i = 0; i <= lineId; i++) {
printf("%s\n", lines[i]);
}
}
int readLine(char line[], int maxLength) {
char ch;
int length = 0;
while ((ch = getchar()) != EOF && ch != '\n' && length < maxLength) {
line[length] = ch;
length++;
}
if (ch == '\n') {
line[length] = '\0';
}
return length;
}
void copy(char from[], char to[]) {
int i = 0;
while (from[i] != '\0') {
to[i] = from[i];
i++;
}
to[i] = '\0';
}
void detab(char line[], char result[]) {
int i = 0;
char ch;
int column = 0;
int spaces;
int nextTabStop;
while ((ch = line[i++]) != '\0') {
if (ch == '\t') {
spaces = TAB_WIDTH - column % TAB_WIDTH;
nextTabStop = column + spaces;
for (; column < nextTabStop; column++) {
result[column] = ' ';
}
} else {
result[column] = ch;
column++;
}
}
result[column] = '\0';
}
First, try to get familiar with '\t' (TAB character) and see what happens when you print
'\t' + ','
'.' + '\t' + ','
'..' + '\t' + ','
And so on. You will see that there is a fixed number of initial '.'s in which the ',' character after '\t' is on the same position, this means that the '\t' length is not fixed, so if you try to replace it with a fixed number of ' ' characters (white spaces), the output will be different from the input.
Understanding that, your task is to create a program that replaces all '\t' characters with white spaces, so you have to calculate the number of necessary white spaces to print for each '\t' char you read. This is what I've done so far.
#include <stdio.h>
#define WSPT 8 // white spaces per tab
main () {
int c, counter;
counter = 0; // distance from the previous tab stop
while((c = getchar()) != EOF) {
if(c == '\t') {
for(int i = 0; i < WSPT - counter; ++i)
putchar(' '); // print white spaces until reach the next tab stop
counter = 0; // you are again at the start of a tab stop
} else {
putchar(c);
if(c != '\n')
counter = (counter + 1) % WSPT; // move 1 step
else
counter = 0; // you are again at the start of a tab stop
}
}
}
Okay, his is actually a very simple question and I'm not sure why everyone is making it more complicated than it is. We need to simply replace tab's with the necessary number of blanks so the resulting output looks no different than if there was a tab there.
No need for a million lines of code... a few will do...
#include <stdio.h>
/* A program *detab* that replaces tabs in the input with the proper number of blanks to space to the next tab stop. Assuming a fixed set of tabstops, say every n columns */
#define TAB_WIDTH 4 // tab width on particular machine
int main()
{
int c;
int i = 0;
while((c = getchar()) != EOF) {
if(c != '\t')
putchar(c);
else
while(i < TAB_WIDTH - 1){
putchar(' ');
i++;
}
}
}
why so complicated stuffs..just do this
#include <stdio.h>
int main()
{
int c, tab=6, count=0;
while((c=getchar())!=EOF)
{
count++;
if (c=='\t')
{
for (int i=count; i%(tab+1)!=0; i++) putchar(' ');
}
else putchar(c);
if(c=='\n') count=0;
}
}

Char Array trucates itself(K&R1-16&1-17)

In the following code, the char array prints up to 100 characters at location 1 and 2 but at location 3 it only prints 22. What is the reason for this behavior?
#include<stdio.h>
/* print the longest input line */
/*Exercise 1-16. Revise the main routine of the longest-line program so it will correctly print the length of arbitrary long input lines, and as much as possible of the text.*/
#define MAXLENGTH 100
int mygetline(char s[], int limit);
void charcopy(char to[], char from[]);
int main(){
char current[MAXLENGTH];
char longest[MAXLENGTH];
int curlen;
int maxlen;
maxlen = 0;
while( (curlen = mygetline(current, MAXLENGTH)) > 0 ){
if (curlen > 80)
printf("\nvery long:%d; %s\n", curlen, current);//#1# prints 100 digits
if(curlen>maxlen){
maxlen=curlen;
charcopy(longest, current);
printf("\nlonger:%d; %s\n", maxlen, longest);//#2# prints 100 digits
}
}
if (maxlen)//char array seems to truncates itself at scope boundry.
printf("\nlongest:%d; %s\n", maxlen, longest);//#3# prints 22 digits
printf("\nall done!\n");
return 0;
}
int mygetline(char s[], int limit){
int i, c;
for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
s[i]=c;
if(c=='\n'){
s[i]=c;
++i;}
else
if(i >= limit-1)
while (((c=getchar()) != EOF) && c != '\n')
++i;
s[i]='\0';
return i-1;
}
void charcopy(char to[], char from[]){
int i;
i=0;
while( (to[i] = from[i]) != '\0'){
++i;}
}
Its the location marked 3 in comment that prints only 22 characters instead of the full 100. Its very weird.
Edit:
As per Scotts answer, i have changed mygetline to this:
int mygetline(char s[], int limit){
int i, c, k;
for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
s[i]=c;
if((c=='\n') && (i < limit -1)){
s[i]=c;
++i;}
else{//if we are over the limit, just store the num of char entered without storing chars
k = 0;
while (((c=getchar()) != EOF) && c != '\n')
++k;}
s[i]='\0';
return i+k;
}
As can be seen, if input overshoots limit, then num of characters entered is stored in entirely new variable, k which does not touch the array. I still get truncation of the last printed line and i get weird 32770 as line lengths.Why? As can be seen, array is being baby sat and coddled and fed just the precise amount of char and no more.
Edit: The problem with the first listing was, as pointed out by Scott was that i was overshooting arrays. The problem with the second mygetline was that k=0; was initialized way way inside the if else nest. Moving the initialization upwards and making it global to the whole function, seems to solve the second issue.
working mygetline as follows:
int mygetline(char s[], int limit){
int i, c, k;
k=0;
for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i)
s[i]=c;
if((c=='\n') && (i < limit -1)){
s[i]=c;
++i;}
else{//if we are over the limit, just add the num of char entered without storing chars
while (((c=getchar()) != EOF) && c != '\n')
++k;}
s[i]='\0';
return i+k;
}
Ok, so the thing you need to know about C is that it doesn't babysit you at all. If you have an array declared as char foo[4] and try writing to foo[20], C won't complain at all. (It will typically throw a segmentation violation if you write into restricted memory, like NULL, but if you have access to the memory, you can do whatever you want to it.)
So, what happens, when you write to an array, further than you should? The official answer is "undefined behavior" - a blanket answer that is totally generic, and says, "It's up to the compiler." However, in most C compilers, it will do something called corrupting your stack.
The memory you ask for in any function - including main - is all allocated in a nice single coherent block. So in your main function, you have 100 bytes for current, 100 bytes for longest, 4 bytes for curlen and 4 bytes for maxlen (assuming 32-bit integers. They may also be 64 - again, depends on the compiler.) If you write to current[123], C will let you do it - and it will put whatever you wrote in the place of longest[23]. (Usually. Again, it's technically undefined behavior, so it's not guaranteed this will happen.)
Your problem is the line in mygetline where you set s[i] = '\0';. The problem is, you've let i get bigger than the array. If you printf("i = %d\n", i); right before that line, you'll see that i = 123. Your last line is not as big as your biggest line, so you're overwriting the data in longest that you don't want to overwrite.
There are lots of ways to fix this. Namely, make sure that when you set something to '\0', make sure that i <= limit - 1. (You can do this by moving the s[i] = '\0' line to above your while !EOF line and setting it to s[limit - 1] just to make sure you don't go over. You'll also need to add {} to your if statement. Generally, it's a good policy to add them to any if or while statement. They take up a line, but make sure you're coding in the right place.) Remember, the instruction is to "get the maximum length, not the maximum string.`
I'd be surprised if you're actually seeing 100 characters in the first 2 lines. From what I can tell, you should be seeing 122.

Embracing/or not ++i in one part of a code. K&R longest line example

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;
}
This example is from K&R book on C, chapter 1.9 on arrays. What I do not understand is why do we have to embrace ++i inside if statement? Writing it outside should do the same work.
if(c=='\n')
s[i] = c;
++i;
s[i] = '\0'
return 0;
}
In case of embracing i program works as intended, but on the second case(which in my opinion should do the same work and this is why I edited that part) it doesn't. I ran it through debugger and watched i which in both cases was correctly calculated and returned. But program still won't work without embracing ++i. I don't get my print from printf statement, and Ctrl+D just won't work in terminal or XTerm(thorough CodeBlocks) I can't figure out why. Any hint please? Am I missing some logical step? Here is a complete code:
//Program that reads lines and prints the longest
/*----------------------------------------------------------------------------*/
#include <stdio.h>
#define MAXLINE 1000
int getline(char currentline[], int maxlinelenght);
void copy(char saveto[], char copyfrom[]);
/*----------------------------------------------------------------------------*/
int main(void)
{
int len, max;
char line[MAXLINE], longest[MAXLINE];
max = 0;
while( (len = getline(line, MAXLINE)) > 0 )
if(len > max){
max = len;
copy(longest, line);
}
if(max > 0)
printf("StrLength:%d\nString:%s", max, 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;
++i;
}
s[i] = '\0';
return i;
}
/*----------------------------------------------------------------------------*/
void copy(char to[], char from[])
{
int i;
i = 0;
while( (to[i]=from[i]) != '\0')
++i;
}
/*----------------------------------------------------------------------------*/
The line
if(c == '\n')
is equivalent to
if(c != EOF)
Does that help explain why the embracing occurs?
There is a logic there:
if(c=='\n'){
s[i] = c;
++i;
}
It means only if you read an additional newline, you need to increment i one more in order to keep space for the \0 character. If you put ++i outside the if block. it means that it will always increase i by 1 even there is no newline input, in this case, since i is already incremented in the for loop , there is already space for \0, therefore, ++i again will be wrong. You can print the value of i and see how it works.
The index specified by i is the location where the terminating null should be placed when there is no more input for the line. The location just before the index i contains the last valid character in the string.
Keep in mind that the loop that reads data from stdin can terminate for reasons other than reading a \n character.
If you had this construct:
if(c=='\n')
s[i] = c;
++i;
then if the last character read from stdin wasn't a newline you would increment the index by one without writing anything into the location specified by the pre-incremented value of i. You would be effectively adding an unspecified character to the result.
Worse(?), if the for loop terminated because of the i<lim-1 condition you would end up writing the terminating null character after the specified end of the array, resulting in undefined behavior (memory corruption).
The ++i is inside the if statement because we do not want to increment i if we are not placing the \n character in the current index; that would result in leaving an index in between the last character of the input and the \0 at the end of the character string.
For loop can exit due to 3 conditions
1. reading char limit reached or EOF encountered
2. New Line encountered
For first Case We need to store Null into string s , as i points to next position to last valid character read so no need to increment i.
But for second case , as i points to next position to last valid character read , we now store newline at that position then increment i for storing NULL character.
Thats why we need to increment i in 2nd case not in 1st case.
if(c=='\n'){
s[i] = c;
++i;
}

Resources