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

Ваш аккаунт

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

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

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

C++, функция. работающая с массивами

52K
01 ноября 2009 года
Гаечка
4 / / 25.10.2009
помогите, пожалуйста, компилятор показывает ошибку:
error C2664: 'mas' : cannot convert parameter 1 from 'short' to 'short [][3]'.
я понимаю, что ошибка, скорее всего, элементарная, но не могу найти


//Написать функцию, которая для заданных двухмерных массивов А, В
// и С типа double одинаковой размерности вычисляет массив D по
//формуле Di,j = Ai,j+ Bi,j*Ci,j

#include "stdafx.h"
#include <stdlib.h>
#include <iostream.h>

void mas (short A[3][3],short B[3][3],short C[3][3])
{
short D[3][3];
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
D[j]=A[j]+B[j]*C[j];
cout<<D[j]<<"\t";
}
cout<<"\n";
}
}

void main()
{
short M[3][3];
short N[3][3];
short K[3][3];
short L[3][3];
int i,j;
cout<<"massiv M\n";
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
M[j]=rand()%100;
cout<<M[j]<<"\t";
}
cout<<"\n";
}
cout<<"\n";

cout<<"massiv N\n";
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
N[j]=rand()%100;
cout<<N[j]<<"\t";
}
cout<<"\n";
}
cout<<"\n";

cout<<"massiv K\n";
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
K[j]=rand()%100;
cout<<K[j]<<"\t";
}
cout<<"\n";
}
cout<<"\n";

mas(M[3][3],N[3][3],K[3][3]);
}
47K
01 ноября 2009 года
Cka3o4HuK
31 / / 21.10.2009
Я сам в программировании недавно и возможно буду не прав в тонкостях, но суть думаю передам =)
Цитата:
cannot convert parameter 1 from 'short' to 'short [][3]'


Компилятор не может преобразовать конкретное значение типа short к массиву типа short

Цитата:
mas(M[3][3],N[3][3],K[3][3]);


Этим вы передаете в функцию mas не сами массивы, а только значения элементов, имеющих индекс 3, по сколько в ваших массивах всего три элемента(0,1,2, т.е. максимальный индекс равен 2), то скорее всего вы передаете в функцию какое-то значение из не вашей области памяти - мусор.
Правильная передача массивов в функцию будет так:

 
Код:
mas(M,N,K);

По заданию указано тип массивов double, а у вас short =)
20K
02 ноября 2009 года
sem2711
124 / / 23.09.2009
Предлагаю вам пересмотреть объявления массивов. Связано это с тем, что компилятор воспринимает имя массива как указатель на начальный элемент. Поскольку мы имеем дело с массивом массивов, то начальным элементом будет тоже указатель на первый элемент вложенного массива. Поэтому K является массивом указателей. Это влечет за собой ряд изменений. Например, не нужно выводить результирующий массив в теле функции mas() - он никуда не денется и по завершении ее работы. Вместо этого необходимо передать указатель на результирующий массив (который, кстати, объявлен у вас как L, но не используется) в функцию. В список параметров mas() необходимо добавить размеры массивов - а их, в свою очередь, объявить константами в main(). Инициализация массивов несколько усложняется, но работать будет правильно. В индексации массива на первом месте идет вертикаль (то есть y или j), а на втором - горизонталь (x или i). Поэтому при обращении к отдельным элементам буквы надо поменять местами (K[j]). В условии сказано, что массивы должны иметь тип double, но при инициализации через rand() это не имеет смысла. Однако, если элементы массива читать из файла или с клавиатуры, то тип short пользователя может не устроить. Поэтому в своем варианте оставил double на всякий случай. Ну, и в заключении, освободить выделенную из кучи память. Вот мой вариант с учетом вышесказанного:
Код:
#include <iostream>
#include <cstdlib>
#include <ctime>

void mas(double** A, double** B, double** C, double** D,
            const int x, const int y)
{
    for (int j = 0; j < y; ++j)
    {
        for (int i = 0; i < x; ++i)
        {
            D[j] = A[j] + B[j] * C[j];
        }
    }
}

