[Imperative Programming + C] Bài 14 – Simplicity DSA Array (tiếp theo)

Như vậy là chúng ta đã có các sub-program hỗ trợ việc khởi tạo các Array mới trong các tình huống ứng dụng khác nhau. Tiếp theo chúng ta sẽ cùng xem lại một số thao tác cơ bản làm việc với mảng và đặt một chút suy nghĩ về vấn đề tạo mảng với

Như vậy là chúng ta đã có các sub-program hỗ trợ việc khởi tạo các Array mới trong các tình huống ứng dụng khác nhau. Tiếp theo chúng ta sẽ cùng xem lại một số thao tác cơ bản làm việc với mảng và đặt một chút suy nghĩ về vấn đề tạo mảng với độ dài linh động như JavaScript.

Data Table

Ngoài việc được sử dụng để lưu trữ các dải giá trị số học hay các chuỗi rời rạc, các mảng thường được sử dụng như các bảng dữ liệu lưu trữ các bản ghi như một database nho nhỏ trong các chương trình. Trường hợp mô tả các bảng dữ liệu có thể được hiểu đơn giản là khi chúng ta lưu trữ các struct bản ghi dữ liệu trong mảng. Lúc này mỗi một struct bản ghi dữ liệu sẽ là một hàng trong bảng, và mỗi trường dữ liệu của struct chính là tên cột trong bảng.

Nhân tiện khi nói tới ví dụ này thì chúng ta sẽ tạo một struct bản ghi dữ liệu để sử dụng xuyên suốt cái project nho nhỏ simplicity-dsa-c. Đối tượng dữ liệu ở đây sẽ là các bản ghi mô tả thông tin bìa của các cuốn sách có tên là Book. Ở đây mình sẽ liệt kê lại một chút về cấu trúc thư mục hiện tại của simplicity-dsa-c.

[simplicity-dsa-c]
.  |
.  +-----test.c
.  +-----index.h
.  |
.  +-----[array]
.  |        |
.  |        +-----new.c
.  |        +-----from.c
.  |        +-----slice.c
.  |        +-----concat.c
.  |        +-----destroy.c
.  |
.  +-----[book]
.           |
.           +-----new.c
.           +-----print.c
.           +-----destroy.c

Bổ sung định nghĩa struct_book và các sub-program làm việc với Book.

typedef double val;
typedef void* ref;

// - Array - - - - - - - - - - - - - - - - -

typedef struct {
   void* at;
   int   length;
   int   capacity;
} array_struct;

typedef array_struct* Array;

Array array_new (int capacity);
Array array_from (void* literal, int length, int capacity);
Array array_slice (Array origin, int start, int end);
Array array_concat (Array first, Array second);
void* array_destroy (Array thearray);

// - Book - - - - - - - - - - - - - - - - -

typedef struct {
   int id;
   ref title;
   ref author;
   val rating;
} book_struct;

typedef book_struct* Book;

Book book_new (int id, ref title, ref author, val rating);
void book_print (Book thebook);
void book_destroy (Book thebook);
#include<stdlib.h>#include"../index.h"

Book book_new(int id,
   ref title,
   ref author,
   val rating
)// -{  Book newbook =malloc(sizeof(book_struct));
      newbook->id = id;
      newbook->title = title;
      newbook->author = author;
      newbook->rating = rating;return newbook;}

Create Table

Chúng ta sẽ khởi đầu với việc tạo một bảng dữ liệu có sẵn một vài bản ghi và in ra màn hình.

