Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Помогите разобраться с массивом строк! 
:(
    Опции темы
Волод
Дата 15.6.2005, 13:19 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Помогите разобраться с массивом!
Предположим, у меня есть такой массив строк:
Код

char *li[]=
    {
        "Струйкой",
        "дым",
        "понесла",
        "тишина,",
        "запечалилась",
        "в небе",
        "луна",
        "ну и пусть",
        "мне",
        "печаль",
        "не страшна,",
        "главное,",
        "что есть ты",
        "у меня..."
    };


Началось все с того, что я захотел получить через формулу количесво элементов такого массива. Сбацал нечто вроде такого: int elem=(int)(sizeof(li)/sizeof(li[0])). В общем-то количество элементов подсчиталось правильно, но появились подозрения, что полученный таким образом результат будет не всегда верным. Главным образом потому, что мне непонятен механизм выделения памяти под каждую строку в массиве. Если предположить, что на каждую строку память выделяется по числу символов в строку, тогда результат в большинстве случаев будет неверным. Попробовал проверить догадку, оставивив в первой строке всего один символ. – но нет результат расчитался вновь правильно. Тогда я в отладчике посмотрел, сколько памяти выделено под первую строку – и очень удивился - независимо от размера строки оператор sizeof(li[0]) всегда дает 4 байта. То есть для строки “струйкой” это очень мало (на каждый char - символ должен выделяться 1 байт), а для строки из одного символа это очень много. Короче, здесь я окончательно запутался…. Помогите понять механизм выделения памяти под массив строк! И является-ли верным мой вариант поддсчета количества строк, или он срабатывает не всегда…

  Вверх
chaos
Дата 15.6.2005, 13:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Серийный программист
****


Профиль
Группа: Завсегдатай
Сообщений: 2979
Регистрация: 7.7.2004
Где: Екатеринбург

Репутация: 6
Всего: 44



ты наверное видел не размер выделяемый под строку, а размер для хранения адреса в памяти для этой строки
PM WWW   Вверх
Дрон
Дата 15.6.2005, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 93



Волод
Вариант твой верный smile

Си строки действительно несколько хитры.

sizeof(li[0]) равно 4, потому что li[0] это указатель (тип char*). И размер указателя (грубо говоря) всегда 4 байта. В Си нет типа строка, на самом деле строка в Си представляет собой просто массив.

Если написать: char *str = "abcdef"; то будет создан указатель, значение которого будет адресом в памяти, где хранится сама строка. Сама строка, кстати, будет занимать 7 байт: шесть символов и нулевой байт - конец строки.

В твоём коде создаётся массив из 14 указателей, каждый из которых указывает на кусок памяти содержащий символы нужной строки.

ЗЫ: Как приятно читать вопрос человека, понимающего что он спрашивает... Сейчас это редкость smile smile


--------------------
Да. Именно так.
PM   Вверх
chaos
Дата 15.6.2005, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Серийный программист
****


Профиль
Группа: Завсегдатай
Сообщений: 2979
Регистрация: 7.7.2004
Где: Екатеринбург

Репутация: 6
Всего: 44



так ты же и так знаешь размер массива на этапе разработке smile
PM WWW   Вверх
Дрон
Дата 15.6.2005, 14:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 93



Цитата(chaos @ 15.6.2005, 15:44)
так ты же и так знаешь размер массива на этапе разработке

И где в приведённом коде можно увидеть размер массива? smile


--------------------
Да. Именно так.
PM   Вверх
srd
Дата 15.6.2005, 16:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нереварин
**


Профиль
Группа: Участник Клуба
Сообщений: 951
Регистрация: 30.8.2003
Где: Владивосток

Репутация: 27
Всего: 49



Извиняюсь, что не совсем по теме, но:
Код

char *li[]=    
    {    
        "Струйкой",    
        "дым",    
        "понесла",    
        "тишина,",    
        "запечалилась",    
        "в небе",    
        "луна",    
        "ну и пусть",    
        "мне",    
        "печаль",    
        "не страшна,",    
        "главное,",    
        "что есть ты",    
        "у меня..."    
    };

Этот код содержит ошибку. Символьные литералы в Си++ имеют тип const char *, не char *. Возможность присваивать указатели на const char* указателям на char* без явного приведения типов оставлена только для совместимости со старым Си-кодом. Запись в область памяти, занятую символьными литералами, можно разрешить ключиками компилятора, но по умолчанию она должна быть запрещена в любом вменяемом компиляторе. Я однажды обжёгся об это при портировании старой DOS-программы и потому обращаю ваше внимание smile


--------------------
Не смей читать мою подпись!!!
PM MAIL Jabber   Вверх
comcon1
Дата 15.6.2005, 16:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



Я обычно массивы указателей на объекты, строки и пр. принудительно заканчиваю NULL-ом.
Тогда можно написать функцию (универсальную), получающую размер твоего массива.
Типа такой:
Код

int Count(const void **array) {
         int ans = 0;
         while(*array) {
           array++; ans++;
        }
        return ans;
}


Так потом, если ты даже не обрубаешь NULL на конце, компилятор делает это автоматически. Например вот такое работает (у меня GCC):
Код

        char **StringArray = new (char*)[10];
        for (int i=0; i<11; i++) {
                if (i!=10) {
                        StringArray[i] = new char[10];
                        strcpy(StringArray[i], "Hellow!!");
                }
                if (StringArray[i] == NULL) cout << "NULL" << endl;
                else cout << i << " element " << StringArray[i] << endl;
        }


Выводит десять раз Hellow и NULL в конце smilesmile



--------------------
PM MAIL   Вверх
Волод
Дата 16.6.2005, 05:16 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Спасибо за подробные объяснения!
  Вверх
chaos
Дата 16.6.2005, 06:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Серийный программист
****


Профиль
Группа: Завсегдатай
Сообщений: 2979
Регистрация: 7.7.2004
Где: Екатеринбург

Репутация: 6
Всего: 44



Цитата
Цитата(chaos @ 15.6.2005, 15:44)
так ты же и так знаешь размер массива на этапе разработке

И где в приведённом коде можно увидеть размер массива? smile

ручками посчитать
PM WWW   Вверх
Гость_Илья
Дата 19.8.2005, 04:05 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











comcon1, Я запустил твой код который в конце выводит нулл.
У меня компилятор MinGW 3.4.2-20040916-1.
Он когда создает массив указателей все их значения мусорные а не нулл, и соответственно возникает ошибка когда он пытается написать элемент по непонятному адресу. Может ты какие нить ключи особенные используешь при компиляции ? И еще, вот так он ругается
Код

char **StringArray = new (char*)[10];

А когда скобки убираешь полный порядок
Код

char **StringArray = new char* [10];


Не подскажете почему так ?
  Вверх
Mayk
Дата 19.8.2005, 04:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 45
Всего: 134



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

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

memset(array,0,sizeof_array); 

где sizeof_array - кол-во занимаемых массивом байт.







--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0575 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.