Home > Software design >  Writing multiple lines of text to an array in C
Writing multiple lines of text to an array in C

Time:06-08

I'm a very amateur programmer working his way through K&R's 'The C Programming language'. I'm on the character arrays section of the first chapter, and I'm trying to do one of the recommended exercises.

I had already made a program that worked, but the problem was that it worked immediately, so I had to write all my test input text separately then paste it into the terminal.

The original program in the book has a property where the program only outputs text once the EOF character has been found. I wanted to replicate that in my program, and the only way I could think to do that was storing it all in one array. One hour later and this was the result, but I can't for the life of me figure out why it isn't working.

The program only outputs the first line that is longer than 80 characters.

Help would be appreciated.

  1 #include <stdio.h>
  2 #define MAXLINE 1000    /* maximum input line */
  3 #define MINLENGTH 80    /* minimum length of an output line */
  4 
  5 int getlone(char line[], int maxline);
  6 int append(char to[], char from[], int i);
  7 
  8 /* print all input lines longer than 80 characters*/
  9 int main(){
 10     int len;    /* current line length */
 11     int outlen;     /*length of all output lines so far*/
 12     char line[MAXLINE];     /* current input line */
 13     char printlines[MAXLINE];   /*all output lines*/
 14 
 15     while((len = getlone(line, MAXLINE)) > 0){
 16             if (len > MINLENGTH){
 17                 outlen = append(printlines, line, outlen);
 18             }
 19     }
 20     printlines[outlen] = '\0';
 21     printf("%s", printlines);
 22     return 0;
 23 }
 24 
 25 /*getline: read a line into s, return length*/
 26 int getlone(char s[], int lim){
 27     int c, i;
 28     for(i=0; i < lim-1 && (c = getchar()) != EOF && c != '\n'; i  ){
 29         s[i] = c;
 30     }
 31 
 32     if (c == '\n') {
 33         s[i] = c;
 34         i  ;
 35     }
 36     return i;
 37 }
 38 
 39 /* append: adds line to the end of a character array*/
 40 int append(char to[], char from[], int i){
 41     while((to[i] = from[i]) != '\n')
 42         i  ;
 43     return i  ;
 44 }
 45 

CodePudding user response:

First off, well done for working through the classic K&R book. That's how I learned C programming too.

Your problem stems from two problems:

  1. The index to the array returned by append() returns 1 past the last point written. Which is one past a likely zero, as arrays are typically (in modern C) initialized with zeros in each character. And zero is telling the print statement to stop printing.

  2. You're not initializing outlen to zero, and unlike arrays it can get filled with a random value (potentially).

  3. You're copying from another string (char array) starting at the index of the multiline instead of the line.

To demonstrate, consider this code

#include <stdio.h>

#define MAXLINE 1000    /* maximum input line */

/* append: adds line to the end of a character array*/
int append(char to[], char from[], int i){
    while((to[i] = from[i]) != '\n')
        i  ;
    return i  ;
}

int main() {
    char printlines[MAXLINE];
    int outlen = 0;

    outlen = append(printlines, "foo", outlen);
    outlen = append(printlines, "bar", outlen);
    printf("multi: %s\n", printlines);
}

This code when run will only print "foo". But if you look at the bytes in the actual array using gdb, you'll see that bar is there, but one spot too far:

(gdb) p printlines[0]
$1 = 102 'f'
(gdb) p printlines[2]
$2 = 111 'o'
(gdb) p printlines[3]
$3 = 0 '\000'
(gdb) p printlines[4]
$4 = 98 'b'

Or using the better x command in gdb:

(gdb) x/8b printlines
0x7fffffffced0: 0x66    0x6f    0x6f    0x00    0x62    0x61    0x72    0x00

This actually works:

#include <stdio.h>

#define MAXLINE 1000    /* maximum input line */

/* append: adds line to the end of a character array*/
int append(char to[], char from[], int i){
    int j = 0;
    while((to[i] = from[j]) != '\n') {
        i  ;
        j  ;
    }
    return i 1;
}

int main() {
    char printlines[MAXLINE];
    int outlen = 0;

    printf("outlen: %d\n", outlen);

    outlen = append(printlines, "foo\n", outlen);
    printf("outlen: %d\n", outlen);

    outlen = append(printlines, "bar\n", outlen);
    printf("outlen: %d\n", outlen);

    printf("multi: %s\n", printlines);
}

Final note: your code is subject to buffer overflows. You should always keep track of the length of an array used, and pass this into any functions to make sure you don't overwrite the end of the array. Consider a file with 20 80-line lines. This will be larger than your 1000 limit, but your program will still attempt to write beyond it (and will crash).

CodePudding user response:

There are a few problems here:

  1. outlen should be initialized to zero
     int outlen = 0;     /*length of all output lines so far*/
  1. the while on line 15 should be comparing > 1 not > 0 because '\n' will be counted as one character.
     while((len = getlone(line, MAXLINE)) > 1){
  1. append needs an additional index to account for the fact that to[] and from[] are different sizes
/* append: adds line to the end of a character array*/
    int append(char to[], char from[], int tolen){
        int i = 0;
        while((to[i   tolen] = from[i]) != '\n')
            i  ;
        return (tolen   i   1);
    }
  1. This no longer matters but it is important to note, the i on line 43 will happen after the return, so you will be returning a number one fewer than anticipated. It should have been something like:
    return   i; // or (i 1)

Good luck with your journey into c.

  • Related