1

I am writing a program which takes in user input character by character and print it out at the end:

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


#define FACTOR 2

int main(void) {

    printf("Enter line: ");
    int curr_size = 10;
    char curr_char = 0;
    char *ptr = malloc(curr_size * sizeof(char));
    int num_of_chars = 0;

    while (1) {
        int res = scanf(" %c", &curr_char);
        if (res == EOF) {
            break;
        }
        if (res != 1) {
            printf("Error: %c is not a character", res);
            break;
        }
        if (num_of_chars == curr_size) {
            curr_size = FACTOR * curr_size;
            ptr = realloc(ptr, curr_size);
        }

        ptr[num_of_chars] = curr_char;
        num_of_chars++;
    }

    printf("%s\n", ptr);
    return 0;
}

However, I notice that whenever I enter a line more than 10 characters (which trigger realloc), there is a unknown character appended at the end of my line when outputing:

output image, cant display that character on paste
If I change ptr[num_of_chars] = curr_char; to *(ptr + num_of_chars) = curr_char; the character disappear, may I know why and how to fix it? Thanks in advance.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Kallzvx
  • 594
  • 7
  • 23
  • 5
    Where do you terminate this string you're building character by character ? `%s` mandates a null-terminated sequence, and you're not definitively providing one. Therefore, invoking `printf("%s\n", ptr);` invokes *undefined behavior*. – WhozCraig Sep 23 '19 at 15:22
  • 2
    "%c is not a character" can never happen -- anything you can type is a character. – Barmar Sep 23 '19 at 15:22
  • 2
    You're never adding the null terminator to the string. – Barmar Sep 23 '19 at 15:24
  • 1
    You need to check the value returned by realloc. It can return NULL. – William Pursell Sep 23 '19 at 15:25
  • @WhozCraig What do you mean by terminate this string? Sorry I new to c... – Kallzvx Sep 23 '19 at 15:25
  • @WilliamPursell I see, I will add them later, Thanks! – Kallzvx Sep 23 '19 at 15:26
  • @Barmar Could you explain a bit more on string's null terminator? – Kallzvx Sep 23 '19 at 15:27
  • 1
    Possible duplicate of [What is a null-terminated string?](https://stackoverflow.com/questions/2037209/what-is-a-null-terminated-string) – dandan78 Sep 23 '19 at 15:27
  • 1
    @Kallzvx Read the chapter on strings in any C textbook or tutorial. A string is an array of characters ending with a null byte. – Barmar Sep 23 '19 at 15:28
  • @dandan78 That's about C++, which is likely to confuse a C beginner. – Barmar Sep 23 '19 at 15:28
  • @WhozCraig Thanks! I fixed it by adding `ptr[num_of_chars] = '\0';` before printing! – Kallzvx Sep 23 '19 at 15:38
  • @WhozCraig But actually I have another question: why using `*(ptr + num_of_chars) = curr_char;` solved my problem as well? I did not add an string terminator while using that line... – Kallzvx Sep 23 '19 at 15:42

1 Answers1

1

Taking into account this if statement

    if (res == EOF) {
        break;
    }

the following if statement

    if (res != 1) {
        printf("Error: %c is not a character", res);
        break;
    }

does not make sense. Moreover you are trying to output an integer returned by the function scanf as a character.

In general the function realloc can return NULL. In this situation there will be a memory leak because the previous value of the pointer ptr was overwritten

ptr = realloc(ptr, curr_size);

and this statement

    ptr[num_of_chars] = curr_char;

will invoke undefined behavior.

Also you are trying to output the character array as a string

printf("%s\n", ptr);

but you did not append the array with the terminating zero character.

You should in this case use the call at least like

printf("%*.*s\n", num_of_chars, num_of_chars, ptr);

or you have to append the terminating zero character.

And you should free the allocated memory.

The program can look like

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

#define FACTOR 2

int main(void) 
{
    size_t curr_size = 10;  

    char *ptr = malloc( curr_size * sizeof( char ) );
    ptr[0] = '\0';
    char c;

    printf( "Enter line: " );

    size_t i = 0;
    for ( ; scanf( "%c", &c ) == 1 && c != '\n'; i++ )
    {
        if ( i == curr_size )
        {
            char *tmp = realloc( ptr, curr_size * FACTOR );

            if ( tmp == NULL ) break;

            curr_size *= FACTOR;
            ptr = tmp;
        }

        ptr[i] = c;
    }

//  i == curr_size ? ptr[i-1] = '\0' : ( ptr[i] = '\0' );

//  puts( ptr );

    printf( "%*.*s", ( int )i, ( int )i, ptr );

    free( ptr );

    return 0;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335