#c #arrays #vector
#c #массивы #вектор
Вопрос:
Я не знаю почему, но он не возвращает двумерный массив, который я объявляю в функции.
char** canvas() {
char canvas[18][8];
fill(canvas[0], canvas[0] 18 * 8, 'O');
return canvas;
}
Комментарии:
1. Совет: Используйте
std::vector<int> of size
18 * 8` и эмулируйте его размерность. Альтернативой является ручное выделение памяти, которое в спешке превращается в кучу невеселых действий.2. Примечание:
char x[a][b]
никоим образом не совместим сchar**
. Один представляет собой двумерный массив, другой — указатель на массив указателей . Ваш компилятор должен сходить с ума. Если это не так, включите больше предупреждений, таких как-Wall
.3. Какой стандарт C вы используете?
Ответ №1:
canvas
является локальной переменной, ее время жизни истекает, когда функция выходит за пределы области видимости, обращение к этой переменной через указатель после этого вызовет неопределенное поведение.
Возвращаемый тип функции также несовместим с объектом, который вы пытаетесь вернуть.
Если вам необходимо использовать массивы в стиле C (выведенные из вашего комментария), вы можете сделать что-то вроде:
char (*canvas())[8] //pointer to array return type
{
char (*canvas)[8] = new char[18][8]; //C manual allocation
//std::fill(canvas[0], canvas[0] 18 * 8, 'O'); //works
std::fill_n(canvas[0], 18 * 8, 'O'); //better, as suggested by Ted Lyngmo
return canvas;
}
Затем вы можете вызвать его следующим образом:
int main()
{
char(*canv)[8] = canvas(); //assign it
for (int i = 0; i < 18; i ) //use it like a 2D array
{
for (int j = 0; j < 8; j )
{
std::cout << canv[i][j];
}
std::cout << std::endl;
}
delete[] canv; //delete object after it's used
}
Поскольку вы используете C , я бы предложил контейнер типа STL std::vector
, то есть вектор векторов std::vector<std::vector<char>>
, который вы также можете использовать std::array
, поскольку размеры известны во время компиляции, т. е. std::array<std::array<char, 8>, 18>
.
Для реализации на C std::array
:
std::array<std::array<char, 8>, 18> canvas()
{
std::array<std::array<char, 8>, 18> canvas;
std::fill_n(canvas.begin()->begin(), 18 * 8, 'O');
return canvas;
}
int main()
{
std::array<std::array<char, 8>, 18> canv = canvas();
//...
}
Для std::vector
реализации:
std::vector<std::vector<char>> canvas()
{
std::vector<std::vector<char>> canvas{18, std::vector<char>(8, '0')};
return canvas;
}
int main()
{
std::vector<std::vector<char>> canv = canvas();
//...
}
В обоих случаях вы можете использовать цикл в стиле C for
, как в первом примере, но вы также можете использовать цикл for на основе диапазона, который лучше, потому что он позволяет избежать выхода за пределы массива и, следовательно, избежать неопределенного поведения.
for (autoamp; a : canv)
{
for (autoamp; ch : a)
{
std::cout << ch;
}
std::cout << std::endl;
}
Вывод во всех случаях:
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
Комментарии:
1.
std::array
это не то же самое, что массив. Массивы на C используются довольно редко,std::array
илиstd::vector
почти всегда превосходят их.2. @john, да, конечно, но в данном случае, поскольку размеры известны во время компиляции, это вариант.
3. @DiaskyVB Если границы массива известны во время компиляции, то вы могли бы использовать
std::array
но, вероятно, ваш текущий компилятор не будет его поддерживать.4. @TedLyngmo, это звучит разумно, кстати, хорошо замечено
[]
.5. @TedLyngmo, еще раз, хорошо замечено, я чувствую, что должен поделиться голосами с вами 🙂
Ответ №2:
Распространенное заблуждение, что поскольку char[n]
преобразуется в char*
, то должна быть также возможность преобразования char[n][m]
в char**
, но это не так.
Проблема в том, что элементы char[n]
и char*
одинаковы. Каждый элемент является a char
, поэтому преобразование выполняется нормально.
Но с char[n][m]
каждым элементом есть char[m]
и с char**
каждым элементом есть char*
. Это не одно и то же, и преобразование недопустимо.
Простое решение заключается в использовании векторов вместо массивов.
vector<vector<char>> canvas(){
vector<vector<char>> canvas(18, vector<char>(8));
fill(canvas[0], canvas[0] 18 * 8, 'O');
return canvas;
}
Комментарии:
1. 11 19 [Ошибка] ‘>>’ должно быть ‘> >’ в списке аргументов вложенного шаблона
2. @DiaskyVB У вас, должно быть, очень старый компилятор или вы используете его с очень старыми опциями. Но если вы должны затем поставить пробел между
>>
.3. Я использую Devc 5.11
4. Это очень старый компилятор, есть современные компиляторы C , доступные бесплатно. Вам следует обновить.
5. @TedLyngmo Да, спасибо, я скопировал код операционной системы, не посмотрев на него достаточно внимательно.
Ответ №3:
Это может быть странный синтаксис:
char (*canvas())[8] //pointer to array return type
для улучшения разборчивости может быть полезно использовать псевдонимы типов:
using canvas_ptr = char (*)[8];
Таким образом, вы можете написать решение в стиле c таким образом:
canvas_ptr getCanvas()
{
canvas_ptr canvas = new char[18][8]; //C allocation
std::cout << "size:" << std::size(canvas) << 'n';
std::fill_n(canvas[0], 18 * 8, 'O'); //as suggested by Ted Lyngmo
return canvas;
}
int main()
{
canvas_ptr c = getCanvas();
for (int i = 0; i < 18; i ) //use it like a 2D array
{
for (int j = 0; j < 8; j )
{
std::cout << c[i][j];
}
std::cout << std::endl;
}
delete[] c; //delete object after it's used
}