#c #segmentation-fault
#c #ошибка сегментации
Вопрос:
Код успешно компилирует его, но я не могу понять, почему при определенных значениях number программа завершает работу, а при других значениях — нет. Может ли кто-нибудь объяснить поведение добавления a long int
с a char*
, которое использует компилятор?
#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;
}
Результаты тестирования:
Value 1 : >
Value 2 : Segmentation fault
Примечание: я не ищу решение о том, как добавить строку с числом.
Комментарии:
1. Для этого наверняка есть дубликат
2. Интуитивно я бы сказал
""
, что возвращает адрес первого элемента буквенной пустой строки; затем вы добавляетеnumber
к этому адресу; затемoperator<<
пытается разыменовать этот новый адрес для чтения строки, что является неопределенным поведением.3. Обманщик объясняет, что происходит, когда вы добавляете a
char
. Ваш случай является более простым, посколькуchar
он повышен доint
первого.4. Для более наглядного объяснения этого явления: замените
""
на"Hello, World!"
иnumber=255;
наnumber=7;
5. @stef Спасибо за объяснение, которое решило мою проблему
Ответ №1:
В C ""
это const char[1]
массив, который распадается на const char*
указатель на первый элемент массива (в данном случае на ''
нулевой завершитель строкового литерала).
Добавление целого числа к указателю выполняет арифметику указателя, которая увеличивает адрес памяти в указателе на указанное количество элементов типа, как объявлен указатель (в данном случае, char
).
Итак, в вашем примере ... << ("" number) << ...
эквивалентно ... << amp;""[number] << ...
или в более общем смысле:
const char *ptr = amp;""[0];
ptr = reinterpret_cast<const char*>(
reinterpret_cast<const uintptr_t>(ptr)
(number * sizeof(char))
);
... << ptr << ...
Это означает, что вы выходите за пределы массива при number
любом значении, отличном от 0, поэтому ваш код имеет неопределенное поведение, и при operator<<
попытке разыменования недопустимого указателя, который вы ему даете, может произойти что угодно.
В отличие от многих языков сценариев, ("" number)
это неправильный способ преобразования целого числа в строку в C . Вместо этого вам нужно использовать явную функцию преобразования, такую как std::to_string()
, например:
#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;
}
Или вы можете просто разрешить std::ostream::operator<<
обрабатывать это преобразование для вас, например:
#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;
}
Ответ №2:
Виновата арифметика указателей.
A const char*
принимается operator<<
, но не будет указывать на допустимый адрес памяти в вашем примере.
Если вы включите -Wall
, вы увидите предупреждение компилятора об этом:
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