#include<stdio.h>#include"index.h"voidprint_header();voidprint_data(Array booktable);voidprint_row(Book abook);intmain(){  Book laotzu =book_new(0,"Tao Te Ching","Lao Tzu",9.0);
      Book lotus =book_new(1,"Lotus Sutra","Buddha",10.0);
      Book yoga =book_new(2,"Yoga Sutra","Patanjali",9.8);// - CREATE TABLE - - - - - - - - - - - - - - - - - - - -
      Book literal[10000]={ laotzu, lotus, yoga };
      Array booktable =array_from(literal,3,10000);// - PRINT TABLE - - - - - - - - - - - - - - - - -print_header();print_data(booktable);return0;}voidprint_header(){printf("+------------+---------------------------+------------------+-------------+ n");printf("|  Id        |  Title                    |  Author          |  Rating     | n");printf("+------------+---------------------------+------------------+-------------+ n");}voidprint_data(Array booktable){int index; Book selected;if(booktable->length ==0)return;// - else print - - - - - - - - - - - - - - - - -
      index =-1;
      loop: index +=1;
         selected =((ref*) booktable->at)[index];print_row(selected);if(index < booktable->length -1)goto loop;}voidprint_row(Book abook){printf("|  %-9i |  %-24s |  %-15s |  %-10.1lf | n",
         abook->id, abook->title, abook->author, abook->rating
      );printf("+------------+---------------------------+------------------+-------------+ n");}
