Thứ Bảy, 9 tháng 1, 2016


Chào các bạn!

Hôm nay mình xin chia sẻ một số từ khóa để các bạn có thể học lập trình Java Core từ cơ bản đến nâng cao.




JAVA BASIC
  • Java - Home
  • Java - Overview
  • Java - Environment Setup
  • Java - Basic Syntax
  • Java - Object & Classes
  • Java - Basic Datatypes
  • Java - Variable Types
  • Java - Modifier Types
  • Java - Basic Operators
  • Java - Loop Control
  • Java - Decision Making
  • Java - Numbers
  • Java - Characters
  • Java - Strings
  • Java - Arrays
  • Java - Date & Time
  • Java - Regular Expressions
  • Java - Methods
  • Java - Files and I/O
  • Java - Exceptions

JAVA OBJECT ORIENTED
  • Java - Inheritance
  • Java - Overriding
  • Java - Polymorphism
  • Java - Abstraction
  • Java - Encapsulation
  • Java - Interfaces
  • Java - Packages
  • 3. Java Advanced
  • Java - Data Structures
  • Java - Collections
  • Java - Generics
  • Java - Serialization
  • Java - Networking
  • Java - Sending Email
  • Java - Multithreading
  • Java - Applet Basics
  • Java - Documentation

Các từ khóa để học về Java Swing hoặc Android sẽ được mình cập nhật trong các bài viết sau.Tham khảo bài viết tương tự với ngôn ngữ lập trình C# tại: Trình tự học C# từ cơ bản đến nâng cao

Chào các bạn, chúc các bạn học tốt!



Chào các bạn!

Hôm nay mình xin chia sẻ một số từ khóa để các bạn có thể học lập trình C# từ cơ bản đến nâng cao.




  • C# - Overview
  • C# - Environment
  • C# - Program Structure
  • C# - Basic Syntax
  • C# - Data Types
  • C# - Type Conversion
  • C# - Variables
  • C# - Constants
  • C# - Operators
  • C# - Decision Making
  • C# - Loops
  • C# - Encapsulation
  • C# - Methods
  • C# - Nullables
  • C# - Arrays
  • C# - Strings
  • C# - Struct
  • C# - Enums
  • C# - Classes
  • C# - Inheritance
  • C# - Polymorphism
  • C# - Operator Overloading
  • C# - Interfaces
  • C# - Namespaces
  • C# - Preprocessor Directives
  • C# - Regular Expressions
  • C# - Exception Handling
  • C# - File I/O
  • C# - Advanced Tutorial
  • C# - Attributes
  • C# - Reflection
  • C# - Properties
  • C# - Indexers
  • C# - Delegates
  • C# - Events
  • C# - Collections
  • C# - Generics
  • C# - Anonymous Methods
  • C# - Unsafe Codes
  • C# - Multithreading


Các bạn cứ học theo từng mức độ, search các từ khóa này mà học thì sẽ dễ học và tiện nắm bắt các kiến thức hơn
Tham khảo các từ khóa tương tự với ngôn ngữ Java tại: Trình tự học Java Core từ cơ bản đến nâng cao

Chúc các bạn thành công!



Thứ Hai, 4 tháng 1, 2016

- Đây là mã nguồn tôi viết
//a + i <=> &a[0 + i] ;

