Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Как передать в функцию указатель на двумерный символьный массив?

68K
03 июня 2013 года
BlGhost
24 / / 25.11.2012
При передаче массива в функцию выдается ошибка: : cannot convert parameter 1 from 'char [10][20]' to 'char **'


Код:
void Function(char **plugs, int size);

void main(void)
{
    int i;
    const int Size=10;
    char Plug[Size][20];

    Function(Plug, Size);
    for(i=0; i<Size; i++)
        printf("\r\n %d \r\n",Plug[i]);


     _getch();

}

void Function(char **plugs, int size)
{      
        char str[10];
        for(int i=0; i<size; i++)
        {  
            sprintf(str," %d",i);
            strcpy(plugs[i], str);
        }
};
Подскажите в чем ошибка. Спасибо!
326
03 июня 2013 года
sadovoya
757 / / 19.11.2005
Имя вашего массива -- адрес головного символа, т.е. одинарный указатель. Вам нужен указатель на указатель, например, массив указателей. Это легко делается, например, с динамическим выделением памяти.


 
Код:
char** Cells;
.....
Cells = new char* [N1];

for (i = 0; i < N1; i++) {
         Cells[i] = new char[N2];
    }
В этом примере Cells можно передать в ф-цию, ожидающую char**

P.S. Вот еще пример, в C-стиле и с дин. выделением памяти только на одно из измерений.
326
04 июня 2013 года
sadovoya
757 / / 19.11.2005
ОФТОП, но может кому интересно. Маленький пример, чтобы разобраться как располагаются элементы двумерных массивов в памяти при статических и динамических способах задания. Тип данных выбран однобайтовым целым для удобства. Скомпилируйте и смотрите (в выходе данные и в скобках смещение адреса относительно головы массива).

Код:
//смещения адресов элементов относительно нулевого

#include <iostream>

using namespace std;

void prnt_adress(signed char**, int, int);

int main() {

    int i,j;

    const int N1 = 3;
    const int N2 = 2;

    const signed char src[N1][N2] = {
        {1, 2},
        {3, 4},
        {5, 6}
    };

    signed char array[N1][N2];
    signed char** Cells;
    signed char* ar[N1];


    Cells = new signed char* [N1];

    for (i = 0; i < N1; i++) {
        ar[i] = new signed char[N2];
        Cells[i] = new signed char[N2];
    }

    for (i = 0; i < N1; i++)
        for (j = 0; j < N2; j++) {
            array[i][j] = src[i][j];
            Cells[i][j] = src[i][j];
            ar[i][j] = src[i][j];
        }

    cout << "Значение ячейки (смещение адреса) в src\n";
    for (i = 0; i < N1; i++, cout << endl)
        for (j = 0; j < N2; j++, cout << '\t')
            cout << (int)src[i][j] << "(" <<
                 (&src[i][j]-&src[0][0]) << ")";

    cout << endl;

    cout << "Значение ячейки (смещение адреса) в array\n";
    for (i = 0; i < N1; i++, cout << endl)
        for (j = 0; j < N2; j++, cout << '\t')
            cout << (int)array[i][j] << "(" <<
                 (&array[i][j]-&array[0][0]) << ")";

    cout << endl;

    cout << "Значение ячейки (смещение адреса) в Cells\n";
    prnt_adress(Cells, N1, N2);

    cout << endl;

    cout << "Значение ячейки (смещение адреса) в ar\n";
    prnt_adress(ar, N1, N2);

    for (i = 0; i < N1; i++) {
        delete[] ar[i];
        delete[] Cells[i];
    }
    delete[] Cells;

    return 0;
}

void prnt_adress(signed char** ar2d, int k1, int k2) {
    for (int i = 0; i < k1; i++, cout << endl)
        for (int j = 0; j < k2; j++, cout << '\t')
            cout << (int)ar2d[i][j] << "(" <<
                 (&ar2d[i][j]-&ar2d[0][0]) <<
                 ")";
};
414
04 июня 2013 года
CassandraDied
763 / / 24.05.2012
Функция ожидает char **, значит, ей надо передать char **, а не двумерный массив. Иначе необходимо вызывать преобразование типа.
326
04 июня 2013 года
sadovoya
757 / / 19.11.2005
Преобразование типа не поможет. Свой массив вы как char** не передадите. Либо char* ar[N], либо, как приведено с Cells.
341
04 июня 2013 года
Der Meister
874 / / 21.12.2007
 