int main()
{
    using std::cout;
    // srand() устанавливает начальную точку
    // для генерации псевдослучайных чисел
    srand((unsigned)(time(0)));
    // задаем размеры массивов
    const int size_x = 3;
    const int size_y = 3;

    double** M = new double*[size_y];
    double** N = new double*[size_y];
    double** K = new double*[size_y];
    double** L = new double*[size_y];
   
    int i, j;

    for (j = 0; j < size_y; ++j)
    {
        M[j] = new double[size_x];
        N[j] = new double[size_x];
        K[j] = new double[size_x];
        L[j] = new double[size_x];
    }

    cout << "massiv M\n";
    for (j = 0; j < size_y; ++j)
    {
        for (i = 0; i < size_x; ++i)
        {
            M[j] = (double)(rand() % 100);
            cout << M[j] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';

    cout << "massiv N\n";
    for (j = 0; j < size_y; ++j)
    {
        for (i = 0; i < size_x; ++i)
        {
            N[j] = (double)(rand() % 100);
            cout << N[j] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';

    cout << "massiv K\n";
    for (j = 0; j < size_y; ++j)
    {
        for (i = 0; i < size_x; ++i)
        {
            K[j] = (double)(rand() % 100);
            cout << K[j] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';

    mas(M, N, K, L, size_x, size_y);
    // вывод результирующего массива
    cout << "massiv L\n";
    for (j = 0; j < size_y; ++j)
    {
        for (i = 0; i < size_x; ++i)
        {
            cout << L[j] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';
    // освобождаем память
    for (j = 0; j < size_y; ++j)
    {
        delete [] M[j];
        delete [] N[j];
        delete [] K[j];
        delete [] L[j];
    }
    delete [] M;
    delete [] N;
    delete [] K;
    delete [] L;

    return 0;
}

PS Забыл еще сказать по поводу заголовков. Не знаю зачем вам понадобился stdafx.h - возможно вы использовали прекомпиляцию, но это с большей эффективностью будет работать при использовании MFC. А вот iostream.h и stdlib.h в стандарт C++ не входят. Это хедеры из C, которые оставили для совместимости. А в С++ нужно использовать соответствующие стандарту iostream и cstdlib и пространство имен std.
47K
02 ноября 2009 года
Cka3o4HuK
31 / / 21.10.2009
Если человек использует статические массивы, зачем предлагать ему решения с использованием динамической памяти? Если бы необходимо было использовать динамический двумерный массив, то скорее всего именно так в задании и было бы написано =)
Цитата:
В индексации массива на первом месте идет вертикаль (то есть y или j), а на втором - горизонталь (x или i). Поэтому при обращении к отдельным элементам буквы надо поменять местами (K[j]).


Так вот наверное то, что так хотел рассказать человек в вот этой теме

20K
02 ноября 2009 года
sem2711
124 / / 23.09.2009
Цитата: Cka3o4HuK
Если человек использует статические массивы, зачем предлагать ему решения с использованием динамической памяти?


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

Код:
#include <iostream>
#include <cstdlib>
#include <ctime>

// задаем размеры массивов
const int size_x = 3;
const int size_y = 3;

void mas(double A[][size_x], double B[][size_x],
         double C[][size_x], double D[][size_x])
{
    for (int j = 0; j < size_y; ++j)
    {
        for (int i = 0; i < size_x; ++i)
        {
            D[j] = A[j] + B[j] * C[j];
        }
    }
}

int main()
{
    using std::cout;
    // srand() устанавливает начальную точку
    // для генерации псевдослучайных чисел
    srand((unsigned)(time(0)));
   
    double M[size_y][size_x];
    double N[size_y][size_x];
    double K[size_y][size_x];
    double L[size_y][size_x];

    int i, j;

    cout << "massiv M\n";
    for (j = 0; j < size_y; ++j)
    {
       
        for (i = 0; i < size_x; ++i)
        {
            M[j] = (double)(rand() % 100);
            cout << M[j] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';

    cout << "massiv N\n";
    for (j = 0; j < size_y; ++j)
    {
        for (i = 0; i < size_x; ++i)
        {
            N[j] = (double)(rand() % 100);
            cout << N[j] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';

    cout << "massiv K\n";
    for (j = 0; j < size_y; ++j)
    {
        for (i = 0; i < size_x; ++i)
        {
            K[j] = (double)(rand() % 100);
            cout << K[j] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';
   
    mas(M, N, K, L);

    // вывод результирующего массива
    cout << "massiv L\n";
    for (j = 0; j < size_y; ++j)
    {
        for (i = 0; i < size_x; ++i)
        {
            cout << L[j] << '\t';
        }
        cout << '\n';
    }
    cout << '\n';

    return 0;
}
3
03 ноября 2009 года
Green
4.8K / / 20.01.2000
Цитата: sem2711
Предлагаю вам пересмотреть объявления массивов. Связано это с тем, что компилятор воспринимает имя массива как указатель на начальный элемент.


Это не так.
Компилятор может неявно преобразовывать массив к указателю на первый элемент этого массива.
Но это не значит, что "компилятор воспринимает имя массива как указатель".
Массив самостоятельный тип данных, который может быть использован, в т.ч. передан в функцию без преобразования к указателю на первый элемент. Т.к. сам тип содержит свою размерность, то в этом случае нет необходимости передавать количество элементов отдельным параметром.
Единственное ограничение, что массив должен передаваться по ссылке, а не по значению, т.к. он не имеет конструктора копирования.

Я уже как-то подробно рассказывал об этом. Воспользуйтесь поиском.

20K
03 ноября 2009 года
sem2711
124 / / 23.09.2009
Цитата: Green
Т.к. сам тип содержит свою размерность, то в этом случае нет необходимости передавать количество элементов отдельным параметром.


В контексте данного решения, думаю, все же это необходимо. Каким же образом можно организовать расчет элементов массива в цикле, если функция не знает о том, сколько в массиве элементов? В примере с размещением массивов в статической области памяти я не передаю размеры массива, т.к. они объявлены глобально (иначе ведь никак нельзя, кроме использования пространства имен?).

87
03 ноября 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Green
Я уже как-то подробно рассказывал об этом. Воспользуйтесь поиском.


Легко сказать...
Вот. Вроде нашел:
http://forum.codenet.ru/showpost.php?p=205152&postcount=44

Ну и поигрался для тренировки:

Код:
#include <iostream>

using namespace std;

template<class T, int N, int M>
void Test(const T(&)[N][M])
{
    cout << "This is an array of " << N << " x " << M << " elements" << endl;
}

template<class T>
void Test(const T&)
{
    cout << "This is not array" << endl;
}

template<class T, int N, int M>
void Fill(T(& a)[N][M])
{
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < M; ++j)
            a[j] = (i + 2) * 10 + j + 1;
}

template<class T, int N, int M>
void Print(const T(& a)[N][M])
{
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < M; ++j)
            cout << a[j] << " ";
        cout << endl;
    }
}

int main()
{
    int a[3][4];
    Test(a);

    int *b;
    Test(b);

    Fill(a);
    Print(a);
   
    return 0;
}
20K
03 ноября 2009 года
sem2711
124 / / 23.09.2009
Цитата: Kogrom
Легко сказать...


Спасибо за находку! Подчерпнул для себя немало. Вот только применить эти знания в данной задаче не смог. С оператором sizeof все понятно: функция получает не массив, а указатель. (sizeof(A)/sizeof(A[0][0]) в списке параметров функции не работает.

Цитата:
массив должен передаваться по ссылке, а не по значению

Не знаю как передать массив по ссылке :confused:

87
03 ноября 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: sem2711
Вот только применить эти знания в данной задаче не смог.


Как-то так:

Код:
#include <iostream>
#include <cstdlib>
#include <ctime>

using std::cout;
using std::endl;

template<class T, int N, int M>
void mas(T(& A)[N][M], T(& B)[N][M],
         T(& C)[N][M], T(& D)[N][M])
{
    for (int j = 0; j < N; ++j)
    {
        for (int i = 0; i < M; ++i)
        {
            D[j] = A[j] + B[j] * C[j];
        }
    }
}

template<class T, int N, int M>
void FillMass(T(& a)[N][M])
{
    for (int j = 0; j < N; ++j)
        for (int i = 0; i < M; ++i)
            a[j] = (double)(rand() % 100);
}

template<class T, int N, int M>
void PrintMass(T(& a)[N][M])
{
    for (int j = 0; j < N; ++j)
    {
        for (int i = 0; i < M; ++i)
            cout << a[j] << '\t';
        cout << endl;
    }
    cout << endl;
}

int main()
{
    // srand() устанавливает начальную точку
    // для генерации псевдослучайных чисел
    srand((unsigned)(time(0)));

    const int size_x = 3;
    const int size_y = 3;

    double M[size_y][size_x];
    double N[size_y][size_x];
    double K[size_y][size_x];
    double L[size_y][size_x];

    FillMass(M);
    cout << "massiv M\n";
    PrintMass(M);

    FillMass(N);
    cout << "massiv N\n";
    PrintMass(N);

    FillMass(K);
    cout << "massiv K\n";
    PrintMass(K);

    mas(M, N, K, L);

    // вывод результирующего массива
    cout << "massiv L\n";
    PrintMass(L);

    return 0;
}

Не всё дублирование и мешанину стилей убрал, но не в том суть. sizeof тут не нужен. Тут работает другой финт с компилятором - хитрое использование шаблонов. Шаблон типа T можно убрать в этой задаче, используя простое double.
12K
03 ноября 2009 года
Ghox
297 / / 26.07.2009
Цитата: Green
Единственное ограничение, что массив должен передаваться по ссылке, а не по значению, т.к. он не имеет конструктора копирования.


Цитата: sem2711
Не знаю как передать массив по ссылке :confused:


Полагаю, что в той фразе участника Green имелось в виду:
В случае передачи обычной переменной (не являющейся массивом) есть возможность выбора, передавать по ссылке или по значению:

 
Код:
void func1(int n) // передача по значению
{ ... }
void func1(int& n) // передача по ссылке
{ ... }
...
    int n = 10;
    func1(n); // по значению
    func2(n); // по ссылке

В случае же передачи в функцию массива такой возможности выбора нет - передавать массив можно только по ссылке. Т.е. когда вы делаете такой вызов функции:
 
Код:
void func3(int mas[])
{ ... }
...
    int a[10];
    // заполнение a
    func3(a);

Вы передаете массив именно по ссылке, а не по значению, несмотря на то что знак & в функции не пишете.
3
03 ноября 2009 года
Green
4.8K / / 20.01.2000
Цитата: Ghox

Т.е. когда вы делаете такой вызов функции:
 
Код:
void func3(int mas[])
{ ... }
...
    int a[10];
    // заполнение a
    func3(a);

Вы передаете массив именно по ссылке, а не по значению, несмотря на то что знак & в функции не пишете.


Нет.
В данном примере ты передаешь по указателю на первый элемент, т.к. запись int mas[] равнозначна записи int* mas.

Передача массива по ссылке выглядит так (используется именно знак &):

 
Код:
void func3(int(&mas)[10])
{ ... }
...
    int a[10];
    // заполнение a
    func3(a);
20K
03 ноября 2009 года
sem2711
124 / / 23.09.2009
Цитата: Kogrom

Шаблон типа T можно убрать в этой задаче, используя простое double.


В том-то и дело, что нельзя! Ведь размеры массива как раз и передаются в функцию в виде параметров шаблона. Как тогда должно выглядеть объявление функции?

 
Код:
void mas(double (&A)[][], double (&B)[][],
         double (&C)[][], double (&D)[][]);

Это, конечно, приводит к ошибке компиляции:
 
Код:
error: declaration of ‘A’ as multidimensional array must have bounds for all dimensions except the first

Цитата:
Передача массива по ссылке выглядит так (используется именно знак &):
Код:
void func3(int(&mas)[10])
{ ... }


Насколько я понимаю, возможны два варианта (кроме широко известных):
1. передача в шаблонную функцию, которая в качестве параметров типа принимает размеры массива;
2. передача по ссылке с прямым указанием размера массива (ну, или через глобальную переменную).

87
03 ноября 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: sem2711
В том-то и дело, что нельзя! Ведь размеры массива как раз и передаются в функцию в виде параметров шаблона. Как тогда должно выглядеть объявление функции?
 
Код:
void mas(double (&A)[][], double (&B)[][],
         double (&C)[][], double (&D)[][]);

Это, конечно, приводит к ошибке компиляции


Я не говорил, что шаблон надо убрать совсем. Я говорил про такое:

 
Код:
template<int N, int M>
void mas(double (&A)[N][M], double (&B)[N][M],
         double (&C)[N][M], double (&D)[N][M]){/* ... */}

Тут нету шаблона типа T.
Цитата: sem2711
Насколько я понимаю, возможны два варианта (кроме широко известных):
1. передача в шаблонную функцию, которая в качестве параметров типа принимает размеры массива;
2. передача по ссылке с прямым указанием размера массива (ну, или через глобальную переменную).


Ну и правильно. В варианте с шаблоном компилятор сам подставит размер массива, если я правильно понимаю механизм этой фишки. То есть, мы напишем только одну функцию для массивов разных размеров, а компилятор сделает из них несколько.

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