#c
Вопрос:
Я недавно перешел с c на c и просто не могу понять, что я здесь делаю не так. Я хотел бы получить доступ и установить элемент карты с помощью другой функции.
Вот мой пример, который вы можете просто скопировать в cpp.sh или так, если хотите
#include lt;iostreamgt; #include lt;mapgt; using namespace std; struct test{ int i; int j; }; void addValues(test* val){ if (val == NULL){ val = new test(); coutlt;lt;"new"; } val-gt;i = 10; val-gt;j = 12; } void printVal(test* val){ coutlt;lt;"finish " lt;lt; val-gt;i lt;lt; " " lt;lt; val-gt;j; } int main() { maplt;string, test*gt; bla = {{"test1",NULL}}; addValues(bla.at("test1")); printVal(bla.at("test1")); return 0; }
код из моего проекта немного сложнее, но в основном это проблема. Я создал тест в addValues() и не удалил его. Почему я не могу напечатать это значение в printVal()? Что я упускаю?
Заранее спасибо!
Комментарии:
1. По той же причине, которая
val = malloc(sizeof(test));
не будет работать в C. Указатели передаются по значению, вам необходимо передавать по ссылке, если вы хотите, чтобы изменения переменной были видны вне функции2. Что ж, в более современном C даже использование new/delete больше не рекомендуется. А для строк есть std::строка. Вскоре я покажу небольшой пример
3.
std::map
здесь это не имеет значения,test* t = nullptr; addValues(t);
приведет к той же проблеме.4. Вы говорите, что отображаете «элемент с помощью указателя» в своем вопросе. Но ваш код нигде не содержит указателя на элемент карты. Ты имел в виду
maplt;string, testgt;
и нетmaplt;string, test*gt;
?
Ответ №1:
Параметры передаются по значению. Указатели не являются исключением из этого правила. Вы addValues
изменяете локальную копию указателя при nullptr
передаче a. Изменение этой локальной копии не влияет на указатель на карте. Передайте указатель по ссылке:
void addValues(test*amp; val){ if (val == nullptr){ val = new test(); coutlt;lt;"new"; } val-gt;i = 10; val-gt;j = 12; }
Или еще лучше, не используйте необработанные указатели в первую очередь. Кроме того, подумайте о том, чтобы написать конструктор, который инициализирует члены test
вместо того, чтобы полагаться на вызывающего для их инициализации.
Ответ №2:
Пример :
#include lt;iostreamgt; #include lt;mapgt; //using namespace std; NO teach yourself not to do this. struct test { int i = 0; // lt;== in c you can initialize values of structs int j = 0; }; // this instead of printVal std::ostreamamp; operatorlt;lt;(std::ostreamamp; os, const testamp; t) { os lt;lt; "i = " lt;lt; t.i lt;lt; ", j = " lt;lt; t.j lt;lt; "n"; return os; } int main() { std::maplt;std::string, testgt; map = { {"test1",{1,1}}, {"test2",{2,2}}, }; // loop over all entries in the map // range based for loop. // each entry in the map is a key,value pair (not they key, not the value but a pair) // https://en.cppreference.com/w/cpp/language/range-for std::cout lt;lt; "range based for over keyvalue pairsn"; for (const autoamp; kv : map) { // note kv.second is where we use operatorlt;lt; from earlier. std::cout lt;lt; "Key : " lt;lt; kv.first lt;lt; ", value : " lt;lt; kv.second lt;lt; "n"; } std::cout lt;lt; "n"; // structured bindings make code more readable // https://en.cppreference.com/w/cpp/language/structured_binding std::cout lt;lt; "range based for using structured bindings n"; for (const autoamp; [key, value] : map) { std::cout lt;lt; "Key : " lt;lt; key lt;lt; ", value : " lt;lt; value lt;lt;"n"; } std::cout lt;lt; "n"; return 0; }