2

I want to read in the first 20 characters from stdin. Would I be able to just use a for loop that iterates 20 times and scanf("%c",&var)? What would happen if the input is less than 20 characters long?

I was thinking of using gets() to bypass this issue. Read in the entire line, then iterate over the string either until a counter reaches 20 or the end of string is reached. However, is there a way I can detect the end of a string?

Or is there a better way?

Only asking this because we're not allowed to use any of the functions from the string.h library.

e19293001
  • 2,783
  • 9
  • 42
  • 54
Quinn Tai
  • 55
  • 1
  • 7

4 Answers4

1

You can try this way...

1 - Read first 20 characters of a line by using scanf() as shown in example given below in a character array .

for example :

  char str[21];

  scanf("%20[^\n]s",str);

2 - Finally you will have first 20 characters from line in your character array .

3 - if the line length is less than 20 then it will automatically assign the '\0' character at the end of line .

and if you want to find total number of characters in a array then calculate the length of the array

**The end of a string is determine by using the '\0' NULL character

Nutan
  • 778
  • 1
  • 8
  • 18
  • 3
    [Don't use `gets` to read input.](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) – Holt Dec 11 '15 at 07:19
  • @holt why your saying that? – Nutan Dec 11 '15 at 07:21
  • Because `gets` is not safe, it will read everything up to the `\n` character, weither your buffer is long enough to store it or not. There are tons of posts on SO (the link I posted being one) and other sites explaining why you should not use `gets`. – Holt Dec 11 '15 at 07:26
  • but if line contain a space character then he must use gets() to read entire line . otherwise it will only read upto space character – Nutan Dec 11 '15 at 07:35
  • No. If you don't want to use `scanf`, you can use `fgets` which is *almost* equivalent to `gets` but is safe. But it is also possible to read line with spaces using `scanf` using e.g. `"%[^\n]20s"` format. – Holt Dec 11 '15 at 07:39
  • BTW, `str[20]` is wrong since your array has a size of `20`. – Holt Dec 11 '15 at 07:41
  • If I only need 20 elements, i.e. indexes 0 through 19, why do I need to do str[21]? – Quinn Tai Dec 11 '15 at 21:27
  • Nevermind, I realize it's for the \0 character. Thanks for all the help, guys. – Quinn Tai Dec 11 '15 at 21:33
1

Here is a solution using basic fgetc:

#include <stdio.h>

#define LEN(arr) ((int) (sizeof (arr) / sizeof (arr)[0]))

static void ReadLine(FILE *file, char result[], int resultLen)
{
    int i, ch;

    ch = fgetc(file);
    i = 0;
    while ((ch != EOF) && (ch != '\n') && (i < resultLen - 1)) {
        result[i] = ch;
        ch = fgetc(file);
        i++;
    }
    result[i] = '\0';
}


int main(void)
{
    char s[20 + 1];

    ReadLine(stdin, s, LEN(s));
    puts(s);
    return 0;
}
August Karlstrom
  • 10,773
  • 7
  • 38
  • 60
0

Here is a short version which works using scanf:

#include <stdio.h>

int main(void) {
    char buffer[20 + 1] ; // 20 characters + 1 for '\0'
    int  nread ;
    nread = scanf("%20[^\n]", buffer) ; // Read at most 20 characters
    printf("%s\n", buffer);
    return 0;
}

scanf will automatically add the '\0' character at the right place in buffer and with the "%20[^\n]" it will read at most 20 characters different from '\n'.

If you want to put this in a function and avoid repeating 20 (error prone):

#include <stdio.h>

int read_chars (char buffer[], int len) {
    char format[50] ;
    sprintf(format, "%%%d[^\n]", len);
    return scanf(format, buffer) ;
}

#define MAX_CHARS 20

int main(void) {
    char buffer[MAX_CHARS + 1] ; // 20 characters + 1 for '\0'
    read_chars (buffer, MAX_CHARS) ;
    printf("%s\n", buffer);
    return 0;
}

Edit: If you don't want to use sprintf to create the format string, you could use preprocessor (will not work if MAX_CHARS is not a preprocessor constant):

#include <stdio.h>

#define _READ_CHARS(buffer, N) scanf("%" #N "[^\n]", buffer)
#define READ_CHARS(buffer, N) _READ_CHARS(buffer, N)

#define MAX_CHARS 20

int main(void) {
    char buffer[MAX_CHARS + 1] ; // 20 characters + 1 for '\0'
    READ_CHARS (buffer, MAX_CHARS) ;
    printf("%s\n", buffer);
    return 0;
}
Holt
  • 36,600
  • 7
  • 92
  • 139
  • As far as I understand it is not possible to write a general line reading function using *scanf* since the width specifier cannot be made a variable, or am I wrong? – August Karlstrom Dec 11 '15 at 08:11
  • @AugustKarlstrom See my edit, you can create the format string on the fly, you just have to be careful about the `format` string length (I assumed 50 was enough in this case). – Holt Dec 11 '15 at 08:14
0

Just use read:

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

    int main(){
        //Declare the reading buffer. Need 1 more position to add '\0'
        char buffer[21];

        int char_num;
        if ((char_num = read(0, buffer, 20)) < 0) {
            perror("read: ");
            exit(1);
        }
        //means that there were less than 20 chars in stdin
        //add the null character after the last char and return
        else if (char_num < 20) {
            //terminate the string after the last char read from stdin
            buffer[char_num] = '\0';
            close(0);
            printf("%s\n", buffer);
        }
        //means that there were more than 20 (or exactly 20 chars on stdin)
        else {
            buffer[20] = '\0';
            printf("%s\n", buffer);
            //now it depends on what you want to do with the remaining chars
            //this read just discard the rest of the data, in the same buffer
            //that we ve used. If you want to keep this buffer for some other
            //task, figure out some other solution
            while(1) {
                if ((char_num = read(0, buffer, 20)) < 0) {
                    perror("read: ");
                    exit(1);
                }
                close(0);
                if (char_num == 0 || char_num < 20)
                    break;
            }
        }
        return 0;
    }
sestus
  • 1,875
  • 2
  • 16
  • 16