Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> передать массив в функцию 
:(
    Опции темы
mrgloom
Дата 20.8.2013, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



передаю в функцию NULL, в функции выделяю память и хочу вернуть обратно измененный массив.

Код

//так не работает
void test_func(char* mask)
{
    int sz=23;
    mask= new char[sz];
    mask[10]=13;
}

//так работает
void test_func(char*& mask)
{
    int sz=23;
    mask= new char[sz];
    mask[10]=13;
}

//сам код
        char* p= NULL;
        test_func(p);
        if(p[10]==13)
            int f=0;


не могу понять почему, ведь я передаю указатель, причем когда память выделяется "сверху" функции, то всё как и ожидается

т.е. когда 
Код

void test_func(char* mask)
{
    mask[10]=13;
}
char* p = new char[sz];
test_func(p);
if(p[10]==13)
int f=0;


Добавлено @ 14:17
Код

void test_func(char** mask)
{
    int sz=23;
    *mask= new char[sz];
    (*mask)[10]=13;
}

так тоже работает.


или это всё специфика передачи массива?

Это сообщение отредактировал(а) mrgloom - 20.8.2013, 14:54
PM MAIL   Вверх
bsa
Дата 20.8.2013, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



mrgloom, указатель, фактически, это такая переменная, которая хранит адрес. Когда ты вызываешь какую-то функцию и передаешь ей какой-то параметр, то в ней создается новая переменная (имя и тип ее указаны в скобках после имени функции), которой присваивается переданное в качестве параметра значение. Таким образом, когда ты меняешь эту переменную, ты меняешь только ее, а не источник значения на входе функции.
когда ты указываешь программе использовать ссылку или указатель на переменную (в твоем случае переменная - указатель на char), то ты можешь поменять значение источника.
PM   Вверх
SenkraD
Дата 20.8.2013, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 3.2.2006
Где: Украина::Киев

Репутация: нет
Всего: 23



Код

void test_func(char* mask)
{
    int sz=23;
    mask= new char[sz];
    mask[10]=13;
}

дело в том mask - это копия указателя. тоесть она указывает туда же, куда и оригинальный, но адресс у него другой, тоесть это другой указатель:
Код

#include <cstddef>
#include <iostream>

void print(char* data)
{
    std::cout << __FUNCTION__ << std::endl;
    std::cout << "Address of data: " << &data << std::endl;
    std::cout << "Value of data: "   << data << std::endl;
}

int main(int argc, char* argv[])
{
    char* data = "some my data";

    std::cout << __FUNCTION__ << std::endl;
    std::cout << "Address of data: " << &data << std::endl;
    std::cout << "Value of data: "   << data << std::endl;

    std::cout << std::endl;
    print(data);

    return 0;
}


Вывод:
Код
main
Address of data: 0012FF60
Value of data: some my data

print
Address of data: 0012FE8C
Value of data: some my data


Это сообщение отредактировал(а) SenkraD - 20.8.2013, 14:55


--------------------
 Имеющий язык - да не убоится спросить! 
user posted image
PM MAIL ICQ   Вверх
mrgloom
Дата 20.8.2013, 15:03 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



ну это всё понятно, вопрос как передать указатель на пустой массив, внутри функции выделить память для него, заполнить и потом выдать обратно(чтобы переданный указатель указывал но новый массив).

получается что нужно передавать указатель по ссылке? или указатель на указатель?

вообщем тут вот ответ
http://www.codeproject.com/Articles/4894/P...ence-to-Pointer

получается что передавая указатель на массив мы можем изменять начинку массива, но не можем изменять переданный указатель, а при выделении памяти заново внутри функции мы как раз меняем указатель. 
PM MAIL   Вверх
SenkraD
Дата 20.8.2013, 15:09 (ссылка)  | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 3.2.2006
Где: Украина::Киев

Репутация: нет
Всего: 23



кстати, это не мешает вам удалить то, на что указывает указатель:
Код

template <typename T>
void deleter(T* pointer)
{
    delete pointer;
}
но лучше таки так:
Код

template <typename T>
void deleter(T*& pointer)
{
    delete pointer;
    pointer = NULL;
}


Это сообщение отредактировал(а) SenkraD - 20.8.2013, 15:09


--------------------
 Имеющий язык - да не убоится спросить! 
user posted image
PM MAIL ICQ   Вверх
bsa
Дата 20.8.2013, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(SenkraD @  20.8.2013,  16:09 Найти цитируемый пост)
но лучше таки так:
по-хорошему, лучше так не делать. Удалять надо там же, где и выделять. Иначе потом можно кучу проблем огрести.
mrgloom, посмотри описание функции realloc. Такой подход тоже можно использовать.
PM   Вверх
SenkraD
Дата 20.8.2013, 15:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 3.2.2006
Где: Украина::Киев

Репутация: нет
Всего: 23



Цитата(bsa @  20.8.2013,  15:16 Найти цитируемый пост)
по-хорошему, лучше так не делать. Удалять надо там же, где и выделять. Иначе потом можно кучу проблем огрести.

ну это с тех времен, когда смарт поинтеры еще были не так популярны или их нельзя было использовать или их не было в проекте. Плюс несколько раз приходилось писать кустомный делетеры для boost::shared_ptr


--------------------
 Имеющий язык - да не убоится спросить! 
user posted image
PM MAIL ICQ   Вверх
bsa
Дата 20.8.2013, 15:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



SenkraD, мое замечание в основном касалось конкретного примера. Естественно, что при использовании умных указателей заморачиваться не надо (хотя, если память выделяется в библиотеке, то и освобождаться должна там же).
PM   Вверх
SenkraD
Дата 20.8.2013, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 3.2.2006
Где: Украина::Киев

Репутация: нет
Всего: 23



Ну, собсвенно,  такие функции часто бывают в библиотеках:
Код

void destroy(some_type* some_object);
так как память должна освождаться там, где выделяется + нужна, зачастую,  для  поддержки binary interface compatibility


--------------------
 Имеющий язык - да не убоится спросить! 
user posted image
PM MAIL ICQ   Вверх
NoviceF
Дата 21.8.2013, 07:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: 2
Всего: 2



Цитата(mrgloom @  20.8.2013,  16:03 Найти цитируемый пост)
получается что нужно передавать указатель по ссылке? или указатель на указатель?


Тоже относительно недавно узнал об этой возможности.. Как-то в книгах такая конструкция не особо встречается, ну или, по крайней мере, не бросается в глаза.
PM MAIL   Вверх
mrgloom
Дата 21.8.2013, 08:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



как раз с delete[] похоже и выявилась проблема, долго не мог понять в чем дело, потом нашел


Цитата

    Deleting memory twice (especially likely if you copy pointers around)
    Deleting a pointer that was never initialized
    Deleting a pointer that was assigned to garbage
    Deleting a pointer to memory that was allocated with something other than new
    Deleting a pointer that points to an item not on the heap (i.e. an item on the stack or a global variable)
    If you have an array of pointers, deleting a pointer off the end of the array
    Deleting a pointer that was allocated from another instance of the C++ runtime (e.g. calling new from a DLL and delete from the main exe or visa versa)
    Calling delete[] on memory allocated with new.  Calling delete on memory allocated with new[] (These may not always crash, but it is still wrong and undefined behavior). 


похоже в моем случае это связано как раз с dll, как решаются такие проблемы?

самое простое вроде как передавать std::vector<std::vector<char>>

еще заметил что если сделать так
Код

char* p = new char[10];
p[0]=0; 

то массив вроде как зануляется (?) , а я всего лишь хотел приравнять первый элемент к нулю. это наверно связано с тем, что массив char воспринимается как строка? 
PM MAIL   Вверх
SenkraD
Дата 21.8.2013, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 3.2.2006
Где: Украина::Киев

Репутация: нет
Всего: 23



Цитата(mrgloom @  21.8.2013,  08:42 Найти цитируемый пост)
то массив вроде как зануляется (?) , а я всего лишь хотел приравнять первый элемент к нулю. это наверно связано с тем, что массив char воспринимается как строка? 

ну да дебагер ее видит как строку, но сам массив не зануляется.


Цитата(mrgloom @  21.8.2013,  08:42 Найти цитируемый пост)
похоже в моем случае это связано как раз с dll, как решаются такие проблемы?

в чем именно это выраженно? общее правило при работе с dll такие:
  • типы линковки в dll и модуле, который ее использует должны совпадать
  • память, выделяется в dll, должна в ней и освобождаться: например: T* getObject() и void destroyObject(T* object)
  • не возвращаем с интерфейсов dll STL контейнеры, уоторые можно изменять не средствами dll
после delete/delete[] указателю лучше присваивать NULL/nullptr, если возможен даблделит, так как их удаленние определенно стандартом и считается валидным

Это сообщение отредактировал(а) SenkraD - 21.8.2013, 11:14


--------------------
 Имеющий язык - да не убоится спросить! 
user posted image
PM MAIL ICQ   Вверх
xvr
Дата 21.8.2013, 11:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(mrgloom @  20.8.2013,  15:03 Найти цитируемый пост)
ну это всё понятно, вопрос как передать указатель на пустой массив, внутри функции выделить память для него,

Никак. В С и С++ массив (точнее область памяти), выделенный с помощью new и/или malloc, уже не может изменить свой размер. Так что сколько вы ему памяти при создании дали, столько в нем и будет, и никакая функция этого изменить не сможет.
Что же касается функции realloc, то она как ни странно не увеличивает размер массива, а содает новый массив (по другому адресу), и копирует в него содержимое старого массива. Т.е. адрес массива после нее может измениться.

PM MAIL   Вверх
akizelokro
Дата 24.8.2013, 13:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Цитата

Никак. В С и С++ массив (точнее область памяти), выделенный с помощью new и/или malloc, уже не может изменить свой размер. 


Добавлено через 3 минуты и 56 секунд
Цитата(xvr @  21.8.2013,  11:25 Найти цитируемый пост)
Что же касается функции realloc, то она как ни странно не увеличивает размер массива, а содает новый массив (по другому адресу), и копирует в него содержимое старого массива. Т.е. адрес массива после нее может измениться.


А может и не измениться

Добавлено через 7 минут и 45 секунд
И вообще здесь начните с объяснения, как в С просто передаются параметры в функцию.

Я просто навскидку уже знаю один вариант, как менять содержмое массива внутри функции, даже не передавая туда значение. С помощью глобальных переменных и решая вопрос с, например, видеопамятью, которая начинается по фиксированному адресу.

Добавлено через 13 минут и 51 секунду
Цитата(mrgloom @  20.8.2013,  14:10 Найти цитируемый пост)
передаю в функцию NULL, в функции выделяю память и хочу вернуть обратно измененный массив.


сам стиль плох. потому что вызовом new(malloc и т.д.) уже в одну строчку выделяется память

Это сообщение отредактировал(а) akizelokro - 24.8.2013, 13:59


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
aleksandrkr
  Дата 19.9.2013, 14:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



давай мыслить логически как выглядит переменная. переменная состоит из двух частей [адрес в памяти][значение]
передаётся в функцию по копии то есть, создаётся копия переменной.
что такое указатель это тоже самое, только во второй части у него лежит адрес.
что передаётся в функцию если переменная ровна нулю, правильно делается копия. но значение у нас ноль [адрес в памяти][NULL];
в это 0 мы выделяем память, то есть там не ноль а адрес. вот тут и получается прикол что твоя переменная ( p ) понятия не имеет о выделенной памяти у неё значение 0;
в копию мы выделили память а в переменной так и осталось значение 0;
рассуждаем дальше что нам надо для того чтоб можно было выделить память, нужно сделать указатель на указатель
то есть нужно чтоб сюда в значение попал адрес переданной переменной [адрес в памяти][значение]. и получается что-то такого типа [адрес копии][адрес переданного указателя][значение переданного указателя (не копия)]. вот вам два способа как этого добиться:

Код

C:

void f(int** p)
{
  (*p) = new int(10);
}

C++:

void f(int*& p)
{
  p = new int(10);
} 

 smile 

Это сообщение отредактировал(а) aleksandrkr - 19.9.2013, 14:17
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0577 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.