Tại sao phải ép kiểu Việc ép kiểu: p = int *mallocn*sizeofint; Là cần thiết vì hàm malloc trả về kiểu void*: void * mallocunsigned int nbytes; Kiểu void* chỉ 1 kiểu con trỏ chung, có
Trang 2mảng, tránh lãng phí không gian nhớ.
Trang 3Hàm malloc
void * malloc(unsigned int nbytes);
Hàm malloc được sử dụng để cấp phát động nbytes trong bộ nhớ.
malloc trả về con trỏ tới vùng nhớ được cấp phát nếu thành công, trả về con trỏ NULL
nếu thất bại.
Nên kiểm tra xem có cấp phát thành công
hay không.
Phải #include<stdlib.h>
Trang 4/* Cấp phát 1 mảng int với kích thước thích hợp */
p = (int *)malloc(n * sizeof(int));
Trang 5/* Đưa ra theo thứ tự ngược lại*/
printf("The numbers in reverse order are \n");
Trang 6Tại sao phải ép kiểu
Việc ép kiểu:
p = (int *)malloc(n*sizeof(int));
Là cần thiết vì hàm malloc trả về kiểu void*:
void * malloc(unsigned int nbytes);
Kiểu void* chỉ 1 kiểu con trỏ chung, có thể ép tới bất kì kiểu con trỏ nào.
Trang 7 Nếu p không trỏ đến 1 vùng nhớ đã được
cấp phát bởi malloc, sẽ xảy ra lỗi thi hành.
Luôn luôn phải nhớ giải phóng bộ nhớ nếu không cần đến chúng nữa.
Trang 8Exercise 2.1
Tạo hàm my_strcat():
- Đầu vào: 2 xâu s1,s2
- Đầu ra: trả về con trỏ trỏ tới xâu nối của 2 xâu s1,s2 (được cấp phát động).
- Ví dụ: xâu nối của “hello_” and “world!” là:
“hello_world!”
• Test hàm của bạn.
Trang 11Các cấu trúc - kiểu được định nghĩa bởi người dùng
Là 1 tập các biến dưới cùng 1 tên đơn
Là 1 cách thuận lợi để nhóm các thông tin có liên quan tới nhau.
Các biến trong struct(cấu trúc) được gọi la member (thành viên) hoặc field (trường)
Trang 12ĐỊnh nghĩa 1 cấu trúc
struct struct-name
{
field-type1 field-name1; field-type2 field-name2; field-type3 field-name3;
…
};
Trang 15Exercise 2.2
Cho 2 cấu trúc sau:
typedef struct point //điểm trong mặt phẳng (2 toạ độ)
Trang 16y_dist = p->y - c->center.y;
return (x_dist * x_dist + y_dist * y_dist <=
c->radius * c-c->radius);
}
Trang 17printf(“Nhập toạ độ điểm\n");
scanf("%lf%lf", &p.x, &p.y);
printf(“nhập toạ độ tâm đường tròn \n"); scanf("%lf%lf", &c.center.x, &c.center.y); printf(“Nhập bán kính \n");
Trang 18Con trỏ trong cấu trúc
Nếu 1 trường của cấu trúc là con trỏ, nó có thể là con trỏ trỏ tới chính bản sao của nó.
Trang 19Chế độ cho Binary file (file nhị fân)
"rb" Mở 1 file binary đã có để đọc
“wb” Tạo 1 file binary để ghi
“ab” Mở 1 file đã có để thêm dữ liệu vào cuối
“r+b” Mở 1 file binary đã có để đọc hoặc ghi
"w+b“ Tạo 1 file binary để đọc hoặc ghi
"a+b" Tạo mới hoặc mở 1 file đã có để thêm dữ
liệu vào cuối
Trang 20Quản lí file: làm việc với 1 khối dữ liệu
2 hàm vào/ra là fread() và fwrite() có thể dùng
để thực hiện các thao tác với khối dữ liệu.
Như các hàm quản lí file khác, chúng làm
việc với con trỏ file.
Trang 21 Nguyên mẫu:
size_t fread(void *ptr, size_t size,size_t n, FILE
*stream); //đọc n dữ liệu, (kích thước mỗi dữ liệu là size) từ file trỏ bởi stream lưu vào mảng ptr
ptr là con trỏ trỏ tới mảng lưu trữ dữ liệu
• size: kích thước mỗi phần tử mảng.
• n: số phần tử cần đọc.
• stream: con trỏ tới file đã được mở để đọc
• Hàm fread() trả về số phần tử thực tế được đọc.
Trang 22 Nguyên mẫu:
size_t fwrite(const void *ptr, size_t size,
size_t n, FILE *stream); //ghi n dữ liệu, (kích thước mỗi dữ liệu là size) mảng ptr vào file được trỏ đến bởi con trỏ stream
ptr là con trỏ tới mảng lưu trữ dữ liệu
• size: kích thước mỗi phần tử mảng.
• n: số phần tử cần ghi.
• stream: con trỏ tới file đã được mở để ghi
• Hàm fwrite() trả về số phần tử thực tế được ghi vào file.
Trang 23Hàm feof()
int feof(FILE *stream);
Trả về 0 nếu chưa tới cuối file, trả về số
nguyên # 0 nếu đã tới của file (kết thúc file)
Trang 24printf("Cannot open %s.\n", filename2);
reval = FAIL; exit(1);
Trang 25Exercise 2.3
Viết 1 chương trình sử dụng các phép toán thao tác trên file theo khối, copy nội dung từ file lab1.txt sang file lab1a.txt
Sử dụng fread(), fwrite(), feof().
Trang 26#include <stdio.h>
enum {SUCCESS, FAIL, MAX_LEN = 80};
void BlockReadWrite(FILE *fin, FILE *fout);//hàm đọc ghi dữ liệu theo khối main(void) {
FILE *fptr1, *fptr2;
char filename1[]= "lab1a.txt";
char filename2[]= "lab1.txt";
int reval = SUCCESS;
if ((fptr1 = fopen(filename1, "w")) == NULL){
printf("Cannot open %s.\n", filename1);
reval = FAIL;
} else if ((fptr2 = fopen(filename2, "r")) == NULL){
printf("Cannot open %s.\n", filename2);
Trang 28Exercise 2.4
Cải thiện chương trình trong bài 2.3 bằng cách nhận vào tên file qua tham số dòng lệnh.
Ví dụ: nếu tên chương trình của bạn là
“filecpy” , bạn có thể sử dụng nó theo
nguyên mẫu sau (trong Linux):
./filecpy haiku.txt haiku2.txt
Trang 29Gợi ý
Sử dụng argc[] và argv[]
if(argc<3) { printf("%s<file1><file2>\n",argv[0]); exit(1); }//kiểm tra nếu nhập chưa đủ 3 tham số
argv[1] và argv[2] là tên của file nguồn và file đích.
Trang 30Exercise 2.5 – vào ra theo cấu trúc
Tạo 1 sổ danh bạ điện thoại
Định nghĩa 1 cấu trúc gồm ”name”,
”telephone number”(số điện thoại), ”e-mail
address”(địa chỉ mail) Tạo 1 mảng chứa các phần tử có cấu trúc trên.Mảng chứa tối đa 100 fần tử.
Nhập khoảng 10 dữ liệu vào mảng.
Viết chương trình ghi nội dung của mảng vào
1 file (sử dụng fwrite()) tuỳ theo số fần tử dữ liệu có trong mảng, và đọc các dữ liệu đó trở lại mảng, sử dụng hàm fread().
Trang 32int i,n, irc; // return code
int reval = SUCCESS;
printf("How many contacts do you want to enter (<20)?");
scanf("%d", &n);
for (i=0; i<n; i++){
printf("name:"); scanf("%s",phonearr[i].name); printf("tel:"); scanf("%s",phonearr[i].tel);
printf("email:"); scanf("%s",phonearr[i].email); }
Trang 33if ((fp = fopen("phonebook.dat","w+b")) == NULL){ printf("Can not open %s.\n", "phonebook.dat"); reval = FAIL;
}
// ghi dữ liệu mảng vào file
irc = fwrite(phonearr, sizeof(phoneaddress), n, fp);
printf(" fwrite trả về = %d\n", irc);
fclose(fp);
Trang 34//đọc dữ liệu trở lại vào mảng
if ((fp = fopen("phonebook.dat","rb")) == NULL){ printf("Can not open %s.\n", "phonebook.dat"); reval = FAIL;
Trang 35Truy nhập file tuỳ ý
2 hàm fseek() và ftell()
fseek():hàm chuyển con trỏ file tới vị trí theo
ý muốn trong file
- Nguyên mẫu:
fseek(FILE *stream, long offset, int whence);
- stream: con trỏ tới file đã mở
- offset: chỉ ra số byte tính từ vị trí đã được
định trước.
- Whence: SEEK_SET, SEEK_CUR, và
SEEK_END
• SEEK_SET: tính từ đầu file
• SEEK_CUR: tính từ vị trí hiện tại
• SEEK_END: tính từ cuối file
Trang 36Truy nhập file tuỳ ý
ftell :thu được giá trị vị trí hiện tại.
- Nguyên mẫu:
long ftell(FILE *stream);
rewind(): thiết lập lại vị trí con trỏ file về đầu file.
- Nguyên mẫu:
void rewind(FILE *stream);
Trang 37Exercise 2.6 - cấp phát bộ nhớ động
Viết 1 chương trình nạp vào 1 phần dữ liệu được chỉ định của address book (bt trước),
ví dụ:”từ dữ liệu thứ 3 đến dữ liệu thứ 6”, hoặc “từ dữ liệu thứ 2 đến dữ liệu thứ 3”, sửa đổi lại dữ liệu đó và ghi nó trở lại vào file.
Nhưng bạn phải cấp phát bộ nhớ 1 cách tối cần thiết.Ví dụ:kích thước bộ nhớ cần thiết cho “từ dữ liệu thứ 3 đến dữ liệu thứ 6” là 4.Sử dụng hàm malloc.
Trang 38int i,n, irc; // return code
int reval = SUCCESS;
printf("Read from 2sd data to 3rd data \n");
Trang 40irc = fwrite(phonearr, sizeof(phoneaddress), 2, fp);
printf(" fwrite return code = %d\n", irc);
fclose(fp); free(phonearr);
return reval;
}
Trang 41Exercise 2.7
Có 1file text class1EF.txt
Viết chương trình thêm vào 1 dòng trống giữa các dòng trong file.
Trang 43 Dạng của dữ liệu được nạp vào từ đầu vào
chuẩn:đầu tiên là số lượng các số, sau đó là các số.
Ví dụ: input: 4 12 -45 56 3
- 4: số các số theo sau là 4
- 12 -45 56 3: các số cần được ghi vào file out.txt
- out.txt : 3 56 -45 12 26 //các số đưa ra theo thứ tự ngược lại Số 26 ở cuối cùng là tổng tất cả các số trước nó.
• Lưu ý: số lượng các số thay đổi nên phải sử dụng cấp phát động.
Trang 44Solution for homework
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//author: Cao Tuan Dung
//for HEDSPI project
enum {SUCCESS, FAIL};
int main(void)
{
FILE *fp;
int *p;
int i,n, value, sum;
int reval = SUCCESS;
printf("Enter a list of numbers with the first is the size of list:
\n");
scanf("%d", &n);
p = (int *)malloc(n*sizeof(int)); i=0; sum=0;
Trang 45Solution for homework