0

first of all i'm new to coding in C.

I tried to read a string of unknowns size from the user until a blank line is given and then save it to a file, and after that to read the file.

I've only managed to do it until a new line is given and I don't know how to look for a blank line.

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

char *input(FILE* fp, size_t size) {
    char *str;
    int ch;
    size_t len = 0;
    str = realloc(NULL, sizeof(char)*size);
    if (!str)return str;
    while (EOF != (ch = fgetc(fp)) && ch != '\n') {
        str[len++] = ch;
        if (len == size) {
            str = realloc(str, sizeof(char)*(size += 16));
            if (!str)return str;
        }
    }
    str[len++] = '\0';

    return realloc(str, sizeof(char)*len);
}

int main(int argc, const char * argv[]) {
    char *istr;
    printf("input string : ");
    istr = input(stdin, 10);
    //write to file
    FILE *fp;
    fp = fopen("1.txt", "w+");
    fprintf(fp, istr);
    fclose(fp);

    //read file
    char c;
    fp = fopen("1.txt", "r");
    while ((c = fgetc(fp)) != EOF) {
         printf("%c", c);
    }

    printf("\n");
    fclose(fp);

    free(istr);
    return 0;
}

Thanks!

6
  • 3
    EOF cannot be stored in char, so the type of c to store what is returned from fgetc() should be int. Commented Jun 3, 2016 at 16:16
  • @MikeCAT Are you serious? isn't EOF on most systems (-1) ? A signed char can store a value between -128 and 127 Commented Jun 3, 2016 at 17:01
  • 1
    @layzak Yes. Characters returned from fgetc() is range of unsigned char. Converting EOF to fit in char isn't a good idea because it will make it unable to distinguish one of possible character and EOF. Commented Jun 3, 2016 at 17:04
  • If realloc fails, you leak memory. Commented Jun 3, 2016 at 17:30
  • 1
    What do you consider the difference between a "new line" and a "blank line"? Commented Jun 3, 2016 at 17:45

3 Answers 3

2

I would restructure your code a little. I would change your input() function to be a function (readline()?) that reads a single line. In main() I would loop reading line by line via readline().

If the line is empty (only has a newline -- use strcmp(istr, "\n")), then free the pointer, and exit the loop. Otherwise write the line to the file and free the pointer.

If your concept of an empty line includes " \n" (prefixed spaces), then write a function is_only_spaces() that returns a true value for a string that looks like that.

While you could handle the empty line in input(), there is value in abstracting the line reading from the input termination conditions.

Sign up to request clarification or add additional context in comments.

Comments

1

Why not use a flag or a counter. For a counter you could simply increase the counter each character found. If a new line is found and the counter is 0 it must be a blank line. If a new line character is found and the counter is not 0, it must be the end of the line so reset the counter to 0 and continue.

Something like this:

int count = 0;
while ((ch = fgetc(fp)) != EOF)
{
    if(ch == '\n')
    {
        if(count == 0)
        {
            break;
        }
        count = 0;
        str[len++] = ch;
    }
    else
    {
        str[len++] = ch;
        ch++;
    }
}

Another way would be to simply check if the last character in the string was a new line.

while ((ch = fgetc(fp)) != EOF)
{
    if(ch == '\n' && str[len - 1] == '\n')
    {
        break;
    }
}

1 Comment

Thanks, But please add len variable into your example.
1

A blank line is a line which contains only a newline, right ? So you can simply keep the last 2 characters you read. If they are '\n', then you have detected a blank line : the first '\n' is the end of the previous line, the second one is the end of the current line (which is a blank line).

char *input(FILE* fp, size_t size) {
    char *str;
    int ch, prev_ch;
    size_t len = 0;
    str = realloc(NULL, sizeof(char)*size);
    if (!str)return str;
    while (EOF != (ch = fgetc(fp)) && (ch != '\n' && prev_ch != '\n')) {
        str[len++] = ch;
        if (len == size) {
            str = realloc(str, sizeof(char)*(size += 16));
            if (!str)return str;
        }
        prev_ch = ch;
    }
    str[len++] = '\0';

    return realloc(str, sizeof(char)*len);
}

Note that parenthesis around ch != '\n' && prev_ch != '\n' are here to make the condition more understandable.

To improve this, you can keep your function that reads only a line and test if the line returned is empty (it contains only a '\n').

2 Comments

that's not possible, if ch is \n then also prev_ch will be \n and then im in the same problem.
Yes but when prev_ch will be '\n', ch will be the next character.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.