-3

Please explain the output when the entered string is longer than the size specified

#include<stdio.h>

int main()
{
  char name[21],address[31];
  puts("enter a name(max 21 characters)");
  gets(name);
  fflush(stdin);
  puts("enter an address(max 31 characters)");
  gets(address);
  fflush(stdin);
  puts("your name is:");
  puts(name);
  puts("Your address is:");
  puts(address);
  return 0;
}
Unda
  • 1,605
  • 3
  • 23
  • 30
  • 7
    undefined behaviour – mch Jul 02 '14 at 12:12
  • 4
    [Using fflush(stdin)](http://stackoverflow.com/questions/2979209/using-fflushstdin?lq=1) – chris Jul 02 '14 at 12:13
  • 2
    The behaviour is even undefined for inputs of 21 and 31 characters, respectively (the 0-terminator takes one byte). – mafso Jul 02 '14 at 12:15
  • 8
    **Never** use `gets`: http://stackoverflow.com/questions/4810764/c-gets-fgets – Ruud Helderman Jul 02 '14 at 12:15
  • 2
    Since this has a C++ tag, just use `std:string name;` and `std::cin >> name;`. No need for an arbitrary maximum number of characters and no buffer overrun. – chris Jul 02 '14 at 12:16
  • @Ruud: This seems to be about buffer overflows, so using `gets` is fine (actually the only use of that function). And it seems to me, that decades of many people complaining about `gets` made people use `scanf("%s", ...)` which is somehow even worse (a call to `gets` is easier to find than a wrong `scanf` call). – mafso Jul 02 '14 at 12:20
  • 2
    @chris Probably `getline(std::cin, name);` is better. – T.C. Jul 02 '14 at 12:23
  • What is the output you want to be explained? You haven't given any. – mafso Jul 02 '14 at 12:25
  • You get UB if the entered string is the _same_ as the size specified. The prompts are too long by 1. Should be "enter a name(max 20 characters)". – chux - Reinstate Monica Jul 02 '14 at 13:04

2 Answers2

0

When you enter more than the asked size, since gets don t check boundaries, you get undefined behavior, and the character that are too much can (or can not be, undefined behavior) be written in the space after the one reserved. You should use fgets (which have boundaries check) in C, and std::getline in C++.

DrakaSAN
  • 6,955
  • 7
  • 43
  • 85
0

Most C compilers will allocate name and address on the stack, next to each other in memory. I tested it with GCC on a Linux machine, and address came after name in memory; other C compilers might as well do it the other way around. It is also possible for compilers to allocate a few bytes of unused space between name and address, for memory alignment reasons; though this is uncommon for char arrays.

Let's assume address comes after name. Memory is allocated like this (lowest address on top):

name[0]
name[1]
name[2]
...
name[19]
name[20]
address[0]
address[1]
address[2]
...
address[29]
address[30]
base pointer
return address
stack frame of caller

As pointed out by mafso, strings are stored with a trailing NUL character, so the name should be 20 characters max (its last character will be in name[19], the NUL terminator in name[20]), and the address should not exceed 30 characters.

Enter a name of 21 characters, and the NUL terminator will be in address[0], only to be overwritten immediately thereafter by the address. Any additional characters entered beyond 21, will be overwritten too. puts(name) will print the 21 characters stored in name, followed by whatever the user entered in address; effectively, name and address are concatenated. puts(address) will print address in a normal fashion, since it starts printing at address[0].

Any attempt to enter an address of more than 30 characters, will overwrite the base pointer and/or return address, which is very likely to make function main crash upon return. Obviously, the same happens when you enter a name of more than 51 characters.

By carefully crafting the excess characters that will overwrite the return address, it is possible to make the program do something else than crash. Skillful hackers can use this to good fortune; this is what makes buffer overrun vulnerabilities so notoriously dangerous.

Ruud Helderman
  • 9,064
  • 1
  • 19
  • 39