Лекція 12. Структури. Символьні рядки
1. Структури
Ми можемо створювати змінні нашого власного типу за допомогою концепції під назвою структури – struct.
Наприклад, якщо ми хочемо зберегти й імена, і гуртожитки кожного окремого студента, то можемо зробити масиви для кожного:
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int enrollment = get_int("Enrollment: ");
string names[enrollment];
string dorms[enrollment];
for (int i = 0; i < enrollment; i++)
{
names[i] = get_string("Name: ");
dorms[i] = get_string("Dorm: ");
}
for (int i = 0; i < enrollment; i++)
{
printf("%s is in %s.\n", names[i], dorms[i]);
}
}
Проте, можливо, надалі ми захочемо додати інші фрагменти даних, тому треба запевнитися, що усі масиви мають правильну довжину і дані для однієї особи знаходяться за одним і тим же індексом та ін. Натомість, ми можемо використати структури у файлі struct.h, який містить:
typedef struct
{
char *name;
char *dorm;
}
student;
І файл struct.c, який містить:
#include <cs50.h>
#include <stdio.h>
#include "struct.h"
int main(void)
{
int enrollment = get_int("Enrollment: ");
student students[enrollment];
for (int i = 0; i < enrollment; i++)
{
students[i].name = get_string("Name: ");
students[i].dorm = get_string("Dorm: ");
}
for (int i = 0; i < enrollment; i++)
{
printf("%s is in %s.\n", students[i].name, students[i].dorm);
}
}
Тепер student – наш власний тип змінної, що містить в собі дві змінні: name та dorm, до яких ми зможемо пізніше отримати доступ за допомогою .name і .dorm.
Ми навіть можемо відкривати і зберігати файли за допомогою фрагментів коду, на кшталт:
FILE *file = fopen("students.csv", "w");
if (file)
{
for (int i = 0; i < enrollment; i++)
{
fprintf(file, "%s,%s\n", students[i].name, students[i].dorm);
}
fclose(file);
}
2. Символьні рядки
Тепер, відкидаючи один рівень абстракції, ми усвідомлюємо що string насправді не існує, а, натомість, є char* з іменем string.
Що ж, виходить що коли ми пишемо щось типу:
string s = get_string();
Функція get_string(), під час першої спроби поверне нам Daven, а також \0:
Судячи з усього, Daven\0 складається з декількох байтів, і якщо string займає всього 4 байти, 32 біти, як ми можемо умістити весь рядок у s? Що ж, рядок комірок, у якому міститься Daven\0, це просто байти в пам’яті. Кожен байт має певну адресу, так само як будинки мають адресу, наприклад 33 Oxford Street, 34 Oxford Street чи 35 Oxford Street, тож пронумеруємо, для наочності, кожен байт у пам’яті.
Тепер ми можемо здогадатись що функція get_string() вертає не весь рядок string, а адресу рядка string: Daven "живе" за адресою 0x1. Тож s лишень містить адресу цього рядка.
І так відбувається з моменту, як ми вперше познайомились з string. Все що ми отримуємо коли запитуємо string - це розташування його початку.
Програмісти випадково можуть призначити будь-яку адресу у змінну і спробувати перейти за нею у пам’яті, і наступного разу ми побачимо скільки проблем це може спричинити.