Chuong1_OnTapC_MangContro

Download Report

Transcript Chuong1_OnTapC_MangContro

1

Trường Đại Học Bách Khoa Hà Nội Viện: Điện Tử - Viễn Thông

Bộ Môn: Điện tử - Kỹ thuật máy tính

Ngôn ngữ lập trình C/C++

Chương 1

: Ôn tập Ngôn ngữ lập trình C Cấu trúc dữ liệu mảng và con trỏ

Các nội dung chính

1. Kiểu mảng 2. Kiểu con trỏ 3. Mối quan hệ giữa hai kiểu DL 4. Cấp phát bộ nhớ động 2

1. Kiểu mảng 1.1. Giới thiệu

Một đối tượng dữ liệu kiểu mảng có các đặc trưng sau: 

Số chiều

: là một giá trị nguyên dương cố định nên được biểu diễn bằng một hằng số nguyên dương.

Kích thước mỗi chiều

: cũng là một giá trị nguyên dương cố định nên cũng được biểu diễn bằng một hằng số nguyên dương.

Kiểu phần tử mảng

: là kiểu dữ liệu của mỗi phần tử (kiểu mảng). 3

1. Kiểu mảng

Các thao tác cơ bản trên một đối tượng dữ liệu kiểu mảng gồm có: 

Khai báo

: xác định các đặc trưng của mảng như số chiều, kích thước mỗi chiều, kiểu mảng. 

Truy nhập vào các phần tử của mảng

: theo một trong hai cách : 

Truy nhập gián tiếp

: bằng cách sử dụng chỉ số. 

Truy nhập trực tiếp

: thông qua con trỏ. 4

1. Kiểu mảng 1.2. Mảng một chiều a) Khai báo

- Khai báo biến mảng: với cú pháp như sau:

kiểu_dữ_liệu tên_biến [N] ; kiểu_dữ_liệu tên_biến [N] = {v1,v2,…,vn}; kiểu_dữ_liệu tên_biến [] = {v1,v2,…,vn};

Trong đó: N phải là một hằng số nguyên dương. v1,v2,…,vn là các giá trị khởi tạo tương ứng cho các phần tử của mảng. 5

1.

Kiểu mảng - Mảng một chiều

VD : char s[20]; char s[10] = {’s’,’t’,’r’,’i’,’n’,’g’}; char s[10] = “string”; char s[10] = {’s’,’t’,’r’,’i’,’n’,’g’,’\0’}; int a[10] = {1,2,3}; int a[10] = {1,2,3,0,0,0,0,0,0,0}; int a[] = {1,2,3}; int a[3] = {1,2,3}; int a[] ; //error 6

1.

Kiểu mảng - Mảng một chiều

-

Khai báo hằng mảng

: với cú pháp như sau:

const kiểu_dữ_liệu tên_biến [N] = {v1,v2,…,vn}; kiểu_dữ_liệu const tên_biến [] = {v1,v2,…,vn};

  Hằng mảng là mảng các hằng số, tức là tất cả các phần tử trong mảng đều là hằng số. Việc khởi tạo giá trị ban đầu cho các phần tử khi khai báo là bắt buộc. VD:

const

int a[3] = {1,2,3}; a[1] = 5 ; //error 7

1.

Kiểu mảng Mảng một chiều

b) Truy nhập

Trong phần này chúng ta chỉ xét phương pháp truy nhập gián tiếp thông qua chỉ số. - Chỉ số của một phần tử : Sau khi khai báo một đối tượng dữ liệu mảng, các phần tử trong mảng sẽ có một số hiệu duy nhất được gọi là chỉ số của phần tử đó. Chỉ số này vừa có vai trò tên gọi, vừa có vai trò xác định địa chỉ tương đối của một phần tử trong mảng. - Cách đánh chỉ số: trong C/C++ quy ước phần tử thứ i (1 thứ N có chỉ số là N-1.  i  N) trong mảng có chỉ số là i-1. Tức là phần tử đầu tiên có chỉ số là 0, phần tử - Truy nhập bằng chỉ số: để truy nhập vào một phần tử có chỉ số i ta dùng cú pháp

