Вы просто разбиваете строку разделенных новой строкой полей. У объекта String в Ruby есть метод split, который делает это.
my_string = "John Clark\nDallas\nSystem Engineer\nGlobal Edge\nWage 2\nY\n1\nRobin James\nCleveland\nArchitect\nMaxSys\nWage 3\nY\n0\nJoseph Neils\nLittle Rock\nDB Admin\nTech Sys\nWage 2\nY\n1\n"
my_string.split("\n")
дает вам массив строк, такой как вы хотите. Затем вы можете объединить эти массивы в другой массив.
Документация по методу разделения здесь: https://ruby-doc.org/core-2.6.2/String.html#method-i-split
Ни в каком смысле в вышеупомянутом коде что-либо разыменованное. Разыменовывание происходит когда *
или ->
используется на значении адреса для нахождения значения, на которое ссылаются. Единственное использование *
выше находится в описании типа в целях кастинга.
->
оператор используется выше, но он не используется для доступа к значению. Вместо этого это используется для захвата адреса значения. Вот немакро-пример кода, который должен сделать это немного более ясным
SomeType *pSomeType = GetTheValue();
int* pMember = &(pSomeType->SomeIntMember);
Вторая строка на самом деле не вызывает разыменовывание (зависящего от реализации). Это просто возвращает адрес SomeIntMember
в pSomeType
значение.
То, что Вы видите, является большим количеством кастинга между произвольными типами и символьными указателями. Причина символа состоит в том, что это - один из единственного типа (возможно, единственное) тип в стандарте C89, который имеет явный размер. Размер равняется 1. Путем обеспечения размера один, вышеупомянутый код может сделать злое волшебство вычисления истинного смещения значения.
В ANSI C, offsetof
НЕ определяется как этот. Одна из причин, это не определяется как этот, - то, что некоторые среды действительно бросят исключения нулевого указателя или откажут другими способами. Следовательно, ANSI C оставляет реализацию offsetof( )
откройтесь разработчикам компилятора.
Код, показанный выше, типичен для компиляторов/сред, которые активно не проверяют на Нулевых указателей, но перестали работать только, когда байты читаются из Нулевого указателя.
Для ответа на последнюю часть вопроса код не является портативным.
Результат вычитания двух указателей определяется и портативный, только если эти два указателя указывают на объекты в том же массиве или указывают на одно прошлое на последний объект массива (7.6.2 Аддитивных операторов, H&S Пятый Выпуск)
Хотя это - типичная реализация offsetof
, это не получает мандат по стандарту, в котором просто говорится:
Следующие типы и макросы определяются в стандартном заголовке
<stddef.h>
[...]
offsetof(
type
,
member-designator
)
который расширяется до выражения целочисленной константы, которое имеет тип
size_t
, значение которого является смещением в байтах к элементу структуры (обозначенныйmember-designator
), с начала его структуры (обозначенныйtype
). Тип и членский указатель должны быть таковы что данный
static
type
t;
затем выражение
&(t.
member-designator
)
оценивает к постоянному адресу. (Если указанный участник является битовым полем, поведение не определено.)
Считайте P J Plauger "Стандартная библиотека для C" для обсуждения его и других объектов в <stddef.h>
которые являются всеми пограничными функциями, которые могли (должен?) быть на надлежащем языке, и который мог бы потребовать специальной поддержки компилятора.
Это представляет исторический интерес только, но я использовал ранний компилятор C ANSI на 386/IX (см., я сказал Вам об историческом интересе, приблизительно 1990), который отказал на той версии offsetof
но работал, когда я пересмотрел его к:
#define offsetof(st, m) ((size_t)((char *)&((st *)(1024))->m - (char *)1024))
Это было своего рода ошибкой компилятора, не в последнюю очередь потому что заголовок был распределен с компилятором и не работал.
Это не делает segfault, потому что Вы не разыменовываете его. Адрес указателя используется в качестве числа, это вычтено из другого числа, не используемого для обращения к операциям памяти.
Это вычисляет смещение участника m
относительно начального адреса представления объекта типа st
.
((st *)(0))
относится к a NULL
указатель типа st *
. &((st *)(0))->m
относится к адресу участника m в этом объекте. Так как начальный адрес этого объекта 0 (NULL)
, адрес участника m является точно смещением.
char *
преобразование и различие вычисляют смещение в байтах. Согласно операциям указателя, когда Вы имеете значение между двумя указателями типа T *
, результатом является количество объектов типа T
представленный между двумя адресами содержится операндами.