1

The code successfully compiles it but I can't understand why, for certain values of number, the program crashes and for other values it doesn't. Could someone explain the behavior of adding a long int with a char* that the compiler uses?

#include <iostream>

int main()
{
    long int number=255;
    std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
    number=15155;
    std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
    return 0;
}

Test results:

Value 1 : >                                                                            
Value 2 : Segmentation fault  

Note: I'm not looking for a solution on how to add a string with a number.

user438383
  • 5,716
  • 8
  • 28
  • 43
  • There's a duplicate for this surely – Hatted Rooster Oct 02 '20 at 15:18
  • 1
    Intuitively I would say `""` returns the address of the first element of a litteral empty string; then you add `number` to that address; then `operator<<` attempts to dereference that new address to read a string, which is undefined behaviour. – Stef Oct 02 '20 at 15:18
  • 2
    The dupe explains what happens when you add a `char`. Your's is a simpler case of that, since `char` is promoted to `int` first. – cigien Oct 02 '20 at 15:19
  • 6
    For a more visual explanation of this phenomenon: replace `""` with `"Hello, World!"` and `number=255;` with `number=7;` – Stef Oct 02 '20 at 15:20
  • @stef Thank's for the explanation that resolved my problem – Bouraoui Al-Moez L.A Oct 02 '20 at 15:21
  • @cigien I've turned the dupes the other way round. It should always be from the specific case to the more generic one. – πάντα ῥεῖ Oct 02 '20 at 15:54
  • @πάνταῥεῖ Oh, I see. I was wondering what that was about :p reordering the dupe definitely makes more sense, thanks for the comment :) – cigien Oct 02 '20 at 15:58
  • Another question involving adding a character to a string literal, similar to the former duplicate: [string concatenation doesn't work as expected](https://stackoverflow.com/questions/21801013/string-concatenation-doesnt-work-as-expected) – JaMiT Oct 02 '20 at 19:15
  • Probable duplicate, but it feels wrong to redirect a question with a positive score to one with a negative score: [Why can you add an integer to a string literal?](https://stackoverflow.com/questions/25299156/why-can-you-add-an-integer-to-a-string-literal) – JaMiT Oct 02 '20 at 19:17

2 Answers2

2

Pointer arithmetic is the culprit.

A const char* is accepted by operator<<, but will not point to a valid memory address in your example.

If you switch on -Wall, you will see a compiler warning about that:

main.cpp: In function 'int main()':
main.cpp:6:59: warning: array subscript 255 is outside array bounds of 'const char [1]' [-Warray-bounds]
    6 |     std::cout<< "Value 1 : " << std::flush << ("" + number) << std::flush << std::endl;
      |                                                           ^
main.cpp:8:59: warning: array subscript 15155 is outside array bounds of 'const char [1]' [-Warray-bounds]
    8 |     std::cout<< "Value 2 : " << std::flush << ("" + number) << std::flush << std::endl;
      |                                                           ^
Value 1 :  q

Live Demo

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
2

In C++, "" is a const char[1] array, which decays into a const char* pointer to the first element of the array (in this case, the string literal's '\0' nul terminator).

Adding an integer to a pointer performs pointer arithmetic, which will advance the memory address in the pointer by the specified number of elements of the type the pointer is declared as (in this case, char).

So, in your example, ... << ("" + number) << ... is equivalent to ... << &""[number] << ..., or more generically:

const char *ptr = &""[0];
ptr = reinterpret_cast<const char*>(
    reinterpret_cast<const uintptr_t>(ptr)
    + (number * sizeof(char))
);
... << ptr << ...

Which means you are going out of bounds of the array when number is any value other than 0, thus your code has undefined behavior and anything could happen when operator<< tries to dereference the invalid pointer you give it.

Unlike in many scripting languages, ("" + number) is not the correct way to convert an integer to a string in C++. You need to use an explicit conversion function instead, such as std::to_string(), eg:

#include <iostream>
#include <string>

int main()
{
    long int number = 255;
    std::cout << "Value 1 : " << std::flush << std::to_string(number) << std::flush << std::endl;
    number = 15155;
    std::cout << "Value 2 : " << std::flush << std::to_string(number) << std::flush << std::endl;
    return 0;
}

Or, you can simply let std::ostream::operator<< handle that conversion for you, eg:

#include <iostream>

int main()
{
    long int number = 255;
    std::cout<< "Value 1 : " << std::flush << number << std::flush << std::endl;
    number = 15155;
    std::cout<< "Value 2 : " << std::flush << number << std::flush << std::endl;
    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770