Tổng kết buổi 5: Con trỏ

Số lượng thành viên tham gia: 10
Link slide buổi học
Link record đang update
Link bài tập lớp buổi 5 CPP
Link btvn buổi 4 CPP
Link btvn buổi 5 CPP

Bản chất của Biến (Variables):

Khái niệm về hằng, biến cục bộ và biến toàn cục:

Hằng (constant):

Hằng (constant) là từ chỉ những thứ không thay đổi và lặp đi lặp lại.

Cách khai báo:

const <kiểu dữ liệu> <tên biến> = <giá trị>;
hoặc
<kiểu dữ liệu> const <tên biến> = <giá trị>;

Biến cục bộ (Local variables):

Biến được định nghĩa bên trong khối lệnh được gọi là các biến cục bộ (local variables). Những biến này chỉ có thể được truy cập bên trong các khối lệnh mà nó được định nghĩa (bao gồm các khối lệnh lồng nhau), và bị hủy ngay sau khi các khối lệnh kết thúc.

Biến toàn cục (Global variables):

Các biến khai báo bên ngoài của khối lệnh được gọi là biến toàn cục. Biến toàn cục có thời gian tĩnh, nghĩa là chúng được tạo ra khi chương trình bắt đầu và bị hủy khi nó kết thúc. Các biến toàn cục có phạm vi tập tin (file scope), hay gọi là “phạm vi toàn cầu” (global scope).

Con trỏ:

Định nghĩa:

Là biến trỏ tới 1 địa chỉ khác, tức giá trị nó lưu là 1 địa chỉ của 1 ô nhớ khác.

Các khái niệm về con trỏ

  • Giá trị của con trỏ: địa chỉ mà con trỏ trỏ đến.
  • Địa chỉ của con trỏ: Địa chỉ của bản thân biến con trỏ đó
  • Giá trị của biến nơi con trỏ đang trỏ tới
  • Địa chỉ của biến nơi con trỏ đang trỏ tới = giá trị của con trỏ.

Làm việc với con trỏ:

Cách khai báo: <kiểu dữ liệu> * <tên biến>
Cách gán giá trị :
Ví dụ:

int *ptr; // khai báo con trỏ
int val = 5; // khai báo biến digit mang giá trị là 42
ptr = &val; // gán giá trị của con trỏ = địa chỉ của biến digit

Lưu ý: Con trỏ được khai báo là kiểu dữ liệu gì thì chỉ có thể trỏ tới biến có cùng kiểu giá trị đó

Tham chiếu ngược: *[tên_con_trỏ]

Con trỏ đặc biệt:

Con trỏ rác (Null Pointer):

Hãy ghi nhớ rằng chúng ta không nên để một con trỏ là rác ( tức là không được khởi tạo giá trị). Một con trỏ rác là con trỏ không trỏ tới cái gì cả, nếu bạn sử dụng nó thì nó sẽ trỏ tới 1 địa chỉ ` ngẫu nhiên ` nào đó và sẽ thật là nguy hiểm nếu địa chỉ đó đang được sử dụng với 1 mục đích khác

Con trỏ Void (Void Pointer):

Một con trỏ void được sử dụng để trỏ tới biến có bất kỳ kiểu dữ liệu nào. Nó có thể tái sử dụng với bất kỳ biến nào mà chúng ta muốn

Bản chất của con trỏ:

Con trỏ có thể thay đổi trực tiếp giá trị của biến mà nó đang trỏ tới Khi thay đổi giá trị của biến, thì rõ ràng nếu tồn tại con trỏ ptr trỏ tới biến đó thì *ptr cũng sẽ thay đổi theo giá trị của biến.

Các lỗi thường gặp:

Nhầm lẫn giữa địa chỉ và giá trị. Con trỏ là biến trỏ tới địa chỉ, không phải giá trị Có thể các bạn sẽ không phân biệt được dấu * khi khai báo con trỏ và khi truy cập vào giá trị của địa chỉ mà con trỏ đang trỏ tới.

Truyền giá trị cho hàm:

Gọi hàm bằng tham trị tức là truyền bản sao của biến vào hàm để xử lý. Bản sao của một biến mang giá trị bằng giá trị của biến đó. Gọi hàm bằng tham chiếu. Chúng ta truyền địa chỉ hoặc tham chiếu của biến vào hàm, lúc này không có bản sao chép nào được tạo cả, đảm bảo việc không bị lãng phí bộ nhớ. Chúng ta có thể truy cập vào giá trị lưu trong các địa chỉ này bằng toán tử tham chiếu ngược *.

Code bài tập trên lớp:

Swap

Viết một hàm swap , nhận hai con trỏ int và hoán đổi giá trị của hai biến đó.

Sample Input:

1 2

Sample Output:

2 1

Solution

#include<bits/stdc++.h>
using namespace std;
void swap(int *a, int *b) {
	int tmp = *a;
*a = *b;
*b = *c; 
}
int main() {
    	int a, b;
    	cin >> a >> b;
    	swap(&a, &b);
    	cout << a << " " << b;
return 0;
}

Max3

Hãy xây dựng một hàm Max3, nhận đầu vào là 3 biến kiểu int a, b, c và một con trỏ Max. Hàm sẽ thực hiện tìm giá trị lớn nhất trong ba số (a, b, c) và gán giá trị đấy vào biến Max.

Sample Input 0

1 30 15

Sample Output 0:

30

Solution

#include<bits/stdc++.h>
using namespace std;

void Max3(int a, int b, int c, int *Max) {
    *Max = a;
    if (b > *Max) *Max = b;
    if (c > *Max) *Max = c;
}

int main() {

    // Không thay đổi code ở hàm main
    int a, b, c;
    cin >> a >> b >> c;
    int ansMax;
    Max3(a, b, c, &ansMax);
    cout << ansMax;
}

Sort

Sau khi đã có hàm swap(int *a, int *b) ở bài tập trước. Hãy ứng dụng nó để xây dựng hàm sort , nhận vào 3 con trỏ và sắp xếp chúng theo thứ tự tăng dần.

Sample Input 0

8 11 9

Sample Output 0:

8 9 11

Solution

#include<bits/stdc++.h>
using namespace std;


void swap(int *a, int *b) {
    int c = *a;
    *a = *b;
    *b = c;
    
}

void sort(int *a, int *b, int *c) {
    if (*a > *b) swap(a, b);
    if (*a > *c) swap(a, c);
    if (*b > *c) swap(b, c);
}

int main() {
    int a, b, c;
    cin >> a >> b >> c;
    sort(&a, &b, &c);
    cout << a << " " << b << " " << c;
}

normalize

Viết một hàm normalize nhận đầu vào là một con trỏ, hàm thực hiện việc chia số đó với 2 mỗi khi có thể (nếu số đó dương và chia hết cho 2).
Ví dụ, số 100 sẽ trở thành 25, và số 5 sẽ vẫn là chính nó. Nó được đảm bảo rằng hàm này sẽ không truyền vào số âm.

Sample Input 0

100

Sample Output 0:

25

Solution

#include<bits/stdc++.h>
using namespace std;


void normalize(int *a) {
    while(*a != 0 && *a % 2 == 0){
        *a /= 2;
    }
}

int main() {
    int a;
    cin >> a;
    normalize(&a);
    cout << a;
}

Pointers CPP
Pointers in C/C++ with Examples
C++ Pointer Tutorial