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

#c #multidimensional-array #char

#c #многомерный массив #символ

Вопрос:

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

 const int size = 12;
    char maze[ size ][ size ] = {
            "############",
            "#...#......#",
            "..#.#.####.#",
            "###.#....#.#",
            "#....###.#..",
            "####.#.#.#.#",
            "#..#.#.#.#.#",
            "##.#.#.#.#.#",
            "#........#.#",
            "######.###.#",
            "#......#...#",
            "############",
        };
  

VS C выдает мне предупреждающее сообщение, в котором говорится, что размер слишком мал для такого массива. Я думаю, это потому, что в каждой строке также должен быть символ ‘ 0’. Как мне инициализировать массив символов без символов ‘ 0’? Я не хочу инициализировать size значением 13, потому что будет слишком сложно использовать эту константу для функций (печать массива, перемещение и т.д.). Есть ли какой-нибудь способ это сделать?

Кроме того, как передать этот массив функции void mazeTraverse с помощью указателя?

 int main()
{
  mazetraverse(maze)
}

void mazeTraverse(char (*maze)[ size ])
  

Такой код не работает…

Комментарии:

1. Напоминает мне о Nethack

2. Имя функции — mazeTraverse . Почему вы пытаетесь вызвать mazetraverse ?

Ответ №1:

Необходимо учитывать нулевой символ в конце строки:

 char maze[size][size   1] = { /*  */ };
  

В качестве альтернативы, для большей гибкости, вы можете сделать:

 char *maze[size] = { /*  */ };
  

Я вижу, вы используете C . Есть ли какая-либо причина, по которой вы не используете std::string ?

 std::string maze[size] = { /*  */ };
  

Это намного более гибко; теперь вы просто меняете прототип на:

 void mazeTraverse(std::string maze[]);
  

Если вы еще более безумны, вы будете использовать std::vector<std::string> .


РЕДАКТИРОВАТЬ: я рекомендую немного изучить std::string . Это работает точно так же, как char* но вам не нужно вручную выделять его / etc. Например:

 std::string mystring = "lol";
mystring = "lololol"; // perfectly legal!

std::cout << mystring[0] << "n";
// Or: printf("%cn", mystring[0]);

char* sz[8];
strcpy(sz, mystring[0].c_str());

// And so on...
  

Комментарии:

1. Большое спасибо! Ваш пример работает идеально. Я не использую string в стиле C , потому что я еще не изучил его. Прямо сейчас я сосредоточен на строках в стиле C.

2. @Alex немного отредактировал мой ответ.

Ответ №2:

Раз вы используете C , почему бы просто не создать простой класс?:

 class Maze {
  public:
    Maze(int width, const std::stringamp; data) 
      :width_(width),
       data_(data.begin(), data.end()) {
    }

    char operator()(int row, int column) const { 
      return data_[width_*row   column]; 
    }

  private:
    int width_;
    std::vector<char> data_;
};
  

Вы можете легко инициализировать его, воспользовавшись тем фактом, что последующие строковые литералы, такие как «foo», «bar», неявно объединяются в «foobar»:

 Maze my_maze(12, 
             "############"
             "#...#......#"
             "..#.#.####.#"
             "###.#....#.#"
             "#....###.#.."
             "####.#.#.#.#"
             "#..#.#.#.#.#"
             "##.#.#.#.#.#"
             "#........#.#"
             "######.###.#"
             "#......#...#"
             "############");
  

Комментарии:

1. Обратите внимание, что после кавычек (в «массиве») нет никаких запятых.

2. @lidjam: Нет, я определенно имел в виду operator(). Operator[] допускает только один аргумент; нам нужны два (т. е. строка и столбец).

3. @muntoo: Именно. Просто чтобы разъяснить это для всех: размещение строковых литералов рядом друг с другом без запятых эквивалентно написанию одной гигантской строки. Конструктор принимает этот const char* и неявно преобразует его в std::string, который затем может быть легко скопирован во внутреннее представление: std::vector<char> без необходимости в символах, заканчивающихся нулем.

4. Ваш пример слишком сложен для моего понимания. Я знаком с основой классов, но что-то вроде:width_ (ширина), data_ (данные.begin(), данные.end()) и std::string мне сейчас неизвестны.

5. @SuperElectric : Если вы имели в виду, operator() то подпись должна быть char operator()(int row, int column) const . В вашем коде отсутствует ключевая часть — какой оператор вы определяете.

Ответ №3:

Для инициализации я бы:

 char* maze[ size ] = {
        "############",
        "#...#......#",
        "..#.#.####.#",
        "###.#....#.#",
        "#....###.#..",
        "####.#.#.#.#",
        "#..#.#.#.#.#",
        "##.#.#.#.#.#",
        "#........#.#",
        "######.###.#",
        "#......#...#",
        "############",
    };
  

Для передачи параметров вы должны иметь возможность использовать символ ** . Так что это было бы:

 void mazeTraverse(char ** param)
  

Ответ №4:

«Не работает»? Код действительно работает. И это работает отлично. (Предполагается, что компилятор позволяет использовать эти 13-символьные строковые литералы для инициализации массивов размера 12. На самом деле это ошибка в C , но вы сказали, что получаете простое предупреждение).

Это

 mazeTraverse(maze);
  

будет скомпилирован и сделает именно то, что вы хотите, чтобы он делал (так, как я это понимаю). Что именно не работает в вашем случае? «Не работает» — это не совсем осмысленное описание проблемы.

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

 char maze[ size ][ size ] = {
  { '#', '#', '#', ... },
  { ...                },
  // and so on
};
  

Если вы хотите использовать строковые литералы, то, как вы сами отметили, вам нужно объявить внутренние подмассивы большего размера

 char maze[ size ][ size   1 ] = {
  "############",
  // and so on
};
  

и соответствующим образом измените объявление функции

 void mazeTraverse(char (*maze)[ size   1 ])