2010-06-28 58 views
37

Tôi đang cố gắng hiểu cách giải quyết vấn đề tầm thường này trong C, theo cách sạch nhất/an toàn nhất. Dưới đây là ví dụ của tôi:Cách gán đúng giá trị chuỗi mới?

#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    typedef struct 
    { 
     char name[20]; 
     char surname[20]; 
     int unsigned age; 
    } person; 

    //Here i can pass strings as values...how does it works? 
    person p = {"John", "Doe",30}; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 
    // This works as expected... 
    p.age = 25; 
    //...but the same approach doesn't work with a string 
    p.name = "Jane"; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    return 1; 
} 

lỗi của trình biên dịch là:

main.c: In function ‘main’: main.c:18: error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’

Tôi hiểu rằng C (không phải C++) không có kiểu String và thay vào đó sử dụng mảng các ký tự, vì vậy một cách khác để làm điều này là để thay đổi cấu trúc ví dụ để giữ con trỏ của ký tự:

#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    typedef struct 
    { 
     char *name; 
     char *surname; 
     int unsigned age; 
    } person; 

    person p = {"John", "Doe",30}; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    p.age = 25; 

    p.name = "Jane"; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    return 1; 
} 

Điều này làm việc như mong đợi nhưng tôi tự hỏi liệu có cách nào tốt hơn để làm điều này không. Cảm ơn.

+0

Nếu chúng ta khai báo cấu trúc trong 'main()', người đó chỉ có thể truy cập bên trong nó. Hãy thử di chuyển ra khỏi chính để sử dụng nó như là toàn cầu – EsmaeelE

Trả lời

29

Ví dụ đầu tiên không hoạt động vì bạn không thể chỉ định giá trị cho mảng - mảng hoạt động (loại) giống như con trỏ const theo khía cạnh này. Tuy nhiên, những gì bạn có thể làm là sao chép một giá trị mới vào mảng:

strcpy(p.name, "Jane"); 

Mảng char là tốt để sử dụng nếu bạn biết kích thước tối đa của chuỗi trước, ví dụ: trong ví dụ đầu tiên bạn chắc chắn rằng 100% tên sẽ phù hợp với 19 ký tự (không phải 20 vì một ký tự luôn cần thiết để lưu trữ giá trị kết thúc bằng 0).

Ngược lại, con trỏ sẽ tốt hơn nếu bạn không biết kích thước tối đa có thể có của chuỗi và/hoặc bạn muốn tối ưu hóa mức sử dụng bộ nhớ của mình, ví dụ: tránh đặt 512 ký tự cho tên "John". Tuy nhiên, với con trỏ, bạn cần phải tự động phân bổ bộ đệm mà chúng trỏ tới và giải phóng nó khi không cần nữa, để tránh rò rỉ bộ nhớ.

Cập nhật: ví dụ về bộ đệm cấp phát động (sử dụng định nghĩa struct trong ví dụ thứ 2 của bạn):

char* firstName = "Johnnie"; 
char* surname = "B. Goode"; 
person p; 

p.name = malloc(strlen(firstName) + 1); 
p.surname = malloc(strlen(surname) + 1); 

p.age = 25; 
strcpy(p.name, firstName); 
strcpy(p.surname, surname); 

printf("Name: %s; Age: %d\n",p.name,p.age); 

free(p.surname); 
free(p.name); 
7

suy nghĩ những chuỗi như đối tượng trừu tượng, và mảng char như container. Chuỗi có thể là bất kỳ kích thước nào nhưng vùng chứa phải dài ít nhất 1 hơn chiều dài chuỗi (để giữ null terminator).

C có rất ít hỗ trợ cú pháp cho chuỗi. Không có các toán tử chuỗi (chỉ các toán tử char-array và char-pointer). Bạn không thể gán chuỗi.

Nhưng bạn có thể gọi các chức năng để giúp đạt được những gì bạn muốn.

Có thể sử dụng chức năng strncpy() tại đây. Để an toàn tối đa Tôi đề nghị sau đây mô hình này:

strncpy(p.name, "Jane", 19); 
p.name[19] = '\0'; //add null terminator just in case 

Cũng có một cái nhìn tại các chức năng strncat()memcpy().

+1

Để bây giờ câu trả lời tốt nhất nhưng cũng Péter của một là tốt (hiển thị như thế nào để làm điều đó với con trỏ) vì vậy tôi đang chờ đợi nhiều hơn một chút để xem nếu nhiều người có thể thêm nhiều lời khuyên/đề xuất về chủ đề. –

4

Hai cấu trúc khác nhau. Khi bạn khởi tạo cấu trúc đầu tiên, khoảng 40 byte bộ nhớ được cấp phát. Khi bạn khởi tạo cấu trúc thứ hai, khoảng 10 byte bộ nhớ được cấp phát. (Số tiền thực tế phụ thuộc vào kiến ​​trúc)

Bạn có thể sử dụng chuỗi ký tự (hằng số chuỗi) để initalize mảng ký tự. Đây là lý do tại sao

person p = {"John", "Doe",30};

hoạt động trong ví dụ đầu tiên.

Bạn không thể gán (theo nghĩa thông thường) một chuỗi trong C.

Các xâu bạn đã ("John") được nạp vào bộ nhớ khi mã của bạn được thực thi. Khi bạn khởi tạo một mảng với một trong các ký tự này, thì chuỗi được sao chép vào một vị trí bộ nhớ mới. Trong ví dụ thứ hai của bạn, bạn chỉ đơn thuần là sao chép con trỏ đến (vị trí của) chuỗi chữ. Làm cái gì đó như:

char* string = "Hello"; 
*string = 'C' 

có thể gây ra biên dịch hoặc lỗi runtime (Tôi không chắc chắn.) Đó là một ý tưởng tồi bởi vì bạn đang thay đổi chuỗi chữ "Hello" mà, ví dụ trên một microcontroler, có thể được bố trí trong bộ nhớ chỉ đọc.

+0

Bạn đã chính xác, nhiệm vụ bạn đã viết gây ra sự phân đoạn vì bạn đang cố gắng thay đổi giá trị con trỏ, nhưng đề cập đến các ví dụ của tôi giống như char * string = "Hello"; string = "C"; (lưu ý không có gán con trỏ trên câu lệnh cuối cùng) hoạt động như mong đợi. –

+1

Tôi muốn đề cập rằng "thay đổi giá trị con trỏ" không nhất thiết gây ra sự phân đoạn. Lý do mà đoạn mã trong bài viết gốc của tôi gây ra một segfault là bởi vì bạn đang cố gắng sửa đổi bộ nhớ được đặt trong một không gian địa chỉ bị hạn chế. – Gus

Các vấn đề liên quan