Подтвердить что ты не робот

Передача массива как параметра функции в С++

В С++ массивы не могут передаваться просто как параметры. Значение, если я создаю такую ​​функцию:

void doSomething(char charArray[])
{
    // if I want the array size
    int size = sizeof(charArray);
    // NO GOOD, will always get 4 (as in 4 bytes in the pointer)
}

У меня нет возможности узнать, насколько велик массив, так как у меня есть только указатель на массив.

В каком виде у меня есть, без изменения сигнатуры метода, чтобы получить размер массива и перебрать его данные?


EDIT: просто дополнение к решению. Если массив char, в частности, был инициализирован следующим образом:

char charArray[] = "i am a string";

то \0 уже добавлен в конец массива. В этом случае ответ (отмеченный как принятый) работает, как говорится.

4b9b3361

Ответ 1

Без изменения подписи? Добавить элемент часового. В частности, для массивов char это может быть нуль-завершающий '\0', который используется для стандартных строк C.

void doSomething(char charArray[])
{
    char* p = charArray;
    for (; *p != '\0'; ++p)
    {
         // if '\0' happens to be valid data for your app, 
         // then you can (maybe) use some other value as
         // sentinel
    }
    int arraySize = p - charArray;

    // now we know the array size, so we can do some thing
}

Конечно, тогда ваш массив сам по себе не может содержать элемент дозорного в качестве содержимого. Для других типов массивов (т.е. Не char) это может быть любое значение, которое не является юридическими данными. Если такого значения не существует, то этот метод не работает.

Кроме того, для этого требуется сотрудничество со стороны вызывающего абонента. Вам действительно нужно убедиться, что вызывающий абонент резервирует массив элементов arraySize + 1 и всегда устанавливает элемент дозорного.

Однако, если вы действительно не можете изменить подпись, ваши варианты ограничены.

Ответ 2

Использовать шаблоны. Это технически не соответствует вашим критериям, поскольку он меняет подпись, но код вызова не нуждается в изменении.

void doSomething(char charArray[], size_t size)
{
   // do stuff here
}

template<size_t N>
inline void doSomething(char (&charArray)[N])
{
    doSomething(charArray, N);
}

Этот метод используется Microsoft Защищенные функции CRT и STLSoft array_proxy.

Ответ 3

Фактически это было довольно распространенное решение для передачи длины в первом элементе массива. Такая структура часто называется BSTR (для "BASIC string" ), хотя это также обозначало разные (но похожие) типы.

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

В приведенной ниже форме он также работает только для строк длины <= 255. Однако это можно легко расширить, сохранив длину в более чем одном байте.

void doSomething(char* charArray)
{
    // Cast unnecessary but I prefer explicit type conversions.
    std::size_t length = static_cast<std::size_t>(static_cast<unsigned char>(charArray[0]));
    // … do something.
}

Ответ 4

В общем, при работе с C или низкоуровневым С++ вы можете переучивать свой мозг, чтобы никогда не рассматривать возможность записи параметров массива в функцию, потому что компилятор C всегда будет рассматривать их как указатели. По сути, набрав те квадратные скобки, вы обманываете себя, думая, что передается настоящий массив, в комплекте с информацией о размере. В действительности, в C вы можете передавать указатели. Функция

void foo(char a[])
{
    // Do something...
}

с точки зрения компилятора C, в точности эквивалентен:

void foo(char * a)
{
    // Do something
}

и, очевидно, что указатель nekkid char не содержит информации о длине.

Если вы застряли в углу и не можете изменить подпись функции, рассмотрите использование префикса длины, как было предложено выше. Непереносимый, но совместимый взлом - это указать длину массива в поле size_t, расположенном перед массивом, примерно так:

void foo(char * a)
{
    int cplusplus_len = reinterpret_cast<std::size_t *>(a)[-1];
    int c_len = ((size_t *)a)[-1];
}

Очевидно, что ваш вызывающий абонент должен соответствующим образом создавать массивы, прежде чем передавать их в foo.

Излишне говорить, что это ужасный взлом, но этот трюк может избавиться от неприятностей.

Ответ 5

если он завершится ошибкой, strlen() будет работать.

Ответ 6

Вы не можете определить размер только от charArray. Эта информация автоматически не передается функции.

Конечно, если это строка с нулевым завершением, вы можете использовать strlen(), но вы, вероятно, уже это считали!

Рассмотрим прохождение a std::vector<char> и параметра, или пару указателей, или указатель плюс параметр размера.

Ответ 7

На самом деле это больше C, чем С++, на С++ вы скорее всего используете std::vector. Однако в C нет способа узнать размер массива. Компиляция позволит вам сделать sizeof, если массив был объявлен в текущей области, и только если он был явно объявлен с размером ( EDIT: и "с размером", я имею в виду, что это был объявлен с целым размером или инициализирован в объявлении, а не передан как параметр, спасибо за downvote).

Общим решением в C является передача второго параметра, описывающего количество элементов в массиве.

EDIT:
Извините, пропустил часть о том, что вы не хотите менять подпись метода. Тогда нет решения, кроме как описано другими, если есть некоторые данные, которые недопустимы в массиве, его можно использовать как терминатор (0 в C-строках, -1 также довольно распространен, но это зависит от вашего фактический тип данных, если предположить, что массив char гипотетический)

Ответ 8

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

  • Передать параметр размера
  • Поместите информацию о размере в массив как-то.

Вы можете сделать последнее несколькими способами:

  • Завершить его с помощью NULL или некоторого другого дозорного, что не произойдет в нормальные данные.
  • сохранить количество элементов в первой записи, если массив содержит числа
  • сохранить указатель на последнюю запись, если массив содержит указатели

Ответ 9

попробуйте использовать strlen (charArray); используя заголовочный файл cstring. это приведет к количеству символов, включая пробелы, до тех пор, пока он не достигнет закрытия ".

Ответ 10

Вы гарантируете получение 4 на 32-битном ПК и правильный ответ. по причине, объясненной здесь здесь и здесь. Короткий ответ: вы на самом деле проверяете размер указателя, а не массив, потому что "массив неявно преобразован или распадается на указатель. Указатель, увы, не сохраняет размер массива, он не даже скажу вам, что переменная, о которой идет речь, представляет собой массив."

Теперь, когда вы используете С++, boost:: array - лучший выбор, чем необработанные массивы. Поскольку это объект, вы не потеряете информацию о размерах сейчас.

Ответ 11

Я думаю, вы можете это сделать:

size_t size = sizeof(array)/sizeof(array[0]);

PS: Я думаю, что название этой темы тоже неверно.

Ответ 12

Чувак, вы можете иметь глобальную переменную для хранения размера массива, который будет доступен по всей программе. По крайней мере, вы можете передать размер массива из функции main() в глобальную переменную, и вам даже не придется менять подпись метода, поскольку размер будет доступен по всему миру.

См. пример:

#include<...>
using namespace std;

int size; //global variable

//your code

void doSomething(char charArray[])
{
    //size available

}