gcc test.c array*.c book*.c -o test
gcc test.c array/*.c book/*.c -o test
test

+-----------+---------------------------+------------------+-------------+ 
|  Id       |  Title                    |  Author          |  Rating     | 
+-----------+---------------------------+------------------+-------------+ 
|  0        |  Tao Te Ching             |  Lao Tzu         |  9.0        | 
+-----------+---------------------------+------------------+-------------+ 
|  1        |  Lotus Sutra              |  Buddha          |  10.0       | 
+-----------+---------------------------+------------------+-------------+ 
|  2        |  Yoga Sutra               |  Patanjali       |  9.8        | 
+-----------+---------------------------+------------------+-------------+

Insert Into

Thao tác đầu tiên là chèn thêm bản ghi mới vào bảng tại một thời điểm bất kỳ và giả định là chúng ta không biết chính xác số lượng bản ghi đã có mặt trong bảng. Ở đây chúng ta sẽ cần tạo id cho bản ghi mới dựa trên id của bản ghi mới nhất.

intmain(){// - CREATE TABLE - - - - - - - - - - - - - - - - - - - -// - GENERATE ID - - - - - - - - - - - - - - - - - - - -int lastindex = booktable->length -1;
      Book lastrecord =((ref*) booktable->at)[lastindex];int newbookid = lastrecord->id +1;// - ÍNSERT INTO - - - - - - - - - - - - - - - - - - - -
      Book theprophet =book_new(newbookid,"The Prophet","Kahlil Gibran",9.0);int index = booktable->length;((ref*) booktable->at)[index]= theprophet;
      booktable->length +=1;// - PRINT TABLE - - - - - - - - - - - - - - - - -}
gcc ... -o test
test

+-----------+---------------------------+------------------+-------------+ 
|  Id       |  Title                    |  Author          |  Rating     | 
+-----------+---------------------------+------------------+-------------+ 
|  0        |  Tao Te Ching             |  Lao Tzu         |  9.0        | 
+-----------+---------------------------+------------------+-------------+ 
|  1        |  Lotus Sutra              |  Buddha          |  10.0       | 
+-----------+---------------------------+------------------+-------------+ 
|  2        |  Yoga Sutra               |  Patanjali       |  9.8        | 
+-----------+---------------------------+------------------+-------------+ 
|  3        |  The Prophet              |  Kahlil Gibran   |  9.0        | 
+-----------+---------------------------+------------------+-------------+

Ồ… mặc dù chúng ta chỉ vừa mới thực hiện một thao tác căn bản đó là thêm một bản ghi vào bảng dữ liệu vào vị trí tiếp theo trong bảng. Tuy nhiên ngay sau thao tác này thì chúng ta đã có đủ chất liệu để đặt ra một số câu hỏi về giới hạn của việc sử dụng mảng.

Rõ ràng là nếu như chúng ta chèn bản ghi mới vào một vị trí trước đó, ví dụ như ngay sau bản ghi đầu tiên có trị số index=0; Và nếu như chúng ta đang có 1001 bản ghi trong bảng tại thời điểm thực hiện thao tác chèn bản ghi mới, thì chúng ta sẽ phải lặp qua 1000 bản ghi tính từ bản ghi có index=1 để di chuyển từng bản ghi tiến về phía trước để tạo chỗ trống cho bản ghi mới.

Hoặc khi xóa một bản ghi nào đó ở vị trí giữa mảng có index=n thì chúng ta cũng sẽ phải thực hiện thao tác ngược lại. Đó là lặp qua tất cả các bản ghi tính từ index=n+1 để di chuyển từng bản ghi lùi lại một bước để lấp chỗ trống của bản ghi vừa xóa.

Mặc dù logic xử lý ở đây cũng không có gì quá khó thực hiện, tuy nhiên điều này cũng cho thấy rằng ngoài đặc tính có dung lượng lưu trữ cố định thì mảng còn có một chút sự bất tiện trong thao tác quản lý dữ liệu trong những trường hợp nhất định. Và đây chính là điểm khiến mình quan tâm tới việc tìm hiểu thêm về một cấu trúc dữ liệu khác có tên là List – tạm dịch là danh sách.

(sắp đăng tải) [Imperative Programming + C] Bài 15 – Simplicity DSA List (giới thiệu)

Dynamic Capacity

Nói tới khả năng tạo mảng có độ dài linh động như JavaScript, thực tế thì chúng ta cũng biết rằng các mảng trong JavaScript là các Object chứ không phải là mảng đơn thuần như cú pháp tạo mảng mặc định của C.

Điều đó có nghĩa là khi chúng ta sử dụng cú pháp với các dấu ngoặc vuông [] để thêm phần tử mới vào mảng, logic xử lý sau khi đi qua trình thông dịch interpreter của JavaScript Engine hoàn toàn có khả năng thực hiện thêm thao tác phân bổ lại bộ nhớ lưu trữ để mở rộng mảng với capacity lớn hơn. Điều này hoàn toàn không ảnh hưởng tới địa chỉ tham chiếu của object Array bao bọc bên ngoài.

Ở đây chúng ta cũng có thể thực hiện logic tương tự bằng cách xin cấp lại bộ nhớ để tạo ra một mảng rộng hơn thay thế cho mảng lưu trữ thực đang được gắn tại trường booktable->at; Sau đó thực hiện sao chép dữ liệu từ mảng cũ sang mảng mới mà không ảnh hưởng tới địa chỉ của array_struct vỏ bọc bên ngoài. Tuy nhiên thao tác này cũng lại cần thực hiện việc lặp qua và di chuyển địa chỉ tham chiếu của 1001 bản ghi đã lưu trong mảng cũ sang mảng mới, không kém phần rườm rà so với thao tác chèn bản ghi mới hay xóa một bản ghi ở giữa mảng như đã nói ở trên.

Declarative Programming + SQL

Việc tìm hiểu về các cấu trúc dữ liệu và cái project mini simplicity-dsa-c của mình vẫn sẽ còn tiếp tục. Nhưng mục tiêu giới thiệu chính của Series Một Số Mô Hình Lập Trình Phổ Biến vẫn cần được tập trung. Do đó nên sau khi đã khá quen thuộc với việc sử dụng một ngôn ngữ lập trình định kiểu tĩnh static-typing, thì đây cũng đã là thời điểm rất phù hợp để chúng ta bắt đầu một Sub-Series mới song song với [Imperative Programming + C].

Mặc dù bài viết giới thiệu về Imperative & Declarative trong Series Tự Học Lập Trình Web đã liệt kê những khác biệt căn bản giữa hai mô hình lập trình này. Tuy nhiên việc sử dụng một ngôn ngữ có cú pháp đặt nền móng trên Declarative Programming sẽ giúp chúng ta nắm bắt được tốt hơn những điểm đã thảo luận.

Bên cạnh đó thì trong Series Tự Học Lập Trình Web, mình cũng đã phải lùi kế hoạch thực hiện Sub-Series giới thiệu SQL căn bản khá nhiều lần cho tới giờ. Lý do là vì bước nhảy từ JavaScript sang SQL sẽ có một khoảng trống khá khó giải thích rõ. Đó là về vấn đề định kiểu dữ liệu tĩnh static-typing mà chúng ta vừa mới làm quen trong lập trình C căn bản. Mọi thứ đã sẵn sàng, chúng ta hãy bắt đầu Sub-Series mới thôi. 😄

(sắp đăng tải) [Declarative Programming + SQL] Bài 1 – RDBMS & MySQL

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