




Why can't I initialise cb to cb1 and how to do it without strcpy?
cb1 относится к типу char*, но cb - это массив в стиле C, также известный как объект типа массива (в частности, char[100]). Объекты типа массив не может быть изменен (даже если они lvalue). Если вы хотите только мелкая копия, а не strcpy(), как вы говорите, тогда вы можете определить cb как char* вместо char[100]:
typedef struct book {
// ...
char* cb;
book(int a1, int b1, char* cb1) {
// ...
cb = cb1;
}
} book;
Но в большинстве случаев я бы не рекомендовал это делать., так как это повлечет за собой ненадежное управление этим необработанным указателем. Это помечено [C++], какая причина не использовать std::string?
Примечание. Хотя вы не пометили этот [C++ 11] или выше, дополнительная причина не использовать такие необработанные указатели или массивы в стиле C, подобные этому, - это то, что произойдет, когда вы попытаетесь использовать указанную выше структуру, возможно, так:
int main() {
book b(4, 2, "Hello");
return 0;
}
Достаточно стандартный компилятор, такой как Clang, сразу сообщит вам, что 1:
ISO C++11 does not allow conversion from string literal to '
char *'.
Это неявное преобразование из строковый литерал (тип которого - const char[]) в char* устарело даже в C++ 03, а теперь полностью удален с C++ 11.
1 По умолчанию это будет как минимум предупреждение и ошибка при сборке, например, с -pedantic-errors.
Вот этот тест, и мы можем использовать только iostream. Я новичок в cpp, поэтому вся эта работа с указателями меня действительно сбивает с толку.
@ManishMadugula Хорошо, друг, без проблем. Значит, вам не разрешено использовать `std :: string '? Вы хотите, чтобы я добавил к ответу дополнительные пояснения относительно работы с этим указателем?
@SkepticalEmpiricist Спасибо, ваш ответ прояснил мои сомнения. Нет необходимости в дополнительных объяснениях.
@SkepticalEmpiricist: Ваша программа недействительна с C++ 11.
@Destructor Я просто не смог найти пункт в спецификации, у вас есть его, чтобы я мог добавить к ответу?
@SkepticalEmpiricist: см. это и ответ это для получения дополнительной информации. Надеюсь, вы обновите свой ответ.
@Destructor Несмотря на то, что мой фрагмент был действителен, так как он не включал то, что я добавил по вашему запросу, я полностью согласен с вами, это важно отметить. Большое спасибо за продвижение вперед и дайте мне знать, если вы увидите что-нибудь еще, так что измените / добавьте.
@Destructor Также я думаю, что нашел соответствующий пункт в стандарте, я использовал его сейчас как ссылку в другом редактировании. Дайте мне знать, как у вас дела!
@SkepticalEmpiricist Вы тратите на это почти 7 часов, исследуя. ;) и придумал хороший ответ. Стоит поднять :)
Вы спрашиваете, почему вы не можете инициализировать char[] в struct?
Ответ на ваш вопрос:
Массивы - это `` граждане второго сорта '' в C; одним из следствий этого предубеждения является то, что вы не можете их приписать. Массив не является изменяемым lvalue в C и C++.
C и C++ - это разные языки программирования. В C++ следует избегать использования простых массивов в старом стиле C, потому что язык C++ предлагает удобные и лучшие альтернативы.
Поскольку этот вопрос был помечен как вопрос C++, идиоматическим решением было бы использовать std :: string в C++.
Итак, будет лучше, если вы сделаете следующее:
#include <string>
struct book {
int a;
int b;
std::string cb;
book(int a1, int b1, std::string cb1) {
a = a1;
b = b1;
cb = cb1;
}
} book;
Я бы не сказал, что массивы - это люди второго сорта. Типы массивов - это полноценные типы. Они настоящие, а не призраки. У них есть хранилище, срок службы и все остальное, чего вы ожидаете. Вы можете легко передавать указатели и ссылки на них, и (когда они завернуты в класс) также могут быть скопированы / перемещены. Лично я считаю правило распада имени, а также невозможность копирования через прямое присвоение отдельными странностями. В любом случае, это не имеет значения, потому что OP пытается инициализировать массив из указателя, который уже ошибочен.
Ваше сообщение помечено [C++], но не использует современные идиомы. Вот версия, которая допускает простую инициализацию. Используя std::string, вы избегаете сложного процесса инициализации.
Обратите внимание, что вам также не нужно переименовывать свои параметры.
std::string#include <iostream>
#include <string>
class book {
public:
int a;
int b;
std::string cb;
book(int a, int b, const char* cb)
: a(a),
b(b),
cb(cb)
{
}
};
int main()
{
using namespace std;
const book test(5, 17, "Woot!");
cout << "Hello " << test.cb << endl;
return 0;
}
$main
Hello Woot!
Вы также можете определить параметр cb как тип std::string
Использование const для элементов данных - не лучшая идея
@ M.M Почему это? Думаю наоборот. Используйте const по умолчанию, если вы не чувствуете, что вам нужно иметь возможность что-то изменить в какой-то момент (и, похоже, в этом нет необходимости).
@LightnessRacesinOrbit делает класс не назначаемым
@ M.M. Вы говорите так, будто это изначально плохо.
Конечно, если вы хотите поместить это в контейнер, я полагаю, вам лучше использовать изменяемые, но частные члены, которые не могут быть изменены через предоставленный API.
Да ладно хорошо ^ _ ^
cb- это массив, а не указатель, и его нельзя присвоить. Это буквально память, которая уже выделена для вас внутри структуры, и вы получаете ключ ко всему. Это похоже на «Вот, я купил дом, он находится на Wayway Ave 39», и ваша жена говорит: «Отлично, вы можете просто переместить его через улицу на Wayway Ave 40?» Если вам нужен указатель, который вы можете назначить, вместо этого используйтеchar *cb.