2

I'm fairly new to coding and am currently taking a programming course at school with C. We were given an assignment and I'm having a bit of difficulty with the first part. We're learning how to use the string-handling library (stdlib.h) and the objective of the assignment is to input multiple lines of text from the keyboard. The instructor advised us to use two-dimensional arrays in order to do this, but I'm a bit stuck. Here's the code I've written:

int main(void) {
    char string[3][SIZE];
    int i, j;
    int c;

    printf("Enter three lines of text:\n");

    for (i = 0; i < 3; i++) {
        j = 0;
        while ((j < SIZE) && (c = getchar() != '\n')) {
            string[i][j] = c;
            j++;
        }
    }

    for (i = 0; i < 3; i++) {
        for (j = 0; j < SIZE; j++) {
            printf("%c", string[i][j]);
        }
        printf("\n");
    }

    return 0;
}

Some points that I'd like to make are that I used the getchar() function to receive input one character at a time, and also the second for loop I intended to print each line of text that is stored in each row of the string array.

The input is any string of text for three lines, for example:

Hi my name is John.\n
I am from the US\n
and I'm a student.

Here's what the current output looks like:

Enter three lines of text:
rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr...

The output that I'm expecting is:

Enter three lines of text:\n
Hi my name is John.\n
I'm from the US\n
and am a student.

Any tips or advice would be greatly appreciated. Thank you!

BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
Sean
  • 2,890
  • 8
  • 36
  • 78
  • Is it a requirement of the exercise that you work character by character? – Schwern May 14 '17 at 03:20
  • 1
    Yes! That's why I used the getchar() function. My instructor recommended since we're studying the string-handling library that we try to utilize as many as we can, regardless of appropriateness or efficiency. – Sean May 14 '17 at 03:53
  • @Sean Thanks for the clarification. BTW [string.h](https://en.wikipedia.org/wiki/C_string_handling) is the string handling library. [stdio.h](https://en.wikipedia.org/wiki/C_file_input/output) is the IO handling library where `getchar` comes from. [stdlib.h](http://www.tutorialspoint.com/c_standard_library/stdlib_h.htm) is sort of a dumping ground. – Schwern May 14 '17 at 04:45
  • fix like [this](http://ideone.com/v1WlsK) – BLUEPIXY May 14 '17 at 04:51
  • This `c = getchar() != '\n'` does not do what you expect. – alk May 14 '17 at 13:11

2 Answers2

1

Note: I wrote this answer before the OP clarified they had to use getchar.

To read a whole line at a time, use fgets. To print a whole string at a time, use printf with the %s format.

#include <stdio.h>

int main(void) {
    // No need to define a SIZE constant.
    // Because it's stack allocated we can its size.
    char strings[3][100];

    printf("Enter three lines of text:\n");

    for ( int i = 0; i < 3; i++) {
        // Reads one line, up to the size of `strings[i]`, from stdin.
        fgets( strings[i], sizeof(strings[i]), stdin );
    }

    for ( int i = 0; i < 3; i++) {
        // Print each string and its line number.
        printf("Line %d: %s\n", i, strings[i]);
    }

    return 0;
}

This is not the best pattern to read input. You'll learn very quickly that fixed memory sizes and reading input don't work well. For future reference, it would be more like this.

#include <stdio.h>
#include <string.h>

int main(void) {
    // A list to store 3 strings, but no memory for the strings themselves.
    char *strings[3];

    printf("Enter three lines of text:\n");

    // A line buffer that's sufficiently large.
    // This will be reused.
    char line[4096];
    for ( int i = 0; i < 3; i++) {
        // Read into the large line buffer.
        fgets( line, sizeof(line), stdin );

        // Copy the string into a buffer that's just big enough.
        strings[i] = strdup( line );
    }

    for ( int i = 0; i < 3; i++) {
        printf("Line %d: %s\n", i, strings[i]);
    }

    return 0;
}

This allocates a single large line buffer to do the reading, then copies what its read with strdup to memory of just the right size. This lets you read even very long lines of input without wasting a bunch of memory if they're very short.

Note that strdup() is not part of the C standard library, but it's part of the POSIX spec. Any major compiler will have it, and it's easy to write your own.

Schwern
  • 153,029
  • 25
  • 195
  • 336
1

First of all let me commend the fact the you starting your way with C. That's the most solid language to learn(better is only assembly itself) - you will have a full understanding of how things work, which you wouldn't get if started from some language written on top of C(like Java and Python). But it's a hard and long road, which worth that.

On the code: there is a lot going and you have made a lot of amusing bugs that would reproduce different interesting things every other time and machine you run it.

First of all: to make your code work somehow all you need is add parenthesis:

    while ((j < SIZE) && ((c = getchar()) != '\n')) {

In C everything is binary(or integer, depending how you look at it) and default binding is to the right a op1 b op2 c op3 d.. First op3 is evaluated c op3 d = r1, then you have a op1 b op2 r1 and so on. Thus you was comparing the value of getchar() with value of character '\n' - which are not equal, so you get TRUE (value 1) and store it in local variable c.

Next you still have some problems because of the way you initialized your array:

     char string[3][SIZE];

What it does is simply "intrusts" 3*SIZE*sizeof(char) bytes of you process address space to a thing labeled "string". But that does not clear up all the remnants of previous live (of your program, or even before) on those bytes, so if it happens that SIZE in your program == 100 and you used to store your credit card on a real address memory (RAM) mapped to that region of your program memory you would see your credit card when you print it by printf - if you didn't overwrite those 300 bytes.

This may help you looking at it:

#include <stdlib.h>
#include <stdio.h>

#define SIZE 10

int main(void) {
    char string[3][SIZE];
    int i, j;
    int c;

    for(i = 0; i < 3; i++)
      for(j = 0; j < SIZE; j++){
        string[i][j] = 0;
      }
    printf("Enter three lines of text:\n");

    for (i = 0; i < 3; i++) {
        j = 0;
        while ((j < SIZE) && ((c = getchar()) != '\n')) {
            string[i][j] = c;
            j++;
        }
    }

    for (i = 0; i < 3; i++) {
        for (j = 0; j < SIZE; j++) {
            printf("%c", string[i][j]);
        }
        printf("\n");
    }

    return 0;
}

Also be aware that getchar() may behave lousy with input and newlines - it depends on whether you console buffers input before sending it to your program on enter(newline) or not. More here How to avoid press enter with any getchar()

Community
  • 1
  • 1
iantonuk
  • 1,178
  • 8
  • 28