Код:
template <int count, int length>
void Foo(char (&plugs)[count][length]) {
    char str[length];
    for(int i = 0; i < count; i++)
    {  
        sprintf(str," %d",i);
        strcpy(plugs[i], str);
    }
}
414
04 июня 2013 года
CassandraDied
763 / / 24.05.2012
Цитата: sadovoya
Преобразование типа не поможет. Свой массив вы как char** не передадите. Либо char* ar[N], либо, как приведено с Cells.


В каком смысле не поможет? Ошибки компиляции не будет? Не будет.

414
04 июня 2013 года
CassandraDied
763 / / 24.05.2012
Цитата: Der Meister
 
Код:
template <int count, int length>
void Foo(char (&plugs)[count][length]) {
    char str[length];
    for(int i = 0; i < count; i++)
    {  
        sprintf(str," %d",i);
        strcpy(plugs[i], str);
    }
}


А что это за интересное использование темплейтов?

341
04 июня 2013 года
Der Meister
874 / / 21.12.2007
Цитата: CassandraDied
А что это за интересное использование темплейтов?

Здесь, скорее, интересное использование вывода аргументов шаблона из использования - пожалуй, единственный способ не потерять информацию о типе при передаче массива в качестве аргумента. Можно принять за идиому.

326
05 октября 2014 года
sadovoya
757 / / 19.11.2005
Почти ОФТОП. Но, чтобы не пропадал исходник, может кому пригодится. Вычисление произведения положительных элементов двумерного динамического массива. Поможет с адресами разобраться и специально через арифметику указателей сделан.

Код:
//CODEC OF THIS FILE is Windows-1251

#include <clocale>
#include <cstdio>
#include <iostream>

using namespace std;

typedef double DATA_TYPE;

DATA_TYPE multi(DATA_TYPE **p, int k, int t);

int main() {
    setlocale(LC_ALL,"");
    const int m = 2, n = 3;
    DATA_TYPE **r;
    r = new DATA_TYPE*[m];
    cout << "Адреса одномерных массивов:" << endl;
    for (int i = 0; i < m; i++) {
        r[i] = new DATA_TYPE[n];
        cout << (unsigned)r[i] << endl;
    }
    cout << "Размер типа данных в байтах: " << sizeof(DATA_TYPE) << endl;
    DATA_TYPE k = -2.0;
    for (int i = 0; i < m; i++)
        for (int j = 0; j < n; j++) {
            r[i][j] = (k += 1.0, k);
            cout << "r[" << i << "][" << j << "] = " << r[i][j] <<
                 ", адрес: " << (unsigned)&(r[i][j]) << endl;
        }
    cout << endl << "Произведение: " << multi(r, m, n) << endl;
    for (int i = 0; i < m; i++)
        delete[]r[i];
    delete[]r;

    cout << endl << "Нажмите клавишу...";
    getchar();

    return 0;
}

DATA_TYPE multi(DATA_TYPE **p, int k, int t) {
    DATA_TYPE w = 1.0;
    for (int i = 0; i < k; i++)
        for (int j = 0; j < t; j++)
            //if (p[i][j]>0) w = w*p[i][j];
            if ( *(*(p+i)+j) >0 ) w *= *(*(p+i)+j); //то-же через указатели
            //адрес элемента получаем по адресу начала его одномерного массива
            //и положению элемента в нем
    return w;
}
Более правильно (по экономии вычислений), а кому-то и более понятно, если переписать функцию для произведения так:

 
Код:
DATA_TYPE multi(DATA_TYPE **p, int k, int t) {
    DATA_TYPE w = 1.0;
    const void* max_pp = p + k;
    for (DATA_TYPE** pp = p; pp < max_pp; pp++)
        for (int j = 0; j < t; j++)
            if ( *(*pp+j) >0 ) w *= *(*pp+j);
    return w;
}
Впрочем тут об оптимизации на скорость не особо старался.