tên_mảng[i] .

8

VD : chương trình sắp xếp một dãy N số theo trật tự tăng dần bằng giải thuật sắp xếp nổi bọt

main(){ const int N = 200 ; float a[N] ; int i,j ; …Nhập giá trị cho mảng a ; for (i=0;ia[j+1]) { float tg = a[j]; a[j]=a[j+1]; a[j+1] =tg; } …In kết quả } 9

1. Kiểu mảng

1.3. Mảng hai chiều a) Khai báo

- Khai báo biến mảng : với cú pháp như sau:

kiểu_dữ_liệu tên_biến [M][N] ; kiểu_dữ_liệu tên_biến [M][N] = {v1,v2,…,vm*n}; kiểu_dữ_liệu tên_biến [][N] = {v1,v2,…,vm*n};

- Khai báo hằng mảng : tương tự như hằng mảng 1 chiều, việc khai báo hằng mảng hai chiều sẽ phải thêm từ khoá

const và khởi tạo giá trị ban đầu cho các phần tử của mảng.

10

VD : khai báo mảng 2 chiều

char s [2][3]; int a[][3] = {1,2,3,4,5};  int a[2][3] = {1,2,3,4,5,0}; int a[2][3] = {{1,2},{3,4,5}};  int a[2][3] = {{1,2,0},{3,4,5}}; int a[2][] ; //error int a[2][] = {1,2,3,4,5}; //error 11

1. Kiểu mảng Mảng hai chiều

b) Truy nhập

- Việc truy nhập vào các phần tử của mảng hai chiều kích thước MxN cũng sử dụng chỉ số với quy ước về cách đánh chỉ số như sau: phần tử thứ nhất có chỉ số là (0,0) phần tử thứ hai có chỉ số (0,1) … phần tử thứ N có chỉ số (0,N-1) phần tử thứ N+1 có chỉ số (1,0) … phần tử thứ MxN có chỉ số (M-1,N-1) Để truy nhập vào phần tử có chỉ số (i,j) ta dùng cú pháp

tên_mảng[i][j].

- Từ việc khai báo và sử dụng mảng một chiều và hai chiều,chúng ta có thể dễ dàng suy ra cách khai báo và sử dụng các mảng nhiều chiều hơn. 12

1. Kiểu mảng

1.4. Tự định nghĩa kiểu dữ liệu mới kiểu mảng

Trong C/C++ cho phép người sử dụng có thể tự định nghĩa các kiểu dữ liệu mới dựa trên các kiểu dữ liệu đã có hay định nghĩa lại tên của các kiểu dữ liệu đã có bằng từ khoá

typedef (viết tắt của type definition).

- Cú pháp của lệnh

typedef:

typedef định_nghĩa_kiểu tên_kiểu ;

- Trong đó: định_nghĩa_kiểu là phần xác định loại, cấu trúc của kiểu dữ liệu mới. Nó thường là định nghĩa cấu trúc các kiểu dữ liệu mới như các cấu trúc mảng, cấu trúc bản ghi (struct)... 13

1. Kiểu mảng Tự định nghĩa kiểu dữ liệu mới kiểu mảng

VD: định nghĩa lại kiểu

int với tên mới là integer như trong Pascal.

typedef int integer ; integer i, j ; - Định nghĩa một kiểu mảng 1 chiều: typedef kiểu_dữ_liệu tên_kiểu[N] ; VD: typedef char ten[30] ; ten t1=”An”,t2=”Binh”,t3; Nếu không sử dụng định nghĩa kiểu mới ta phải khai báo như sau: char t1[30], t2[30] , t3[30] ; 14

1. Kiểu mảng Tự định nghĩa kiểu dữ liệu mới kiểu mảng

- Định nghĩa một kiểu mảng hai chiều: typedef kiểu_dữ_liệu tên_kiểu[M][N] ; VD: typedef float matran[M][N] ; matran A, B - Kiểu mảng hai chiều có thể được định nghĩa thông qua kiểu mảng một chiều như sau: typedef float f1[N] ; typedef f1 f2[M] ; 15

2. Kiểu con trỏ

