поведение строк c отличается при определении и в функции strcat

#c

#c

Вопрос:

 #include <iostream>
#include <cstring>
using namespace std;
int main ()
{
    char str1[10] = "Hello";
    char str2[10] = "World";
    int  len ;
    strcat( str1, str2);
    len = strlen(str1);
    cout << len << endl<<str1<<endl;
    return 0;
}
 

Когда я инициализирую str1 подобным char str1[5]="hello"; образом, компилятор C выдает мне ошибку (означает, что размер строки должен быть на 1 больше, чем заданная строка).
Но в strcat том, что мы объединяем str1 str2 с, размер первой строки равен 10, а длина строки также равна 10 (означает отсутствие дополнительного нулевого символа). Почему это меняет поведение?
Преобразуем ли мы строку C в строку C в strcat функции, пожалуйста, объясните.

Комментарии:

1. Если вы получаете ошибки компилятора, всегда полезно добавить их в свой вопрос

2. Вы никоим образом не используете строки C , поэтому они не имеют к этому никакого отношения. В противном случае я действительно не знаю, о чем вы спрашиваете. Однако вы вызываете неопределенное поведение.

3. Вам нужно обратиться к ссылке . Поскольку адресат недостаточно велик, у вас неопределенное поведение.

4. как и в приведенной ниже строке кода: strcat(str1, str2); в строке # 9 размер назначения равен 10, а длина строки также равна 10, поэтому в них нет места для нулевого символа. я просто не могу понять приведенную выше концепцию..

Ответ №1:

Преобразуем ли мы строку c

Нет, в вашей программе нет строк c (т.Е. std::string ).

почему это изменилось поведение?

Вы написали другую программу, и поведение отличается.

В первом случае ваша программа была неправильно сформирована. Стандарт требует, чтобы компилятор уведомлял вас об этом во время компиляции. И обнаружить вашу ошибку также легко для компилятора. Тип переменной — «массив из 5 символов». 6 символов не подходят — тип неправильный. Типы известны во время компиляции.


В примере кода вы используете strcat . Если вы посмотрите на эту ссылку, вы обнаружите, что

Поведение не определено, если целевой массив недостаточно велик для содержимого как src, так и dest и завершающего нулевого символа.

Стандарт не требует, чтобы компилятор предупреждал вас о неопределенном поведении. На самом деле, компилятору обычно довольно сложно доказать, что программа имеет неопределенное поведение, хотя в данном конкретном случае это кажется очевидным.

Аргументы strcat являются указателями. Вы передаете указатели правильного типа strcat . Ошибок типа нет. Ошибка заключается в неправильных значениях. Значения копируются в массивы во время выполнения (если оптимизатор не выполняет какую-либо магию). Чтобы выяснить вашу ошибку, компилятору придется имитировать выполнение программы. Выполнение этого для всех путей кода будет чрезвычайно медленным. Таким образом, компилятор возлагает ответственность на программиста за выполнение предварительных strcat условий .

Ответ №2:

Это строки в стиле C, а не строки C , т. Е. Вы не используете класс std::string . Строки в стиле C заканчиваются символом ‘ 0’, что означает, что вам нужно дополнительное место для хранения за пределами длины строки. «Hello» имеет длину 5, но для его хранения вам нужен массив размером 6. В вашем примере на самом деле нет необходимости указывать размер массивов, просто выполните следующие действия и позвольте компилятору вычислить размер:

 char str1[] = "Hello";
 

Функция strcat требует, чтобы первый аргумент указывал на массив, в котором достаточно места для объединенной строки. Это опасная функция, потому что она не будет проверять, так ли это на самом деле, если нет, она просто перезапишет все, что находится за пределами конца вашего массива. В вашем случае, объединяя две строки, каждая из которых имеет длину 5 символов, вы получите строку длиной 10 символов, и вам нужно убедиться, что первый аргумент указывает на массив длиной не менее 11 символов. Если бы вы использовали строки C , вам не пришлось бы беспокоиться ни о чем из этого:

 #include <string>
#include <iostream>

int main()
{
   std::string str1("Hello");
   std::string str2("World");
   str1.append(str2);
   std::cout << str1.size() << 'n' << str1 << std::endl;
}