Лекція 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 - це розташування його початку.

Програмісти випадково можуть призначити будь-яку адресу у змінну і спробувати перейти за нею у пам’яті, і наступного разу ми побачимо скільки проблем це може спричинити.

Остання зміна: Thursday 28 May 2020 10:21 AM