Да, тут для 32-битных машин. Под 64-битные не трудно переделать.
326
01 ноября 2014 года
sadovoya
757 / / 19.11.2005
Цитата: Der Meister
Цитата: CassandraDied
А что это за интересное использование темплейтов?

Здесь, скорее, интересное использование вывода аргументов шаблона из использования - пожалуй, единственный способ не потерять информацию о типе при передаче массива в качестве аргумента. Можно принять за идиому.


На настоящую идиому наверно не тянет (в сравнении с RAII, например), но прием полезный.
Даже обычное использование ссылок на (статический) массив позволяет уйти от явной передачи размерности:

Код:
void fill_array(int (&ra)[10]) {
    const int cnt = sizeof(ra) / sizeof(ra[0]);
    for(int i = 0; i < cnt; ++i)
        ra[i] = i;
}

typedef int (&Ref_to_array)[10];

void fill_array2(Ref_to_array ra) {
    const int cnt = sizeof(ra) / sizeof(ra[0]);
    for(int i = 0; i < cnt; ++i)
        ra[i] = -i;
}
...
int C[10];
fill_array(C);
for(int i = 0; i < 10; ++i)
        printf("%d ", C[i]);
puts("");
fill_array2(C);
for(int i = 0; i < 10; ++i)
printf("%d ", C[i]);
Здесь размерность внутри функции становится доступной c помощью sizeof, что недоступно при передаче массива (указателя) обычной (с другой стороны она и так известна, определена в самом типе, ожидаемом функцией). Дополнительно имеем контроль размерности на этапе компиляции - не удастся передать массив иной размерности, чем ожидает функция.
Напрашивается вынести в константы размерность:

 
Код:
const int CNT = 10; //можно менять здесь без переделки кода
typedef int (&Ref_to_array)[CNT];
и использовать CNT в функции (без конструкций с sizeof). Раз так, то вспоминаем о параметрах шаблонов и с ними все становится гораздо изящней. Еще один пример с шаблоном и двумерным массивом:

 
Код:
template<int CNT1, int CNT2>
void fill_array3(int (&ra)[CNT1][CNT2]) {
    int k = 1;
    for(int i = 0; i < CNT1; ++i)
        for(int j = 0; j < CNT2; ++j)
            ra[i][j] = k++;
}
...
int C[2][3];
fill_array3(C); //даже не обязательно fill_array3<2,3> (автоматически выводятся)
Так что спасибо, Der Meister, за полезный пост.

P.S. C динамич. массивом (с помощью new созданного) не сработает. Например, такое не верно:

 
Код:
//Не будет работать как для стат. массива
//int *D = new int[10];
//fill_array(D);
//...
//delete [] D;
327
01 ноября 2014 года
UserNet2008
748 / / 03.04.2010
sadovoya Вы есть коммунист(ка) на кухня впрягаться в тему прошлого года. Там видно , что автору по барабану.
326
01 ноября 2014 года
sadovoya
757 / / 19.11.2005
Автору-то да, но тема давно ушла за рамки первоначального вопроса. Пост Der Meister-а выводит тему на более интересный уровень, может кто присоединится к обсуждению малоизвестных полезных приемов передачи массивов.
327
01 ноября 2014 года
UserNet2008
748 / / 03.04.2010
Ну тогда, по ответам +1
Цитата: sadovoya
Преобразование типа не поможет. Свой массив вы как char** не передадите. Либо char* ar[N], либо, как приведено с Cells.


Да-Да массив передаст значения ~~ char* ar[N].

326
01 ноября 2014 года
sadovoya
757 / / 19.11.2005
Спасибо, рад, что не зря "продвигал" эту тему. А то уж думал никому не интересно.
327
01 ноября 2014 года
UserNet2008
748 / / 03.04.2010
Цитата: sadovoya
Спасибо, рад, что не зря "продвигал" эту тему. А то уж думал никому не интересно.


Честно сказать , мне по кухне Ваши ответы ~~38 годов кнопаю клаву и сделал свою(карьеру), но что обидно я типа начальник (теперь)
Если не ошибаюсь русский певец ~~Полотно слова:
~~Я всё реже достаю свою гитару и всё реже пою. рекомендую послушать
Примерно так
Я всё реже достаю клаву и всё реже пишу код.
P/S
А.Полотно
На Севере
Снег разтаил

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог