Как определить размер массива строк в C ++? - PullRequest
12 голосов
/ 16 февраля 2010

Я пытаюсь просто распечатать значения, содержащиеся в массиве.

У меня есть массив строк с именем 'result'. Я не знаю точно, насколько он велик, потому что он был сгенерирован автоматически.

Из того, что я прочитал, вы можете определить размер массива следующим образом:

sizeof(result)/sizeof(result[0])

Это правильно? Потому что для моей программы sizeof (result) = 16 и sizeof (result [0]) = 16, так что код скажет мне, что мой массив имеет размер 1.

Однако это не выглядит правильно, потому что, если я вручную распечатаю значения массива, как это:

std::cout << result[0] << "\n";
std::cout << result[1] << "\n";
std::cout << result[2] << "\n";
std::cout << result[3] << "\n";
etc...

... тогда я вижу результирующие значения, которые я ищу. Массив содержит более 100 значений длины / размера.

Кажется, что определить размер / длину массива очень просто ... так что, надеюсь, я просто что-то здесь упускаю.

Я немного новичок в C ++, поэтому любая помощь будет признательна.

Ответы [ 8 ]

10 голосов
/ 16 февраля 2010

Вы не можете определить размер массива динамически в C ++. Вы должны передать размер в качестве параметра.

В качестве дополнительного примечания, использование контейнера стандартной библиотеки (например, vector) устраняет это.

В вашем примере sizeof, sizeof(result) запрашивает размер указателя (предположительно, std :: string). Это связано с тем, что фактический тип массива «распадается» на тип указателя на элемент при передаче функции (даже если объявлена ​​функция, принимающая тип массива). sizeof(result[0]) возвращает размер первого элемента в вашем массиве, который по совпадению также составляет 16 байтов. Похоже, что указатели имеют 16 байтов (128-бит) на вашей платформе.

Помните, что sizeof - это всегда , вычисляемое во время компиляции в C ++, никогда во время выполнения.

8 голосов
/ 16 февраля 2010

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

// simple: runtime result
template <typename T, std::size_t N>
inline std::size_t sizeof_array( T (&)[N] ) {
   return N;
}

// complex: compile time constant
template <typename T, std::size_t N>
char (&static_sizeof_array( T(&)[N] ))[N];   // declared, not defined
#defined SIZEOF_ARRAY( x ) sizeof(static_sizeof_array(x))

В обоих случаях компилятор обнаружит, если вы попытаетесь передать указатель (динамический массив или распавшийся массив):

void f( int array[] ) { // really: void f( int *array )
{
//   sizeof_array(array);              // compile time error
//   int another[SIZEOF_ARRAY(array)]; // compile time error
}
int main() {
   int array[] = { 1, 2, 3 };
   std::cout << sizeof_array(array) << std::endl; // prints 3
   int another_array[ SIZEOF_ARRAY(array) ];
   std::cout << sizeof_array(another_array) << std::endl; // 3 again
}
3 голосов
/ 16 февраля 2010

Если у вас есть «настоящий» массив, то трюк sizeof (x) / sizeof (x [0]) работает. Однако, если у вас есть действительно указатель (например, что-то, возвращаемое из функции), то этот трюк не работает - вы в конечном итоге разделите размер указателя на размер указателя , Они являются указателями на разные типы, но в типичной системе все указатели имеют одинаковый размер, поэтому вы получите один. Даже если указатели имеют разные размеры, результат все равно не будет иметь никакого отношения к тому, сколько у вас строк.

1 голос
/ 04 апреля 2016
template< class T, size_t N >
std::size_t Length(const T(&)[N])
{
    return N;
};

std::cout << Length(another_array) << std::endl;
1 голос
/ 02 марта 2014

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

Когда объект содержит указатели, как в случае массива строк, sizeof () возвращает размер структуры самого высокого уровня (фиксированного размера). Часто это просто размер одного указателя. Он не включает размер выделенных данных, на которые указывают указатели. Поскольку эти данные на самом деле не являются частью основного объекта, это действительно один или несколько отдельных объектов (здесь мы имеем агрегацию вместо композиции, см. http://en.wikipedia.org/wiki/Object_composition).

В C ++ использование векторов очень удобно для ваших нужд. Можно использовать и другие подходящие стандартные контейнеры. Методы length () и size () являются синонимами, см. http://www.cplusplus.com/reference/string/string/size/)

P.S. Обратите внимание, что для std :: string s объект sizeof (s) является константой, независимой от фактической (переменной) длины строки, возвращаемой s.length (). Фактический размер выделенной памяти возвращается функцией s.capacity () и может быть больше, чем length ().

Пример использования векторного массива:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    string s = "01234";
    cout << "s[" << s.length() << "]=\"" << s << "\"" << endl; 
    cout << "sizeof(s)=" << sizeof(s) << " (implementation dependent)" << endl;
    cout << endl;

    s += "56789012345";
    cout << "s[" << s.length() << "]=\"" << s << "\"" << endl; 
    cout << "sizeof(s)=" << sizeof(s) << " (implementation dependent)" << endl;
    cout << endl;

    vector<string>vs={"12","23","345","456","567","67888","7899999999","8","9876543210"};

    cout << "vs[" << vs.size() << "]={";
    size_t sz=0;
    for (size_t index=0; index<vs.size(); index++)
    {
        sz+=vs[index].size();
        if (index>0)
            cout << ",";
        cout << "\"" << vs[index] << "\":" << vs[index].size();
    }
    cout << "}:" << sz << endl;
    cout << "sizeof(vs)=" << sizeof(vs) << " (implementation dependent)" << endl;

    return 0;
}

Результат:

s[5]="01234"
sizeof(s)=8 (implementation dependent)

s[16]="0123456789012345"
sizeof(s)=8 (implementation dependent)

vs[9]={"12":2,"23":2,"345":3,"456":3,"567":3,"67888":5,"7899999999":10,"8":1,"9876543210":10}:39
sizeof(vs)=24 (implementation dependent)
1 голос
/ 16 февраля 2010

Лучше использовать std::vector<std::string> вместо необработанного массива. Тогда вам не нужно вручную управлять памятью массивов, и вы можете использовать метод size(), если хотите узнать количество элементов.

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

0 голосов
/ 16 февраля 2010

Что нужно знать: текст может быть представлен разными способами. Массив текста также может быть представлен различными методами.

Массив указателей на строки в стиле C

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

Массив char - упакованный текст

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

Массив std::string

В C ++ текст может быть представлен с использованием std::string. В этом случае массив представляет количество строк (аналогично массиву C-Strings выше). Чтобы получить общий размер всех строк, необходимо суммировать размер каждой отдельной строки. Поскольку это массив, размер массива также должен быть передан.

Краткое описание

Во время выполнения массива размеры должны сопровождать массив при его передаче. sizeof обрабатывается только во время компиляции. Более простая структура - std::vector, которая динамически обрабатывает размер и распределение памяти.

0 голосов
/ 16 февраля 2010

В векторном методе String используйте метод size ()

...