0

I know that strings are just an array of chars with adjacent memory addresses. So when you have a character array:

char s[5];
s[0] = '1';
s[1] = '2';
s[2] = '3';
s[3] = '4';
s[4] = '5';

and change character array at s[1] to "5" then printing such an array should return "15345". Now my question is about scanf and strtol functions. When I insert values into the array s using scanf twice using different sized strings, Why is it that the strtol function does not convert the ENTIRE array?

Here is my code as example:

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

int main(){
    char bytes[5];
    printf("enter size 1: ");
    scanf("%s", bytes);

    printf("the size is: %ld\n", strtol(bytes, NULL, 10));

    printf("enter size 2: ");
    scanf("%s", bytes);

    printf("the size is: %ld\n", strtol(bytes, NULL, 10));

    return 0;

}

So imagine these user inputs:

10000

the program would then print out "the size is 10000"

then the user inputs:

100

the program then prints "the size is 100"

why doesn't it print out "the size is 1000" again? I only stored 100 into bytes, shouldn't the remaining array elements of bytes from the first input be unchanged and strtol should convert the rest of the array right?

In my mind, when the program stores the first input of 10000 into the array bytes, it looks like this at that moment

bytes = {1,0,0,0,0}

then when the user inputs 100, the array looks the same since it only changed the values of the first 3 elements and the rest of the array should remain the same:

bytes = {1,0,0,0,0}

with that strtol would convert the entire array to 10000 right?

Does scanf essentially "empty" out the rest of the array when storing values into the same memory address?

user125535
  • 240
  • 4
  • 15
john
  • 61
  • 8

3 Answers3

2

I know that strings are just an array of chars with adjacent memory addresses.

Not quite. In C, a string is also zero-terminated. That is, the string ends with the first character that has a zero value. For instance

char a[6] = { 'h', 'i',  0 , 'h', 'o', 0 }; // print(a) prints "hi"
char b[6] = { 'h', 'e', 'l', 'l', 'o', 0 }; // print(b) prints "hello"
char c[5] = { 'h', 'e', 'l', 'l', 'o' };    // print(c) will attempt to print "hello" followed by whatever characters happen to follow c[4] in memory, until it hits a zero value. But that may be reading outside the memory bounds of your application, or indeed your system, so anything can happen.

So when you have a character array: <snip>

If you extend s to char s[6] and set s[5] = 0, your assumptions about altering s[1] and printing it will be correct

Now my question is about scanf and strtol functions. When I insert values into the array s using scanf twice using different sized strings, Why is it that the strtol function does not convert the ENTIRE array?

First a suggestion, after each scanf("%s", bytes); line, insert the following:

printf("bytes = { %02x, %02x, %02x, %02x, %02x } (%02x)",
        bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5] );

Run your test code with that change, and check what that line prints. If you see that, you'll hopefully see the answer to your question about scanf and strtol.

I'll annotate your code with some comments below indicating the contents of bytes, using ? as unknown :

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

int main(){
    char bytes[5];
    printf("enter size 1: ");
    scanf("%s", bytes);  // 10000<return>

    // bytes {  ? ,  ? ,  ? ,  ? ,  ?  } bytes[5] = ?
    printf("the size is: %ld\n", strtol(bytes, NULL, 10));
    // bytes { '1', '0', '0', '0',' 0' } bytes[5] = 0 !!! Note overflow

    printf("enter size 2: ");
    scanf("%s", bytes);  // 100<return>
    // bytes { '1', '0', '0', 0,' 0' } Note bytes[3] changes from '0' to 0

    printf("the size is: %ld\n", strtol(bytes, NULL, 10));

    return 0;

}

So in short,

Does scanf essentially "empty" out the rest of the array when storing values into the same memory address?

It doesn't empty it, but you're reading a string (format = "%s"), so scanf will add the appropriate terminating zero at the end of the string you read in.

Sigve Kolbeinson
  • 1,133
  • 1
  • 7
  • 16
1

You left off an important property of strings. They must end in a NUL byte, aka '\0'.

Which means that if you write "10000" into a 5 byte array you broke the rules.

The scanf function will convert characters into string for %s until it hits a space. This is not a safe operation. You should limit the length of the conversion with something like scanf("%4s", bytes). Because the scanf docs say:

String input conversions store a terminating null byte ('\0') to mark the end of the input; the maximum field width does not include this terminator.

That line from the doc also explains why you get "100" for size 2. Because scanf wrote {'1', '0', '0', '\0'} into your bytes array.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
1

Simple answer :

scanf() will terminate your char array with a \0. It does not empty the remainder of the array.

Here is a simple program that proves this :

#include <stdio.h>

int main(void) {
    char str[100];

    scanf("%s", str); // Inputing 0123456789
    printf("String : %s\n", str);

    scanf("%s", str); // Inputing 01234
    printf("String 2 : %s\n", str); // str should be { '0', '1', '2', '3', '4', '\0', '6', ... }

    printf("Proof : %s", str + 6); // Outputs 6789
    return 0;
}

scanf will override the array with what it has found and adds a \0 at the end. Therefore the rest of the array stays intact and still accessible.

In your situation, here is what your array looks like in memory :

  • Before second scanf() : { '1', '0', '0', '0', '\0' } // 1000

  • After second scanf() : { '1', '0', '0', '\0', '\0' } // 100

Corb3nik
  • 1,177
  • 7
  • 26