Giới thiệu

Là đối tượng DL mà giá trị của nó là địa chỉ của các đối tượng khác (có thể là chính nó) trong bộ nhớ P A P = &A 16

2. Kiểu con trỏ

Vai trò: con trỏ được sử dụng trong một số ứng dụng sau:  Quản lý các đối tượng DL động và cấu trúc lưu trữ động (như CTLT móc nối) để cài đặt lưu trữ các CTDL động như danh sách, cây,…   Định vị, truy nhập vào các thành phần của các kiểu DL có cấu trúc nhằm tăng tốc độ thực hiện và độ linh hoạt trong xử lý. Ta hay dùng con trỏ để truy nhập vào mảng, bản ghi (struct).

Tổ chức các tham số đóng vai trò đầu ra của các chương trình con (hàm con). Trong C, điều này là bắt buộc, còn trong C++ ta có thể dùng con trỏ hoặc kiểu tham chiếu.

17

2. Kiểu con trỏ - Khai báo

Khai báo biến con trỏ

T * var; T * var1, *var2; Trong đó: T là kiểu DL bất kì, thậm chí là kiểu con trỏ.

VD: char * s; int i=20; int * pi = &i, *pj=pi; float * pf[20]; //Mảng các con trỏ kiểu float float (*pf)[20]; void * p; //Con trỏ kiểu mảng //Con trỏ tổng quát.

18

2. Kiểu con trỏ - Khai báo

Khai báo hằng con trỏ

const T * cons1 = ; T * const cons2 = ; //Con trỏ đến một hằng số //Hằng con trỏ const T * const cons3 = ; //Hằng con trỏ trỏ đến hằng số 19 const char* pc= “abcd” ; char * s = “fgh” ; pc[1] = ‘f’; //error pc = “efgh”; //OK; pc = s ; //OK char* const cp = “abcd”; cp[1] = “f” ; //OK cp = “efgh”; //error cp = s ; //error const char* const cpc = “abcd”; cpc[1] = “f” ; //error cpc = “efgh”; //error cpc = s ; //error

Các thao tác cơ bản trên kiểu con trỏ

   Phép gán Truy nhập vào đối tượng được trỏ Phép tăng/giảm địa chỉ 20

Phép gán

Sử dụng phép gán ‘=’ để gán giá trị cho con trỏ.

Cú pháp: p= ;

Với p là con trỏ, bt là biểu thức vế phải, cũng phải là kiểu con trỏ. Nếu kiểu con trỏ của p và của bt không giống nhau, ta thường phải sử dụng phép ép chuyển kiểu. Toán tử ‘&’ hay được dùng để lấy địa chỉ đối tượng trong bt để gán cho con trỏ.

char c= ‘A’; char *pc = &c; int a[5], *pa; pa = &a[0]; pa = a; pa = (int*)pc; //ép chuyển kiểu void *p; p = pa; p = pc; //Không cần ép chuyển kiểu //Không cần ép chuyển kiểu 21

Truy nhập vào đối tượng được trỏ

Khi một con trỏ p đang trỏ vào một đối tượng A, ta có thể truy nhập vào A thông qua một trong các toán tử truy nhập. Trong C có nhiều toán tử truy nhập khác nhau, thường phụ thuộc vào kiểu DL của đối tượng A.

 Toán tử

*

: áp dụng khi A là đối tượng DL thuộc một trong các kiểu DL cơ bản (kí tự, số nguyên, số thực). Cú pháp: “*p”.

  Toán tử

[]

: áp dụng khi A là dữ liệu kiểu mảng. Cú pháp: p[N], với N là một biểu thức nhận giá trị nguyên.

Toán tử  : áp dụng khi A là DL kiểu struct. Cú pháp: p  fn, với fn là tên trường trong cấu trúc struct mà ta muốn truy nhập.

22

Truy nhập vào đối tượng được trỏ

char c= ‘A’; char *pc = &c; *pc = ‘D’;

// c = ‘D’;

int a[5], *pa; pa = &a[0]; pa[2] = 10;

//a[2] = 10;