//*(a+i) <=> a[i]
void NhapMang(int *a, int n)
{
//int *pa = a; // Cách 1: Lúc này địa chỉ biến pa cũng là địa chỉ biến a, dùng cho TH có con trỏ pa
int *pa = &a[0]; // Cách 2
for(int i = 0; i < n; i++)
{
printf("\nNhap a[%d]: ", i);
//scanf("%d", &a[i]);
//scanf("%d", &pa[i]);
//scanf("%d", a + i);
//scanf("%d", pa + i);
//scanf("%d", a++);
scanf("%d", pa++);
}
}
// &a[i] <=> (a + i) <=> (pa + i) <=> &pa[i]
void XuatMang(int *a, int n)
{
//int *pa = a; // Giải thích giống
int *pa = &a[0]; // Cách 2
for(int i = 0; i < n; i++)
{
//printf("%4d", a[i]);
//printf("%4d", pa[i]);
//printf("%4d", *(a + i));
//printf("%4d", *(pa + i));
//printf("%4d", *(a++));
printf("%4d", *(pa++));
}
}
int main()
{
int n;
do{
printf("\nNhap so luong phan tu cua mang: ");
scanf("%d", &n);
if(n < 0)
{
printf("\nSo luong phan tu khong hop le. Xin kiem tra lai !");
}
}while(n < 0);

int *a = (int *)malloc(n * sizeof(int));
//a = (int *)calloc(n, sizeof(int));
//a = (int *)realloc(0, n * sizeof(int));

NhapMang(a, n);
XuatMang(a, n);
free(a);

getch();
return 0;
}
- Hàm cấp phát mảng n số thực(xác định số lượng phần tử trước khi cấp phát)
void arrayFloatOutput(float a[], int n)
{
for(int i = 0; i < n; i++)
{
printf("\n%f", a[i]);
}
}

float* arrayFloatInput(int* n)
{
float *a = NULL;
int m;
scanf("%d", &m);
if(m <= 0)
{
return NULL;
}
*n = m;
a = (float*)calloc(m, sizeof(float));
if(a != NULL)
{
for(int i = 0; i < m; i++)
{
scanf("%f", &a[i]);
}
}
return a;
}

int main()
{
float *B; int nB;
printf("Number and elements: ");
B = arrayFloatInput(&nB);
if(B != NULL)
{
// Do something here
arrayFloatOutput(B, nB);
// Free Allocated memory
free(B);
}
getch();
return 0;
void arrayFLoatOutput(float a[], int n)
{
for(int i = 0; i < n; i++)
{
cout << a[i] << "\n";
}
}

float* arrayFloatInput(int &n)
{
cin >> n;
if(n <= 0)
{
return NULL;
}
float* a = new float[n];
if(a != NULL)
{
for(int i = 0; i < n; i++)
{
cin >> a[i];
}
}
return a;
}
int main()
{
float *B; int nB;
printf("Number and elements: ");
B = arrayFloatInput(nB);
if(B != NULL)
{
// Do something here
arrayFLoatOutput(B, nB);
// Free Allocated memory
delete[]B;
}
- Hàm cấp phát mảng n số thực(dùng biến cấu trúc)
typedef struct{
int n;
float* members;
}floatArray;

void floatArrayInit(floatArray* a, int n)
{
a->n = n;
a->members = (float*)calloc(n, sizeof(float));
}

void floatArrayFree(floatArray* a)
{
if(a != NULL)
{
if(a->members != NULL)
{
free(a->members);
}
}
}

void floatArrayInput(floatArray* a)
{
int m;
if(a == NULL) return;
scanf("%d", &m);
if(m <= 0) return;
floatArrayInit(a, m);
if(a->members != NULL)
{
for(int i = 0; i < m; i++)
{
scanf("%f", &(a->members[i]));
}
}
}

void floatArrayOutput(floatArray* a)
{
if(a == NULL || a->members == NULL)
{
return;
}
for(int i = 0; i < a->n; i++)
{
printf("\n%f", a->members[i]);
}
}

int main()
{
floatArray B;
printf("\nNumber and elements: ");
floatArrayInput(&B);
// Do something here
printf("\nArray is: ");
floatArrayOutput(&B);

// Free allocated memory
floatArrayFree(&B);

getch();
return 0;
typedef struct{
int n;
float* members;
}floatArray;

void floatArrayInit(floatArray& a, int n)
{
a.n = n;
a.members = new float[n];
}

void floatArrayFree(floatArray& a)
{

if(a.members != NULL)
{
delete[]a.members;
}

}

void floatArrayInput(floatArray& a)
{
int m;
cin >> m;
if(m <= 0) return;
floatArrayInit(a, m);
if(a.members != NULL)
{
for(int i = 0; i < m; i++)
{
cin >> a.members[i];
}
}
}

void floatArrayOutput(floatArray& a)
{
if(a.members == NULL)
{
return;
}
for(int i = 0; i < a.n; i++)
{
cout << a.members[i] << " ";
}
}

int main()
{
floatArray B;
printf("\nNumber and elements: ");
floatArrayInput(B);
// Do something here
printf("Array is: ");
floatArrayOutput(B);

// Free allocated memory
floatArrayFree(B);

getch();
return 0;
- Hàm cấp phát mảng n số thực (không hỏi trước số lượng phần tử)
void floatArrOut(float a[], int n)
{
for(int i = 0; i < n; i++)
{
printf("%f", a[i]);
}
}

float* floatArrPushBack(float*a, int *n, float x)
{
int m = (*n) + 1;
float* anew = (float*)realloc(a, m * sizeof(float));
if(anew != NULL)
{
anew[*n] = x;
(*n)++;
}
return anew;
}

float * floatArrIn(int *n)
{
float* anew, *a = NULL;
float x;
*n = 0;
while(scanf("%f", &x) > 0)
{
anew = floatArrPushBack(a, n, x);
if(anew != NULL)
{
a = anew;
}
}
return a;
}

int main()
{
float *B;
int nB;
printf("Input element: \n");
B = floatArrIn(&nB);
// Do something here
printf("%d element(s): \n", nB);
floatArrOut(B, nB);
// Free Allocated memory
if(B != NULL)
free(B);
getch();
return 0;
}
void floatArrOut(float a[], int n)
{
for(int i = 0; i < n; i++)
{
cout << a[i] << " ";
}
}

void floatArrPushBack(float *&a, int &n, float x)
{
int m = n + 1;
float *anew = (float*)realloc(a, m * sizeof(float));
if(anew != NULL)
{
anew[n] = x;
n++;
a = anew;
}
}

void floatArrIn(float*& a, int &n)
{
float x;
a = NULL;
n = 0;
while(cin >> x)
{
floatArrPushBack(a, n, x);
}
}
int main()
{
float *B; int nB;
cout << "Input elements: " << endl;
floatArrIn(B, nB);
// Do something here
cout << nB << "element(s): " << endl;
floatArrOut(B, nB);
// Free Alocated memory
if(B != NULL)
free(B);

getch();
return 0;
}
- Hàm cấp phát mảng các phần tử kiểu tùy ý và áp dụng cho kiểu Phân Số
// Tập tin _ARRAY1D_T_H
template <class T>
void arrPushBack(T *&a, int &n, T x)
{
int m = n + 1;
T* anew = (T*)realloc(a, m * sizeof(T));
if(anew != NULL)
{
anew[n] = x; n++;
a = anew;
}
}
template <class T>
void arrInput(T *&a, int &n)
{
T x;
a = NULL; n = 0;
while(cin >> x)
{
arrPushBack(a, n, x);
}
}
template <class T>
void arrOutput(T a[], int n)
{
for(int i = 0; i < n; i++)
{
cout << a[i] << " ";
}
}
#endif // -------End of FILE-------------
struct PhanSo
{
int tuso, mauso;
};

ostream& operator<< (ostream& outDev, const PhanSo& ps)
{
if(ps.mauso == 1|| ps.tuso == 0)
outDev << ps.tuso;
else
outDev << ps.tuso << "/" << ps.mauso;
return outDev;
}
istream& operator>> (istream& inDev, PhanSo& ps)
{
inDev >> ps.tuso >> ps.mauso;
return inDev;
}

int main()
{
PhanSo *B; int nB;
cout << "Input elements of array: \n";
arrInput(B, nB);
// Do something here
cout << nB << " element(s): \n";
arrOutput(B, nB);
// Free Alocated memory
if(B != NULL)
free(B);

getch();
return 0;
}
Đoạn chương trình minh họa về việc tính hiệu của hai con trỏ đang lưu địa chỉ bộ nhớ. Trước tiên là các dòng mã đang bị chú thích, nếu gỡ bỏ việc ghi chú thì sẽ bị lỗi biên dịch. Khi chạy chương trình thì kết quả in ra là d1 = 6, d2 = 24, d3 = 12, Distance = 24. Trong đó giá trị d2 và Distance là 24 chính là độ lệch tính bằng byte của địa chỉ bộ nhớ do cách tính toán ở các dòng "ép kiểu sang char*" và "ép kiểu thô bạo thành số nguyên long". Bởi vì ptr1 giữ địa chỉ &a[7] và ptr2 giữ địa chỉ &a[1] nên độ lệch địa chỉ tính bằng byte giữa ptr1 và ptr2 là d2 = (7 - 1) x sizeof(long) = 6 x 4 = 24 byte. Giá trị d1 là 6 vì lý do là d1 = 24/sizeof(long) = 24/4 = 6. Giá trị d3 = 12 vì lý do d3 = 24/sizeof(short) = 24/2 = 12.

int main()
{
long a[10];
void *ptr1 = &a[7], *ptr2 = &a[1];
// long d0 = ptr1 - ptr2; Lỗi do tính hiệu số hai con trỏ kiểu void không biết kích thước
long d1 = (long*)ptr1 - (long*)ptr2;
long d2 = (char*)ptr1 - (char*)ptr2;
long d3 = (short*)ptr1 - (short*)ptr2;
printf("\nd1 = %ld", d1);
printf("\nd2 = %ld", d2);
printf("\nd3 = %ld", d3);
printf("\nDistance = %ld", (long)ptr1 - (long)ptr2);

// long d4 = (long*)ptr1 - (char*)ptr2 // Lỗi vì tính hiệu số hai con trỏ khác kiểu
// long d5 = (long*)ptr1 - (float*)ptr2 // Lỗi vì tính hiệu số hai con trỏ khác kiểu
getch();
return 0;
}
Chúng ta sẽ xét 1 số ví dụ mình họa cho quy tắc tính toán địa chỉ vừa được trình bày. Hình trên trình bày một ví dụ về tính toán địa chỉ con trỏ và các ký pháp lúc viết chương trình. Con trỏ p kiểu double nhận địa chỉ của biến a[1] là phần tử thứ hai trong mảng năm số. Vì p = &a[1] và đang dùng cùng kiểu double nên theo quy ước ký pháp ở bài trước thì *p, p[0], và a[1] là cùng 1 biến, tức là mặc dù viết khác nhưng chúng tham chiếu đến cùng 1 ô nhớ 8-byte(kích thước biến double) có thể chứa một số thực kiểu double. Địa chỉ p + 1 dời đi so với p một độ dời bằng với 1 x sizeof(double) = 8 byte, nên p + 1 cũng là &a[2], do đó *(p + 1), p[1], a[2] là ba cách viết khác nhau cùng tham chiếu đến cùng một biến. Tương tự *(p + 3), p[3], a[4] cũng tham chiếu đến cùng 1 biến a[4].
Địa chỉ (float*)p + 4 là một con trỏ kiểu float* dời đi so với p một độ dời là 4 x sizeof(float) = 16 byte = 2 x (8 byte). Do đó vì p đang giữ địa chỉ của a[1] nên (float*)p + 4 bằng với: địa chỉ (a[1]) + 16 byte và trùng với địa chỉ của a[3]. Tuy nhiên ký pháp biến *((float*)p + 4) (một biến float kích thước 4-byte) vô nghĩa vì tương đương với phân nửa của biến a[3] (một biến double kích thước 8-byte). Nếu ép kiểu để chuyển về double như là *(double*)((float*)p + 4) thì chính là biến a[3], cũng cùng nghĩa với *(p + 2).

Chủ Nhật, 3 tháng 1, 2016

Chính thức đã bước vào năm 2016 với cái tết Tây hoành tráng bằng những màn bắn pháo hoa ở những thành phố lớn như: Hà Nội - Đà Nẵng - Sài Gòn. Còn tết âm lịch, tết của dân tộc Việt Nam thì sao? Cộng đồng Blogger có trang trí gì cho những ngôi nhà nhỏ của mình trong dịp này?
Một thủ thuật rất hấp dẫn sẽ giúp bạn trang trí cho blog của mình trở nên đúng dịp nhất khi có những màn bắn pháo trực tiếp ngay trên chính blog của mình.
Chúc mừng năm mới 2016 với việc trang trí pháo hoa cho Blogger
chi tiết
-Các phép tính cơ bản cho các biến con trỏ có kiểu(tức không phải là void*)
*Phép cộng, trừ với số: con trỏ(địa chỉ bộ nhớ) +(hoặc -) số nguyên. Phép toán này có ý nghĩa là tạo ra một địa chỉ bộ nhớ có độ lệch so với địa chỉ gốc một số byte tùy thuộc vào kiểu con trỏ và số nguyên mà ta cộng hay trừ vào địa chỉ.
*Phép trừ 2 con trỏ: con trỏ(địa chỉ 1) - con trỏ(địa chỉ 2). Phép toán này yêu cầu 2 con trỏ phải có cùng kiểu. Kết quả cho ra độ lệch địa chỉ có đơn vị tính tùy thuộc vào kiểu con trỏ.
 -Riêng đối với kiểu void*(con trỏ vô kiểu) thì không thể thực hiện 2 phép toán nói trên. Khi muốn tính toán địa chỉ trên con trỏ vô kiểu thì ta phải ép kiểu con trỏ. Thông thường nếu muốn tính theo đơn vị byte thì các con trỏ được ép kiểu sang char*.
- Giả sử pVar là biến con trỏ kiểu T* với T là một kiểu dữ liệu nào đó khác kiểu void và n là 1 số nguyên(có thể âm hay dương). Khi đó pVar + n là địa chỉ bộ nhớ sẽ dời đi so với địa chỉ pVar một độ dời là n x sizeof(T).Nghĩa là chúng ta có công thức sau:
 Địa chỉ(pVar + n) = Địa chỉ(pVar) + n x sizeof(T)
Công thức nói trên cũng lý giải tại sao con trỏ kiểu void* không thể cộng hay trừ với số nguyên bởi vì sizeof(void) không xác định. Đối với con trỏ kiểu char* vì sizeof(char) = 1 nên khi T = char thì pVar + n dời đi so với pVar đúng n byte.
 Quy ước ký pháp: Với điều kiện địa chỉ hợp lệ thì ký hiệu *(pVar + n) được đồng nhất với biến kiểu T tại địa chỉ pVar + n, biến này cũng có thể được truy xuất đến bằng cách dùng ký hiệu mảng pVar[n].
 - Giả sử 2 biến con trỏ pVar1 và pVar2 cùng có kiểu là T* với T là 1 kiểu dữ liệu nào đó khác void. Khi đó pVar1 - pVar2 là độ lệch được tính bằng sizeof(T), nói 1 cách đơn giản hơn là độ lệch này được tính bằng số lượng các phần tử có kiểu là T. Tức là ta có công thức sau:
                             Địa chỉ(pVar1) - Địa chỉ(pVar2) 
 pVar1 - pVar2 = ---------------------------------------
                                          sizeof(T) 
-> Áp dụng công thức khi T = char thì (char*)pVar1 - (char*)pVar2 là độ lệch địa chỉ giữa 2 con trỏ được tính bằng đơn vị là byte.
Các chương trình viết bằng C/C++ chuẩn có thể xin cấp phát bộ nhớ từ hệ điều hành, địa chỉ đầu của vùng nhớ được cấp phát sẽ được trả về thông qua biến con trỏ. Sau khi vùng nhớ sử dụng xong, người lập trình cần phải giải phóng vùng nhớ, để trả về bộ nhớ cho hệ thống.

void main()
{
int n; float *a = NULL; // Khai báo con trỏ a kiểu float*
printf("\nEnter array size: ");
scanf("%d", &n);
if(n < 1)
{
printf("\nInvalid size!"); return;
}
a = (float*)malloc(n * sizeof(float)); // gán đến địa chỉ vùng nhớ xin được cấp phát
if(a == NULL)
{
printf("Memory error!"); return;
}
for(int i = 0; i < n; i++)
{
printf("a[%d] = ", i);
scanf("%f", &a[i]);
}
printf("\nData: ");
for(int i = 0; i < n; i++)
{
printf("%f", a[i]);
// do something here
// Finally freeing memory
}
free(a);
getch();
}

void main()
{
int n; float *a = NULL; // Khai báo con trỏ a kiểu float*
cout << "Enter array size: ";
cin >> n;
if(n < 1)
{
cout << "Invalid size!"; return;
}
a = new float[n]; // gán đến địa chỉ vùng nhớ xin được cấp phát
if(a == NULL)
{
cout << "Memory Error!"; return;
}
for(int i = 0; i < n; i++)
{
cout << "a[" << i << "] = ";
cin >> a[i];
}
cout << "Data: ";
for(int i = 0; i < n; i++)
{
cout << a[i] << " ";
// do something here
// Finally freeing memory
}
delete[]a;
getch();
}
Mã nguồn minh họa việc gán con trỏ bằng 1 vùng nhớ được cấp phát, được viết bằng ngôn ngữ C và C++. Chương trình này chỉ làm 1 việc đơn giản là xin cấp phát 1 mảng n số thực kiểu float, nhập n số thực, xuất ra màn hình và sau cùng giải phóng bộ nhớ. Biến con trỏ a kiểu float* được khai báo, sau đó gán đến địa chỉ vùng nhớ xin được cấp phát. Đối với C++, việc gọi new float[n] nghĩa là xin 1 vùng nhớ liên tục chứa được n số float, thực chất thì vùng nhớ này gồm 4n byte bởi vì mỗi số float có kích thước là 4 byte theo chuẩn IEEE. Đối với C, bởi vì hàm malloc() cần nhận vào 1 tham số quy định số byte được cấp phát và trả về con trỏ kiểu void* nên việc gọi hàm cấp phát có phức tạp hơn. Chỉ thị (float*)malloc(n*sizeof(float)) có nghĩa là xin 1 vùng nhớ có kích thước là n*sizeof(float) = 4n byte, bởi vì địa chỉ vùng nhớ trả về kiểu void* nên phải ép kiểu sang float* mới có thể gán được vào biến con trỏ a có kiểu là float*.
Chào các bạn !
Khá lâu rồi IT Việt 360 mới có bài viết quay trở lại, đó là một sự thiếu sót và chúng tôi sẽ cố gắng khắc phục nó trong năm 2016. Một thủ thuật nho nhỏ mà trong dịp đầu năm muốn chia sẻ với các bạn, đặc biệt là những bạn nào đang sử dụng blogger để làm 1 trang chia sẻ video nguồn chủ yếu từ Youtube của mình.
Bài viết trước đây mình cũng đã chia sẻ nội dung tương tự. Bạn có thể xem qua: Cách lấy hình ảnh Video Youtube tự động cho blogspot
Còn nội dung dưới đây là thêm 1 cách nữa để bạn có nhiều lựa chọn hơn.
BẮT ĐẦU NÀO
* Mọi video của Youtube đều có cấu trúc link hình ảnh dạng:
http://img.youtube.com/vi/VIDEO ID/IMAGE NUMBER.jpg
Ví dụ:
Link video: https://www.youtube.com/watch?v=TTEijimZwag
Có những kích thước hiển thị hình ảnh video tùy chọn sau (theo cấu trúc link ở trên)

  • Hiển thị hình ảnh video với kích thước mặc định
http://img.youtube.com/vi/TTEijimZwag/0.jpg
Ta được kết quả hình ảnh lớn đại diện của video đó 480x360 (Pixel)
Hình ảnh kích thước mặc định
chi tiết
Trong nhiều tình huống, chúng ta có thể cần viết các hàm kết hợp sử dụng cả tham số con trỏ và giá trị trả về kiểu con trỏ. Chằng hạn hàm trả về chuỗi lớn hơn khi so sánh theo thứ tự alphabet. Hàm này có thể được mô tả là char* strmax(char* str1, char* str2); khi chuỗi str1 lớn hơn str2 (tức là đứng sau str2 theo thứ tự từ điển) thì hàm trả về str1, ngược lại trả về str2. Trường hợp này ta thấy hàm strmax() nhận vào các tham số là 2 con trỏ kiểu char* và cũng trả về con trỏ kiểu char*.

char* strmax(char* str1, char* str2)
{
if(strcmp(str1, str2) > 0)
{
return str1;
}
return str2;
}
Một trong những lợi thế của hàm trả về con trỏ là chúng ta có thể gọi lồng các hàm để viết mã gọn hơn. Chẳng hạn sau khi tìm chuỗi lớn nhất chúng ta có nhu cầu chuyển hết các ký tự trong chuỗi đó thành chữ hoa bằng cách gọi hàm strupr().

int main()
{
const int maxLen = 256;
char s1[maxLen], s2[maxLen];
printf("\nInput s1 = "); gets(s1);
printf("\nInput s2 = "); gets(s2);
printf("\nResult: %s", strupr(strmax(s1, s2))); // Gọi lồng hàm
getch();
return 0;
}
Bản thân hàm printf() cũng cho phép nhận vào thàm số con trỏ kiểu char* khi chúng ta dùng định dạng %s trong chuỗi định dạng in. Một điểm cần lưu ý thêm là 2 biến s1 và s2 được khai báo trong hàm main() dưới dạng 2 mảng ký tự, nhưng ý nghĩa sử dụng lại là các chuỗi ký tự. Khi truyền s1 và s2 đến hàm strmax() thì s1 tương đương &s1[0], còn s2 tương đương &s2[0]. Vì vậy cả 2 đối số s1, s2 là 2 địa chỉ bộ nhớ có kiểu là char*.
-Kiểu tham chiếu (reference) của C++ thực chất được cài đặt bằng kỹ thuật con trỏ, nhưng cú pháp lập trình lại tương tự như biến thông thường.Dưới đây là hàm refMinAbs() cài đặt tương tự như 2 hàm indexMinAbs() và pointerMinAbs() ở bài trước và chỉ khác ở 2 chỗ: giá trị trả về và chỉ thị return.

float& refMinAbs(float a[], int n)
{
int i = 1, idx = 0;
while(i < n)
{
if(fabs(a[i]) < fabs(a[idx]))
{
idx = i;
}
i++;
}
return a[idx];
}
- Trong hàm main() của chương trình chạy thử, việc gọi hàm với chỉ thị float& refMin = refMinAbs(B, n) nhằm để refMin tham chiếu đến phần tử tìm được. Lưu ý dấu & trong float& là thực sự cần thiết vì nếu ta thay bằng lời gọi hàm không có dấu & như là float refMin = refMinAbs(B, n) thì chương trình vẫn chạy nhưng biến refMin được gán bằng giá trị của phần tử tìm được chứ không tham chiếu(xem như đồng nhất) với phần tử tìm được. Trong hàm main() thì cả ba địa chỉ &B[id], pMin, &refMin đều cùng 1 giá trị địa chỉ bộ nhớ.

int main()
{
float B[] = {-9, 12.7F, 2.3F, 11, -10, -3.6F};
int n = sizeof(B)/sizeof(B[0]);
int id = indexMinAbs(B, n);
float* pMin = pointerMinAbs(B, n);
float& refMin = refMinAbs(B, n);
printf("Values: %f %f %f\n", B[id], *pMin, refMin);
printf("Memory Adresses: 0x%x 0x%x 0x%x", &B[id], pMin, &refMin);

getch();
return 0;
}
- 2 cách cài đặt hàm tìm phần tử có giá trị tuyệt đối nhỏ nhất trong mảng 1 chiều gồm n số thực kiểu float

int indexMinAbs(float a[], int n)
{
int i = 1, idx = 0;
while(i < n)
{
if(fabs(a[i]) < fabs(a[idx]))
{
idx = i;
}
i++;
}
return idx;
}

float *pointerMinAbs(float a[], int n)
{
int i = 1, idx = 0;
while(i < n)
{
if(fabs(a[i]) < fabs(a[idx]))
{
idx = i;
}
i++;
}
return &a[idx];
}
- Địa chỉ của phần tử tìm được là &a[idx] được trả về thay vì là chỉ số của mảng idx

int main()
{
float B[] = {-9, 12.7F, 2.3F, 11, -10, -3.6F};
int n = sizeof(B)/sizeof(B[0]);
int id = indexMinAbs(B, n);
float* pMin = pointerMinAbs(B, n);
printf("Values: %f %f\n", B[id], *pMin);
printf("Memory Adresses: 0x%x 0x%x", &B[id], pMin);

getch();
return 0;
}
- Chương trình chính minh họa cho việc gọi thử 2 hàm indexMinAbs() và pointerMinAbs(). Khi chạy chương trình ta sẽ thấy B[id] và *pMin in tra cùng giá trị, hơn nữa các địa chỉ bộ nhớ &B[id] và pMin cũng in ra cùng giá trị.

Thứ Bảy, 2 tháng 1, 2016

Đôi khi địa chỉ biến được truyền qua một chuỗi các hàm trong 1 quy trình xử lý nào đó. Chẳng hạn ta muốn viết hàm ajust() để sau khi gọi ajust(&a, &b) thì nếu cần thiết ta phải hoán chuyển giá trị của a và b sao cho |a| <= |b| Trường hợp này, ajust() hàm nhận tham số địa chỉ biến và trong quá trình xử lý lại tiếp tục truyền các địa chỉ biến cho hàm swap() khi gọi hàm.

void swap(float *x, float *y)
{
float u = *x;
*x = *y;
*y = u;
}
void adjust(float *x, float *y)
{
if(fabs(*x) > fabs(*y))
//swap(&(*x), &(*y));
swap(x, y);
}
int main()
{
float a = -1845.3F, b = 234.3F;
adjust(&a, &b);
printf("\nNew values of a and b now are a = %.2f, b = %.2f", a, b);

getch();
return 0;
}
Hàm ajust() nhận 2 tham số x và y là địa chỉ của 2 biến số thực sẽ được gửi đến, tức là *x và *y có thể xem như chính là 2 biến số thực đó. Khi |*x| > |*y| thì chúng ta cần gọi hàm swap() để hoán chuyển nội dung của 2 biến gửi đến. Dòng mã thực hiện điều này là swap(&(*x), &(*y)) với ý nghĩa là đưa địa chỉ của các biến *x và *y đến hàm swap(). Tuy nhiên nếu diễn dịch kỹ thì &(*x) chính là "địa chỉ của biến mà x đang lưu địa chỉ": cụm từ này cho thấy &(*x) = x.

Categories

Sample Text

Được tạo bởi Blogger.

Must Read

Biểu mẫu liên hệ

Tên

Email *

Thông báo *

Popular Posts

Video

Popular Posts

Our Facebook Page