Kiểu dữ liệu trong C/C++: Kiểu dữ liệu với con trỏ

c
c++

(Tao Không Ngu.) #1

Hi mọi người, đã khá lâu từ bài đăng trước của mình. Lần này mình định viết một loạt 4 bài (Tứ bài) về lập trình game 2 đơn giản bằng C++ dùng thư viện SFML nhưng do lười nên thôi. Tuy nhiên bạn nào thích có thể xem thêm trên GitHub. Người dùng linux có thể tải về cấp quyền thức thi chạy luôn được.

12%3A23%3A38

Bài viết hôm nay mình sẽ nói đến kiểu dữ liệu trong C và C++. Với java hay C# thì kiểu dữ liệu của biến khá rõ ràng không có gì phải lăn tăn (Mình biết mỗi hai cái này). Còn với C có kiểu con trỏ thì mọi thứ thức sự phức tạp VD: int *** ** a chưa kể con trỏ hàm nữa @_@!

#include <stdio.h> 
// A normal function with an int parameter 
// and void return type 
void fun(int a) 
{ 
    printf("Value of a is %d\n", a); 
} 
  
int main() 
{ 
    // fun_ptr is a pointer to function fun()  
    void (*fun_ptr)(int) = &fun; 
  
    /* The above line is equivalent of following two 
       void (*fun_ptr)(int); 
       fun_ptr = &fun;  
    */
  
    // Invoking fun() using fun_ptr 
    (*fun_ptr)(10); 
  
    return 0; 
} 

Để giải quyết các vấn đề với con trỏ nhiều cấp thì có một cách là dùng typedef. Tuy nhiên bản thân typedef cũng không dễ hiểu lắm.

#include <stdio.h>

#define SIZE 5

typedef int* (*arrayPoiterFunction[SIZE])(int);

int* fun(int a) 
{ 
    printf("Value of a is %d\n", a);
    return 0;
}

int main(int argc, char** argv) {
	arrayPoiterFunction funs;
	funs[0] = &fun;
	(*funs[0])(10);
	return 0;
}

Cõ lẽ C++ với kiểu dữ liệu tham chiếu là sẽ giúp lập trình viên khỏi phải OT fix bug có thêm thời gian cho cuộc sống. Tuy nhiên thực tế nó chỉ giống như con trỏ với ít hơn một dấu *

#include <iostream>

#define SIZE 5
#define BUFFER_SIZE 512

typedef char (& (* arrayPoiterFunctionBuffer[SIZE])(char (&)[BUFFER_SIZE]))[BUFFER_SIZE];

char (&show(char (& data)[BUFFER_SIZE]))[BUFFER_SIZE] {
	std::cout << data << std::endl;
	return data;
}

int main(int argc, char** argv) {
	arrayPoiterFunctionBuffer funcs;
	funcs[0] = &show;
	char data[BUFFER_SIZE] = {"TKNgu"};
	char (& same)[BUFFER_SIZE] = (*funcs[0])(data);
	std::cout << same << std::endl;
	
	same[5] = '?';
	same[6] = '\0';
	(*funcs[0])(same);
	std::cout << data << std::endl;
return 0;
}

Và nhiều khi mức độ kỳ dị còn hơn cả con trỏ.

Rất may những bộ óc thiên tài tạo ra nó ắt hẳn là có lý do của nó. Đây là một skill mình mới học được chia sẻ cho mọi người cùng nghiên cứu xem.

Code format.

Trong C ký tự * vừa là kiểu dữ liệu vừa toán tử lấy giá trị của một con trỏ.

int *a;
*a = 10; //Code loi.

Để làm rõ khi nào là kiểu dữ liệu, khi nào là toán tử thì mình thường code theo format int* a (* đi liền sau int và cách ra là tên biến) và *a = 10 (* đi liền trước tên biến giống như cách viết hàm fun(10)) cả cụm int* là một kiểu dữ liệu : con trỏ - trỏ đến 1 biến kiểu int.

typedef khi cần.

int* a, b;

Khi khai báo như này thì a là một biến kiểu : con trỏ - trỏ đến 1 biến kiểu int còn b là một biến kiểu int. (Nhìn thì 2 biến cùng kiểu nhưng thực ra nó lại 2 kiểu khác nhau.) Tốt nhất nên viết thành 2 dòng

int* a;
int* b;

Với những kiểu phức tạp như int**** thì nên dùng typedef.
Cú pháp thường thấy:

typedef int**** superSuperSuperStar

tuy nhiên với

typedef int* (*arrayPoiterFunction[SIZE])(int);

khá khó hiểu, thực tế thì không. Khi khai báo 1 biến int**** superSuperSuperStar (superSuperSuperStar là một biến) và thêm typedef vào trước thì tên biến đó sẽ thành một kiểu dữ liệu.

#define SIZE 10
typedef int* array[SIZE];

Tên biến thỏa mãn quy tắc đặt tên thì tên kiểu cũng vậy.

Dừng lại đã mấy cái này thì có gì đâu. Hồi sau sẽ rõ.

Ốc anh vũ.


Một hình xoắn ốc tự nhiên có tỉ lệ vàng cực kỳ cân đối.

Đơn giản nhất:

int a


Vẽ một hình xoắn ốc ngược chiều kim đồng hò từ tên biến.

int** a


a (biến a) -> * (là một con trỏ) -> * tiếp (trỏ đến 1 con trỏ ) -> int (kiểu int).

void (*fun_ptr)(int)


fun_ptr (Biến fun_ptr) -> * (là một con trỏ) ->()(int) (trỏ đến một hàm có tham số đầu vào kiển int) -> void (trả về void).

Biến tham chiếu đến 1 mảng. char(& array)[BUFFER_SIZE]
array%262
array(biến array) -> &(là một biến tham chiếu) -> [BUFFER_SIZE](dến 1 mảng có BUFFER_SIZE phần tử) -> ```char`` (kiểu char).

int* (*arrayPointerFunction[SIZE])(int) mảng các con trỏ hàm.

arrayPointerFunction (biến arrayPointerFunction) -> [SIZE] (là một mảng) -> (*)(int) (các con trỏ hàm đầu vào là int) -> *(trả về một con trỏ) ->> int (đến 1 biến int).

char (& (* arrayPointerFunctionBuffer[SIZE])(char (&)[BUFFER_SIZE]))[BUFFER_SIZE]

Mảng các con trỏ hàm có kiểu dữ liệu vào là một tham chiếu đến 1 mảng. Kiểu trả về cũng là tham chiếu đến 1 mảng.


P/S Cái này mình mới hoc không lâu chưa hiểu rõ lắm. Hi vọng mọi người cho ý kiến.


Phân biệt int* p và int *p, vấn đề về reference
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?