0

I am confused about how pointers to characters work. when I run the following code, what happens?

int main()
{
    char* word;
    scanf("%s",word);
    printf("%s",word;
}

the first line in the main is defining a pointer to char without initialization. scanf should store the word somewhere and give the address to the pointer, right? what if I input a big string, would it overwrite something in the memory?

And what happens in the first line in the following code other than defining a pointer to char. Does the compiler set some limits? or I can't exceed the size specified, right? If done, I will have a run time error, right? what is the difference between the two cases?

int main()
{
    char word[100];
    scanf("%s",word);
    printf("%s",word;
}

What about pointers to other types? Can I just keep writing to the following places using offsets?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    In your first example, you need to malloc `word`. – Robert Harvey Nov 18 '21 at 18:42
  • 2
    As in `char* word = malloc(100 * sizeof(char));` – Robert Harvey Nov 18 '21 at 18:43
  • 1
    C doesn't really specify limits. If you `scanf` to an unallocated variable, it will happily overwrite whatever memory it is pointing to. (i.e. Undefined Behavior). – Robert Harvey Nov 18 '21 at 18:44
  • `"What about pointers to other types? Can I just keep writing to the following places using offsets?"` -- What exactly do you mean? Do you plan to store an `int` somewhere inside the array `word`, and have an `int *` pointing to that `int`? That would violate the [strict aliasing rule](https://stackoverflow.com/q/98650/12149471). – Andreas Wenzel Nov 18 '21 at 19:44

3 Answers3

2

scanf should store the word somewhere and give the address to the pointer, right?

No. It is the other way around. You define the address where scanf shall store the value. As you fail to initialize the pointer to some valid address, you cause undefined behaviour that might result in a crash in best case or seem to work in worst case.

And what happens in the first line in the following code other than defining a pointer to char.

There is no pointer involved at all. An array is not a pointer. An array provides all the memory it needs to store all its members. A pointer doesn't do this.

Does the compiler set some limits? or I can't exceed the size specified, right?

You can write wherever you want. No one will prevent you from doing this. At least no from trying. If you write to some location that does not belong to the memory you allocated, you again cause undefined behaviour.

Gerhardh
  • 11,688
  • 4
  • 17
  • 39
1

The function scanf requires that you pass it the address of a sufficiently large memory buffer for storing the string. If you don't do this, then you will be invoking undefined behavior (i.e. your program may crash).

Simply passing a wild pointer (i.e. an arbitrary memory address) is not sufficient. Rather, you must reserve the memory that you intend to use, for example by declaring an array or by using the function malloc.

Using the %s scanf conversion format specifier by itself is not a good idea, because even if the allocated memory buffer has a size of 100 characters, if the user types more than 99 characters (100 including the terminating null character), then the function will write to the array out of bounds, causing undefined behavior. Therefore, you should always limit the number of characters that are written, in this case by writing %99s instead of simply %s.

Also, before using the result of scanf, you should always check the return value of the function, and only use the result if the function was successful.

int main()
{
    char word[100];
    if ( scanf( "%99s", word ) == 1 )
        printf( "%s\n", word );
    else
        printf( "input error!\n" );
}

what if I input a big string, would it overwrite something in the memory?

It doesn't have to be a "big" string. Writing even a "small" string to a wild pointer will cause undefined behavior and something important may be overwritten, or your program may crash.

And what happens in the first line in the following code other than defining a pointer to char. Does the compiler set some limits?

The line

char word[100];

will allocate an array of 100 characters, i.e. it will give you a memory buffer that is sufficiently large to store 100 characters. This does not give you a pointer. However, when using the array word in the line

scanf("%s",word);

the array word will decay to a pointer to the first element.

Does the compiler set some limits? or I can't exceed the size specified, right?

The compiler won't prevent you from writing to the array out of bounds, but if you allow this to happen, then your program will have undefined behavior (i.e. your program may crash). Therefore, you probably don't want to allow that to happen.

If done, I will have a run time error, right?

If you are lucky, then yes, your program will crash immediately and you will easily be able to identify and fix the bug. If you are unlucky, then no, your program won't crash, but will work as intended, and you won't notice the bug for a very long time, until much later in development, when one day the bug starts overwriting something important in your program. In that case, the bug will probably be hard to diagnose.

This is because C is not a memory-safe language.

However, because these kinds of bugs are often hard to find, there are tools which can help detect these kinds of bugs, such as valgrind and AddressSanitizer.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
1

According to the description of the conversion specifier %s in the C Standard

If no l length modifier is present, the corresponding argument shall be a pointer to the initial element of a character array large enough to accept the sequence and a terminating null character, which will be added automatically.

That is when you pass a pointer as an argument of the function that corresponds to the format %s it shall point to the first element of a character array where the input string will be stored. The character array shall be large enough to accommodate the entered string (including the appended terminating zero character '\0')

In the first program

int main()
{
    char* word;
    scanf("%s",word);
    printf("%s",word;
}

the pointer word is uninitialized and has an indeterminate value. So these two statements

    scanf("%s",word);
    printf("%s",word;

invoke undefined behavior.

You need to provide a valid value of the pointer that will point to a character array. For example

char s[100];
char *word = s;

Or you can allocate memory dynamically like

char *word = malloc( 100 * sizeof( char ) );

In the second program

int main()
{
    char word[100];
    scanf("%s",word);
    printf("%s",word;
}

the array word used as an argument is implicitly converted to a pointer to its first element. If you will enter a string that fits in the array with 100 elements then the program will behave correctly.

However if you will enter 100 or more characters without embedded spaces then the program again will have undefined behavior.

To avoid such a situation you can specify the maximum length of the string that can be read in the array word by using the length modifier the following way

    scanf("%99s",word);

If you want to input a string that may have embedded spaces you should use another conversion specifier. For example

    scanf("%99[^\n]", word );

or

    scanf(" %99[^\n]", word );

Here are two demonstration programs that show the difference between the two conversion specifiers used to enter a string.

#include <stdio.h>

int main(void) 
{
    char word[100];
    
    scanf( "%99s", word );
    
    puts( word );
    
    return 0;
}

If to enter the string

Hello Mohammed Elbagoury

then the program output will be

Hello

And the second program

#include <stdio.h>

int main(void) 
{
    char word[100];
    
    scanf( "%99[^\n]", word );
    
    puts( word );
    
    return 0;
}

Again if to enter

Hello Mohammed Elbagoury

then the program output will be

Hello Mohammed Elbagoury

If you will enter more than 99 characters then only the first 99 characters will be stored in the array appended with the terminating zero character '\0'.

As for your this question

Can I just keep writing to the following places using offsets?

then you can use the pointer arithmetic to store data in any position of an array. for example

int a[10];

scanf( "%d", a + 5 );

In this case a number will be written in the element of the array a[5].

The above statement is equivalent to

scanf( "%d", &a[5] );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335