|
Вопрос знатокам Си про объявление и инициализацию массивов | ☑ | ||
---|---|---|---|---|
0
Chai Nic
22.12.13
✎
10:34
|
Как происходит выделение памяти под статически объявленные внутри функции массивы (в частности char array) и как происходит их инициализация?
Возьмем для примера 2 варианта. 1. char str[]="abc"; str1[0]='x'; 2. char * str="abc";str1[0]='x'; Второй вариант приводит к исключительной ситуации. Означает ли это, что при инициализации str[] в памяти выделяется место под буфер соответствующего размера, соответствующего константной строке инциализации, и в этот буфер копируются символы, а во втором случае, при инициализации char * - просто указателю присваивается адрес глобального константного массива, который недоступен для записи? Создается ли в первом случае буфер под массив на стеке функции, или же в глобальной области памяти? Означает ли это, что объявление и инициализация символьных масивов первым способом потокобезопасно, и использовать malloc не обязательно? |
|||
1
Chai Nic
22.12.13
✎
10:34
|
(0)Поправлю опечатку.
1. char str[]="abc"; str[0]='x'; 2. char * str="abc";str[0]='x'; |
|||
2
Аденэсниг
22.12.13
✎
11:06
|
да
|
|||
3
Аденэсниг
22.12.13
✎
11:07
|
(0)потокопасно
|
|||
4
MKZM
22.12.13
✎
11:18
|
char * str Просто указатель на нечто. Память не выделена
char str[] [] - Выделяет память |
|||
5
jsmith82
22.12.13
✎
11:25
|
(4) +1
|
|||
6
jsmith82
22.12.13
✎
11:28
|
Основные типы данных для работы со строкой это символ и указатель. Понятно, что могут иметься несколько указателей, ссылающихся на один и тот же массив:
1: char city[10]; 2: char *one = city; 3: char *two = city + 2; Здесь мы объявили один массив и три указателя: city, созданный при объявлении массива, one, который хранит адрес первого байта массива, и two, хранящий адрес третьего байта массива. Надо понимать вот что: массив и указатель - это совершенно разные вещи! |
|||
7
jsmith82
22.12.13
✎
11:30
|
Поскольку массив символов - это массив, а указатель на байт символьного массива - это указатель, то те и другие могут быть двух видов: переменными и константными. Объект является переменным, если он может изменять свое значение, иначе он является константным.
Объявление нединамического массива: char city[10] = "London"; создает константный указатель и переменный массив. Мы можем сколько угодно переписывать содержимое массива, но указатель city будет исключительно хранить адрес его первого байта. Если нужно, чтобы массив также был константным, надо написать: const char city[10] = "London"; Попытка присвоения значения элементам константного массива вызывает ошибку на этапе компиляции. |
|||
8
jsmith82
22.12.13
✎
11:31
|
учить матан в общем
|
|||
9
jsmith82
22.12.13
✎
11:34
|
Когда в программе встречается строковая константа, то создается константный массив однозначного размера. Сама строка является константным указателем на этот массив. Вот несколько примеров.
1: printf("%p\n", "Book"); 2: printf("%p\n", "Book" + 3); 3: char *one = "Book"; 4: char *two = "Book" + 2; В 1-й строке кода создается константный массив длиной 7, константный указатель на 1-й байт которого передается в функцию printf. Во второй строке создается идентичный массив и передается указатель на его 4-й байт. В 3-й строке снова создается такой же массив, адрес первого байта которого передается указателю one. В 4-й строке указатель two получает адрес 3-го байта массива. |
|||
10
GANR
22.12.13
✎
12:53
|
(0) Так ведь во втором варианте память надо выделить предварительно, то есть
char *str; str = new char[50]; str[0] = 'c'; str[1] = 'a'; Если где-то ошибся - пардон, 7 лет уже с C/C++ не работал. |
|||
11
Chai Nic
22.12.13
✎
13:49
|
(9) Вся эта теория мне знакома.. нигде не вижу четкого определения "место под нединамическиймассив выделяется в стеке" или "место под нединамический массив выделяется в глобальной памяти". То, что сам указатель хранится в стеке - это-то вопросов не вызывает..
|
|||
12
Chai Nic
22.12.13
✎
13:52
|
+(9) То, что строковая константа суть константный массив, это понятно. Непонятно, что происходит, когда мы пишем в коде "char str[]="abc";". Данные из этой константы побайтно переносятся в выделенную для str область в стеке? Или что?
|
|||
13
jsmith82
22.12.13
✎
13:59
|
(12) в файле .obj разве не видно?
|
|||
14
jsmith82
22.12.13
✎
14:01
|
ты ассебмлер хотя бы знаешь?
|
|||
15
Chai Nic
22.12.13
✎
14:01
|
(13) ?
|
|||
16
Chai Nic
22.12.13
✎
14:02
|
(14) 15 лет назад на асме писал лабы.
|
|||
17
Chai Nic
22.12.13
✎
14:03
|
Вопрос вполне конкретный.. Каким образом хранятся и где инициализируются локально определенные в функции массивы? При чем здесь ассемблер?
|
|||
18
jsmith82
22.12.13
✎
14:03
|
(15) листинг скомпилированной проги посмотри
|
|||
19
jsmith82
22.12.13
✎
14:04
|
напиши примитивный код, скомпилируй в режиме дебаг, запусти отладчик
|
|||
20
Chai Nic
22.12.13
✎
14:06
|
(19) Я думал здесь есть знающие люди, а такие советы "разберись во всем сам" может кто угодно давать..
|
|||
21
AaNnDdRrEeYy
22.12.13
✎
14:08
|
char *str; - это указатель на первый элемент массива.
но не сам массив и память для него выделяется ровно столько сколько занимает одна переменная char |
|||
22
Chai Nic
22.12.13
✎
14:09
|
(21) Второй вариант был приведен чисто для иллюстрации отличий, но мне интересно, как работает первый..
|
|||
23
AaNnDdRrEeYy
22.12.13
✎
14:12
|
более конкретно
char - размер 1 байт char str[]="abc"; - размер 3 байта. адреса в памяти допустим 0x01 0x02 0x03 char * str - это указатель на адрес 0x01 инкрементируя *str можно бегать по массиву *str++ ,будет указывать на 0x02 и т.д. синтаксис может и не совсем правильный но я смысл хотел донести |
|||
24
Chai Nic
22.12.13
✎
14:15
|
(23) Это всё я знаю. Массив в стеке выделяется? При запуске функции в другом треде данные в массиве не будут путаться с данными из другой функции?
|
|||
25
AaNnDdRrEeYy
22.12.13
✎
14:17
|
(22) а что в первом варианте не понятно?
char str[]="abc"; - взять свободную память и выделить память для трех переменных char. и записать в них abc str1[0]='x'; индексатор [0] указывает на сколько единиц нужно увеличить адрес от адреса первого элемента масива. и записать по этому адресу x |
|||
26
AaNnDdRrEeYy
22.12.13
✎
14:19
|
(24) >> Массив в стеке выделяется?
`да в стеке. для того что бы в куче надо memlock(char[3]) вызывать |
|||
27
Chai Nic
22.12.13
✎
14:19
|
(25) "взять свободную память"
В стеке текущей функции? Или в глобальной области памяти (в куче)? |
|||
28
kot_bcc
22.12.13
✎
14:20
|
Способ инициализации и хранения зависит от компилятора (способ хранения ещё и от компоновщика).
Например, при настройках по умолчанию, компиляторы VC крайних версий все строковые константы переносят в отдельный сегмент ("сегмент" в смысле терминов компоновщика), при этом указатели(в смысле ассемблера) вида "char str[]" собираются в момент загрузки модуля на исполнение из таблиц символов portable executable, указатели же вида char * str инициализируются в энтер-коде функции (т.е. прямо в теле функции переменной стека присваивается адрес элемента таблицы символов). |
|||
29
Chai Nic
22.12.13
✎
14:21
|
То есть, при одновременном запуске функции из нескольких потоков использовать локальные нединамические массивы, инициализированные константным массивом можно, они не пересекутся?
|
|||
30
kot_bcc
22.12.13
✎
14:23
|
Нет, нельзя, потому что они (массивы) НЕ локальны. Это элементы таблицы символов, загрузчик ничего не знает о потоках и не делает копий
|
|||
31
Chai Nic
22.12.13
✎
14:23
|
(30) То есть, массивы НЕ хранятся в стеке функции?
|
|||
32
Chai Nic
22.12.13
✎
14:24
|
Речь не о массивах-константах, а именно об определенных внутри функции массивах, _инициализированных_ из констант.
|
|||
33
AaNnDdRrEeYy
22.12.13
✎
14:25
|
(29) пересекуться. делай mallock в каждом потоке
http://sernam.ru/c_42.php |
|||
34
Chai Nic
22.12.13
✎
14:27
|
(33) Так значит они не в стеке хранятся? В стеке они в принципе не способны пересечься..
|
|||
35
kot_bcc
22.12.13
✎
14:27
|
(31)
Нет. Хранятся только указатели. Инициализированные массивы - указатели на области памяти, общие для программы. (32) "массивах, _инициализированных_ из констант" Этот код совершенно не будет похож на код из (0). Чтобы массив инициализировать из константы - надо выделить память. Просто так ("в теневую") память не выделяется. Руками. |
|||
36
Chai Nic
22.12.13
✎
14:30
|
(35) Если так, тогда чем отличается 1 и 2 варианты?
|
|||
37
kot_bcc
22.12.13
✎
14:31
|
Функции скрытой работы с памятью хорошо реализованы в stdlib. Причем независимо от компилятора. Стандарты уже давно предусматривают, что тот же вектор не показывает работы с памятью. В нашем случае - идеально "std::string". Всё сама делает, потокобезопасна, и т.д.
|
|||
38
Chai Nic
22.12.13
✎
14:31
|
(37) С плюсами не хочу связываться, мне интереснее чистый си
|
|||
39
kot_bcc
22.12.13
✎
14:32
|
(36) Отличаются способом хранения указателя (инлайн или стек), и, соответственно, способом инициализации.
|
|||
40
kot_bcc
22.12.13
✎
14:35
|
"Чистый Си" - абстракция примерно того же уровня нереальности, что и "либерализм". О нём можно рассуждать, но рассуждения не имеют смысла ввиду эфемерности предмета дискуссии. Проще смириться с жестокой и отвратительной действительностью :)
|
|||
41
kot_bcc
22.12.13
✎
14:37
|
Я уж не говорю. что в "чистом си" в принципе отсутствует понятие "исключение", тем более - исключение при записи переменной. Т.е. никакой "исключительной ситуации" в "чистом си" не может быть при записи char* - переменной по определению.
|
|||
42
Chai Nic
22.12.13
✎
14:37
|
(40) Угу.. одно только добавление iostream раздувает программу с пары десятков килобайт до половины мегабайта
|
|||
43
Chai Nic
22.12.13
✎
14:38
|
(41) Это не обрабатываемое исключение, а вызываемое системой
|
|||
44
CoolCat
22.12.13
✎
14:39
|
||||
45
CoolCat
22.12.13
✎
14:40
|
(42) щас оперативки много это на заре комп. технологий боролись за КБ
|
|||
46
kot_bcc
22.12.13
✎
14:43
|
(42)
Видимо, Ваша собственная реализация "iostream" весит сотню байт? Вы уверены, что те, кто делал стандартные библиотеки, так уж плохи как разработчики? (43) Какой системой? Как может запись на локальный стек вызвать системное исключение? |
|||
47
kot_bcc
22.12.13
✎
14:46
|
+(46)
"...на локальный стек..." -> "...в область данных программы..." |
|||
48
Chai Nic
22.12.13
✎
14:46
|
(46) Блин. При чем здесь стек? Так массивы хранятся в стеке или нет?
|
|||
49
kot_bcc
22.12.13
✎
14:47
|
успел поправиться :)
|
|||
50
Chai Nic
22.12.13
✎
14:48
|
(46) Я не собираюсь делать аналог стандартных библиотек, потому что мне не нужно 99.9% того, что они умеют.. Моё обращение к Си одноразовое.
|
|||
51
kot_bcc
22.12.13
✎
14:48
|
Ок. Чем мог - помог.
|
|||
52
Chai Nic
22.12.13
✎
14:49
|
Спасибо, буду использовать malloc)
|
|||
53
Chai Nic
22.12.13
✎
14:53
|
Кстати, есть функция alloca(), выделяющая память в стеке - её можно использовать в этом случае?
|
|||
54
Фигня
22.12.13
✎
14:58
|
Да, виден усохший от ФГМ моск 1снега... Про map-файлы и окно процессора в отладчике явно не в курсе. Интересно, а про СП в 1С ТС знает? Про отладчик 1Совский даже как-то страшно спрашивать...
|
|||
55
Chai Nic
22.12.13
✎
15:08
|
(54) Ну покажите мне, где "окно отладчика" в gcc
|
|||
56
ДенисЧ
22.12.13
✎
15:14
|
(55) gbd
|
|||
57
Chai Nic
22.12.13
✎
15:23
|
(56) Я в курсе.. просто без оболочки он слегка неюзабелен)
|
|||
58
Torquader
22.12.13
✎
17:29
|
Второй вариант, в общем случае, даёт ссылку в область кода программы (где живут константы), а она часто ReadOnly.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |