1. Khảo sát vùng nhớ của mảng một chiều và hai chiều
Đoạn mã dưới đây minh họa cách bộ nhớ được cấp phát cho các mảng trong C. Chúng ta sẽ kiểm tra kích thước thực tế占用 (sizeof) và địa chỉ của từng phần tử để xác định tính liên tục của vùng nhớ.
#include <stdio.h>
#define SIZE_1D 4
#define ROWS 2
#define COLS 4
void analyze_1d() {
int data[SIZE_1D] = { 1, 9, 8, 4 };
int i;
// In ra tổng số byte mà mảng chiếm giữ
printf("sizeof(data) = %d\n", sizeof(data));
// Duyệt và in địa chỉ cùng giá trị từng phần tử
for (i = 0; i < SIZE_1D; ++i)
printf("%p: %d\n", &data[i], data[i]);
// In giá trị của tên mảng (địa chỉ đầu tiên)
printf("data = %p\n", data);
}
void analyze_2d() {
int matrix[ROWS][COLS] = { {1, 9, 8, 4}, {2, 0, 4, 9} };
int i, j;
// In ra tổng số byte của mảng hai chiều
printf("sizeof(matrix) = %d\n", sizeof(matrix));
// Duyệt và in địa chỉ, giá trị từng phần tử
for (i = 0; i < ROWS; ++i)
for (j = 0; j < COLS; ++j)
printf("%p: %d\n", &matrix[i][j], matrix[i][j]);
printf("\n");
// In địa chỉ cơ sở của mảng và từng hàng
printf("matrix = %p\n", matrix);
printf("matrix[0] = %p\n", matrix[0]);
printf("matrix[1] = %p\n", matrix[1]);
printf("\n");
}
int main() {
printf("Kiểm tra 1: Mảng một chiều kiểu int\n");
analyze_1d();
printf("\nKiểm tra 2: Mảng hai chiều kiểu int\n");
analyze_2d();
return 0;
}
Kết quả thực thi cho thấy các phần tử trong mảng được lưu trữ liên tiếp nhau trong bộ nhớ. Đối với mảng hai chiều, tên mảng và tên hàng đầu tiên trỏ về cùng một địa chỉ cơ sở. Kích thước của một hàng tương ứng với số byte cần thiết để lưu trữ toàn bộ các cột trong hàng đó.
2. Xử lý mảng một chiều: Tính trung bình loại trừ cực trị
Bài toán yêu cầu nhập một dãy số nguyên, sau đó tính giá trị trung bình cộng của dãy sau khi đã loại bỏ đi giá trị lớn nhất và giá trị nhỏ nhất.
#include <stdio.h>
#define MAX_LEN 100
// Khai báo hàm
void read_values(int arr[], int count);
double calc_average_exclude_extremes(int arr[], int count);
int main() {
int dataset[MAX_LEN];
int n, i;
double result;
while (printf("Nhap so luong phan tử n: "), scanf("%d", &n) != EOF) {
read_values(dataset, n);
result = calc_average_exclude_extremes(dataset, n);
printf("Ket qua = %.2f\n\n", result);
}
return 0;
}
// Định nghĩa hàm nhập liệu
void read_values(int arr[], int count) {
int i;
for (i = 0; i < count; ++i)
scanf("%d", &arr[i]);
}
// Định nghĩa hàm tính toán
double calc_average_exclude_extremes(int arr[], int count) {
int i, max_val, min_val;
double sum = 0;
max_val = min_val = arr[0];
for (i = 0; i < count; ++i) {
sum += arr[i];
if (arr[i] > max_val)
max_val = arr[i];
else if (arr[i] < min_val)
min_val = arr[i];
}
// Tránh chia cho 0 nếu mảng quá nhỏ
if (count <= 2) return 0;
return (sum - max_val - min_val) / (count - 2);
}
Hàm đọc dữ liệu chịu trách nhiệm lưu trữ đầu vào vào mảng. Hàm tính toán sẽ duyệt qua mảng để tìm tổng, đồng thời cập nhật giá trị lớn nhất và nhỏ nhất gặp được, sau đó thực hiện phép chia cho số lượng phần tử còn lại.
3. Thao tác với mảng hai chiều: Khởi tạo và hiển thị
Ví dụ này demonstrates cách truyền mảng hai chiều vào hàm để khởi tạo giá trị đồng nhất và in ra màn hình dưới dạng ma trận.
#include <stdio.h>
#define DIMENSION 100
void show_matrix(int grid[][DIMENSION], int n);
void fill_matrix(int grid[][DIMENSION], int n, int val);
int main() {
int grid[DIMENSION][DIMENSION];
int n, value;
while (printf("Nhap kich thuoc n và gia trị: "), scanf("%d%d", &n, &value) != EOF) {
fill_matrix(grid, n, value);
show_matrix(grid, n);
printf("\n");
}
return 0;
}
void show_matrix(int grid[][DIMENSION], int n) {
int i, j;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j)
printf("%d ", grid[i][j]);
printf("\n");
}
}
void fill_matrix(int grid[][DIMENSION], int n, int val) {
int i, j;
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
grid[i][j] = val;
}
Khi khai báo tham số hàm cho mảng hai chiều, kích thước của chiều thứ hai (số cột) là bắt buộc phải指定 để trình biên dịch có thể tính toán offset bộ nhớ chính xác. Hàm khởi tạo gán một giá trị duy nhất cho toàn bộ các phần tử trong ma trận vuông.
4. Tìm giá trị trung vị (Median) của dãy số
Để tìm trung vị, dãy số cần được sắp xếp trước. Nếu số lượng phần tử là lẻ, trung vị là phần tử ở giữa. Nếu chẵn, trung vị là trung bình cộng của hai phần tử ở giữa.
#include <stdio.h>
#define CAPACITY 100
void read_values(int arr[], int n);
double find_median_value(int arr[], int n);
int main() {
int values[CAPACITY];
int n;
double ans;
while (printf("Nhap so luong phan tử n: "), scanf("%d", &n) != EOF) {
read_values(values, n);
ans = find_median_value(values, n);
printf("Trung vị = %g\n\n", ans);
}
return 0;
}
void read_values(int arr[], int n) {
for (int i = 0; i < n; ++i)
scanf("%d", &arr[i]);
}
double find_median_value(int arr[], int n) {
// Sắp xếp nổi bọt
for (int i = 0; i < n - 1; ++i) {
for (int j = 0; j < n - i - 1; ++j) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
if (n % 2 == 1)
return arr[n / 2];
else
return (arr[n / 2 - 1] + arr[n / 2]) / 2.0;
}
Thuật toán sắp xếp được tích hợp trực tiếp vào hàm tìm trung vị để đảm bảo dãy số đã được orden hóa trước khi truy cập phần tử ở vị trí giữa.
5. Xoay ma trận vuông theo chiều ngang
Bài toán yêu cầu dịch chuyển các cột của ma trận vuông sang phải một đơn vị. Cột ngoài cùng bên phải sẽ được chuyển về cột đầu tiên bên trái.
#include <stdio.h>
#define MAX_SIZE 100
void input_matrix(int mat[][MAX_SIZE], int n);
void print_matrix(int mat[][MAX_SIZE], int n);
void shift_columns_right(int mat[][MAX_SIZE], int n);
int main() {
int mat[MAX_SIZE][MAX_SIZE];
int n;
printf("Nhap kich thuoc ma trận n: ");
scanf("%d", &n);
input_matrix(mat, n);
printf("Ma trận gốc:\n");
print_matrix(mat, n);
shift_columns_right(mat, n);
printf("Ma trận sau khi xoay:\n");
print_matrix(mat, n);
return 0;
}
void input_matrix(int mat[][MAX_SIZE], int n) {
int i, j;
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
scanf("%d", &mat[i][j]);
}
void print_matrix(int mat[][MAX_SIZE], int n) {
int i, j;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j)
printf("%4d", mat[i][j]);
printf("\n");
}
}
void shift_columns_right(int mat[][MAX_SIZE], int n) {
int i, j;
int last_col[MAX_SIZE];
// Lưu trữ cột cuối cùng
for (i = 0; i < n; ++i){
last_col[i] = mat[i][n - 1];
}
// Dịch các cột còn lại sang phải
for (j = n - 1; j > 0; --j){
for (i = 0; i < n; ++i){
mat[i][j] = mat[i][j - 1];
}
}
// Gán lại cột đầu tiên từ dữ liệu đã lưu
for (i = 0; i < n; ++i){
mat[i][0] = last_col[i];
}
}
Quá trình xoay thực hiện bằng cách tạm lưu cột cuối cùng vào một mảng phụ, sau đó dịch tuần tự các cột từ phải sang trái, cuối cùng là gán lại dữ liệu đã lưu vào cột đầu tiên.
6. Chuyển đổi hệ cơ số từ thập phân
Hàm này nhận vào một số nguyên thập phân và chuyển đổi nó sang hệ cơ số bất kỳ (nhị phân, bát phân, thập lục phân) rồi in ra màn hình.
#include <stdio.h>
#define BUFFER_SIZE 100
void convert_decimal_to_base(int num, int base);
int main() {
int x;
while (printf("Nhap so thap phân: "), scanf("%d", &x) != EOF) {
convert_decimal_to_base(x, 2); // Nhị phân
convert_decimal_to_base(x, 8); // Bát phân
convert_decimal_to_base(x, 16); // Thập lục phân
printf("\n");
}
return 0;
}
void convert_decimal_to_base(int num, int base) {
char map[] = "0123456789ABCDEF";
char buffer[BUFFER_SIZE];
int idx = 0;
if (num == 0){
printf("0");
return;
}
// Xử lý số âm nếu cần, ở đây giả sử số dương
while (num > 0){
buffer[idx++] = map[num % base];
num = num / base;
}
// In ngược chuỗi kết quả
for (int j = idx - 1; j >= 0; j--){
printf("%c", buffer[j]);
}
printf("\n");
}
Thuật toán sử dụng phép chia lấy dư để lấy từng chữ số theo hệ cơ số mới, lưu vào mảng tạm và sau đó in ngược lại để có được biểu diễn chính xác của số đó.