struct Person { char name[30]; int age; } ps; struct Person *p = & ps; scanf(“%s”,

p->name

);

p->age

= 20; 23

Phép tăng/giảm địa chỉ

 Đó là các phép toán (+,-, ++, --) trên biến con trỏ. char st[10]; char * ps = st; //ps = &st[0]; ps =

ps +2

; //ps = &st[2]; int si[10]; int * pi = &si[1];

pi++

; pi =

pi - 2

; //pi = &si[2]; //pi = &si[0]; 24

3. Mối quan hệ giữa mảng và con trỏ

  Bản thân mảng là một con trỏ, trỏ đến dãy phần tử của mảng. Nó là hằng con trỏ ( mảng, cũng như không thực hiện được các phép tăng/giảm địa chỉ ) như không thể gán cho tên Biến con trỏ có thể được dùng để truy nhập vào các phần tử của mảng giống như mảng 25

3. Mối quan hệ giữa mảng và con trỏ

1. char s[5]; 2. char * ps = s; //ps = &st[0]; 3. ps =

ps +2

; //ps = &st[2]; 4. s++; //Error s 2.

ps 3.

26

4. Cấp phát động bộ nhớ

  Thư viện cung cấp một số hàm để quản lý vùng nhớ động: Hàm

malloc

(): có định dạng hàm

void * malloc(int size);

Hàm cấp phát vùng nhớ động kích thước size, rồi trả về địa chỉ của ngăn nhớ đầu tiên của vùng nhớ đó. Hàm trả về NULL nếu cấp phát không thành công  Hàm

calloc

(): void * calloc(int nItems, int size_item); Cấp phát vùng nhớ kích thước nItems * size_item  Hàm

realloc

(): void* realloc(void* block, int new_size); Cấp phát lại một vùng nhớ mới kích thước new_size cho vùng nhớ cũ trong block, có copy dữ liệu từ vùng nhớ cũ sang vùng nhớ mới.

 Hàm

free

(): có định dạng hàm

void free (void * p);

Hàm giải phóng vùng nhớ động đã được cấp phát tại địa chỉ p 27

Ví dụ

#include #include //#define N 10 int main(){ int i; int N; scanf(“%d”,&N); //Cap phat bo nho dong cho bien p

int *p = (int*)malloc(N*sizeof(int));

if (p==NULL) { printf("Error allocating memory"); return 0; } for (i=0;i

free(p)

; } //end main 28

Tóm tắt nội dung chính

     Kiểu mảng Số chiều: 1 hay nhiều chiều Các thao tác cơ bản: khai báo, định nghĩa, truy nhập Bản chất: là một hằng con trỏ trỏ vào một dãy các phần tử   Kiểu con trỏ Các thao tác cơ bản: khai báo, lấy địa chỉ, truy nhập vào đối tượng được trỏ, tăng/giảm địa chỉ Quan hệ với kiểu mảng 29

Cảm ơn!

30

Bài tập

   

Bài 1

: viết chương trình nhập vào một dãy N (không lớn hơn 100) số nguyên khác 0 từ bàn phím (nhập số 0 để báo kết thúc việc nhập). Sau đó in ra số lượng các số âm và số dương đã nhập được.

Bài 2

: Viết chương trình nhập vào một ma trận kích thước MxN các số thực từ bàn phím, rồi tính tổng các phần tử theo từng cột rồi in ra.

Bài 3

: Viết một chương trình nhập một dãy N số (không lớn hơn 100) nguyên, sau đó sắp xếp các số theo trật tự tăng dần, rồi in dãy trước và sau khi sắp xếp ra màn hình.

Bài 4

: Viết chương trình nhập 2 ma trận A trận đó ra màn hình.

MxN và B NxP các số thực, rồi tính tích của 2 ma trận đó. Sau đó in toàn bộ các ma 31

Bài tập

 

Bài 5

: Viết lại bài 3 nhưng có sử dụng mảng động với cơ chế cấp phát động thay vì dùng các mảng tĩnh.

Bài 6

: Viết lại bài 4 nhưng có sử dụng mảng động với cơ chế cấp phát động thay vì dùng các mảng tĩnh. 32