2010-09-07 54 views
5

tôi đang cố gắng để tìm hiểu các loại file sử dụng mã c, đây là mãmiễn phí con trỏ char trong c

char *get_file_type(char *path, char *filename) 
{ 
    FILE *fp; 
    char command[100]; 
    char file_details[100]; 
    char *filetype; 

    sprintf(command, "file -i %s%s", path, filename); 
    fp = popen(command, "r"); 
    if (fp == NULL) { 
     printf("Failed to run command\n"); 
     exit(1); 
    } 
    while (fgets(file_details, sizeof(file_details)-1, fp) != NULL) { 
     filetype = (strtok(strstr(file_details, " "), ";")); 
    } 

    pclose(fp); 
    return filetype; 
} 

đây thay vì tuyên bố lệnh [], tôi có thể sử dụng * lệnh? Tôi đã cố gắng sử dụng nó, nhưng nó đã ném một ngoại lệ. chúng tôi không cần phải giải phóng các biến được khai báo như lệnh []? nếu có thì sao?

Trả lời

5

Bạn có thể sử dụng char *command;, nhưng sau đó, bạn phải phân bổ một số bộ nhớ cho command để chỉ với một cuộc gọi đến malloc() và khi bạn đang thực hiện thứ i nhớ rằng, nó phải được trả tự do một lần nữa với một cuộc gọi đến free(). Như bạn có thể thấy, đó là công việc nhiều hơn so với sử dụng một mảng có kích thước cố định (như bạn làm bây giờ), nhưng nó có thể được thực hiện an toàn hơn rất nhiều, bởi vì bạn có thể tạo ra một bộ đệm chính xác bên phải kích thước, thay vì hy vọng rằng tổng chiều dài của lệnh sẽ không vượt quá 100 ký tự.

Bên cạnh đó, mã của bạn có vấn đề: Con trỏ filetype hàm trả về điểm đến một vị trí trong mảng file_details, nhưng mảng đó sẽ được dọn dẹp bởi trình biên dịch khi thực hiện câu lệnh return. được trả về bởi hàm này đề cập đến một số bộ nhớ được đánh dấu là "miễn phí được sử dụng cho các mục đích khác".

Nếu kết quả là get_file_type chỉ có giá trị cho một tệp, bạn có thể khai báo mảng file_details thành static, để nó được bảo toàn qua các cuộc gọi đến hàm.

+0

Tôi có thể sử dụng strdup thay thế? –

+0

Bạn có thể, nhưng sau đó bạn phải nhớ gọi 'miễn phí' trong (các) chức năng gọi để tránh rò rỉ bộ nhớ. –

1

Tại sao bạn thay đổi? Đối với các vùng đệm tạm thời, mọi người thường khai báo các mảng với [] để chúng không phải lo lắng về việc xử lý rác thải.

+0

nhưng bạn có thể giải thích cho tôi cách thực hiện không? –

+0

Đối với một điều, nó có thể sẽ có ý nghĩa để tự động cấp phát một bộ đệm dựa trên độ dài của 'path' và' filename' hơn là âm thầm cho phép tràn bộ đệm. (C99 biến chiều dài mảng sẽ giải quyết điều này, mặc dù. Sử dụng 'snprintf' thay vì' sprintf' sẽ được khuyến khích quá.) – jamesdlin

+4

Điều này nên là một bình luận ... – zeboidlund

11

Khi bạn khai báo một mảng:

char command[100]; 

trình biên dịch phân bổ bộ nhớ cho nó (100 ký tự trong trường hợp này) và command điểm bắt đầu của ký ức đó. Bạn có thể truy cập vào bộ nhớ bạn đã phân bổ:

command[0] = 'a'; // OK 
command[99] = 'A'; // OK 
command[100] = 'Z'; // Error: out of bounds 

nhưng bạn không thể thay đổi giá trị của command:

command = NULL;  // Compile-time error 

Ký ức sẽ được tự động giải phóng khi command đi ra khỏi phạm vi.


Khi bạn khai báo một con trỏ:

char *commandptr; 

bạn chỉ tạo một biến duy nhất cho trỏ đến char s, nhưng nó không trỏ đến bất cứ điều gì được nêu ra.Cố gắng sử dụng nó mà không initialising nó là một lỗi:

commandptr[0] = 'A'; // Undefined behaviour; probably a segfault 

Bạn cần phải phân bổ bộ nhớ cho mình sử dụng malloc:

commandptr = malloc(100); 
if (commandptr) { 
    // Always check that the return value of malloc() is not NULL 
    commandptr[0] = 'A'; // Now you can use the allocated memory 
} 

và miễn phí khi bạn đã hoàn tất với nó:

free(commandptr); 
+0

Trên thực tế, ngăn xếp mảng không được giải phóng, bởi vì nó không cần. Để được hoàn toàn trung thực, malloc và miễn phí là syscalls (tốt, wrappers cho họ), trong khi mảng stack không. – KAction