01/10/2018, 08:33

Thắc mắc về mảng kí tự, kí tự, chuỗi

Cho em hỏi:
Char* var có khác char var[] nhau không ạ?
Sự khác nhau giữa %c và %s ?
Khi nào thì nên dùng %c khi nào thì nên dùng %s ?
Cám ơn:slight_smile:.

rogp10 viết 10:37 ngày 01/10/2018

[quote=“kiki, post:1, topic:42442”]
Sự khác nhau giữa %c và %s ?Khi nào thì nên dùng %c khi nào thì nên dùng %s ?
[/quote]Không dùng scanf để nhập chuỗi nhé bạn.

Người bí ẩn viết 10:35 ngày 01/10/2018

char *var nghĩa là khai báo con trỏ var thuộc kiểu char.
char var[] nghĩa là khai báo mảng var có kiểu char, nếu không gán ngay lúc khai báo thì phải để thêm chỉ số (số lượng phần tử) trong cặp [] nữa. VD: char var[30];.

Còn sự khác biệt thì có một vài điểm cần lưu ý như sau:

  • Khi để `char *var = "string";` thì đồng nghĩa với việc bạn sẽ cho con trỏ `var` này trỏ đến một vùng dữ liệu **hằng** có tên `string` trong vùng nhớ Constant (vùng nhớ chỉ read-only, mọi thao tác chỉnh sửa, thay đổi, ... sẽ bị vi phạm, gọi là string literal). VD: ``` int main() { char *str = "Hello world"; str[0] = 'z'; // wrong return 0; } ```
  • Còn khi để `char var[] = "string";` thì nó khác. Lúc này, `var` không trỏ đến vùng dữ liệu hằng có tên `string` trong vùng nhớ Constant nữa mà nó sẽ **tạo một bản sao** của `string` và đem nó tới vùng nhớ Stack (vùng nhớ hiện tại của `char var[]`, gọi là character array. VD: ``` int main() { char str[] = "Hello world"; str[0] = 'z'; // ok return 0; } ```
  • Khi để `char *var = "string";` thì khi lấy sizeof của nó: `sizeof(var)` sẽ chỉ return về **kích thước** của con trỏ `var` (4 bytes trên OS 32bit và 8 bytes trên OS 64bit) chứ không phải lượng vùng nhớ mà nó chiếm hữu. VD: ``` int main() { char *str = "Hello world"; printf("%d", sizeof(str)); // This line will print the size of pointer: 4 (on 32bit OS) or 8 (on 64bit OS) return 0; } ```
  • Còn khi để `char var[] = "string";` thì khi lấy sizeof của nó: `sizeof(var)` sẽ return về số ô nhớ mà mảng `var` sử dụng, tức là số lượng phần tử (bao gồm cả ký tự `\0`). Nên kết quả sẽ khác với bên trên. VD: ``` int main() { char str[] = "Hello world"; printf("%d", sizeof(str)); // This line will print the number of elemets in str array return 0; } ```
  • Khi để `char *var ...` thì `&var` hoàn toàn khác `var`. Vì `var` là 1 pointer nên để `var` có nghĩa là lấy ra địa chỉ mà `var` đang lưu trữ, còn để `&var` có nghĩa là lấy ra địa chỉ thật sự của `var`.
  • Khi để `char var[] ...` thì để `&var` cũng giống như khi để `var`. Vì khi khai báo mảng, compiler sẽ cấp cho mảng đó `n` phần tử những không cấp phát vùng nhớ để lữu trữ biến mảng `var` nên mặc định `var` sẽ được gán cho địa chỉ của ô nhớ đầu tiên, vì thế: `&var` = `var` = `&var[0]` = `0[var]`.
  • .
  • Khi để `char *var ...` thì chúng ta vẫn có thể trỏ nó đến một vùng nhớ khác vì nó là con trỏ. VD: ``` int main() { char *str = "Hello world"; str = "Lorem ipsum dolor sit amet"; // ok, no problem. printf("%s", str); } ```
  • Còn khi để `char str[] ...` thì lúc này, như đã trình bày ở trên, biến mảng `str` không được compiler cấp phát vùng nhớ lưu trữ nên sẽ không thể trỏ đến chỗ khác. VD: ``` int main() { char str[] = "Hello world"; str = "Lorem ipsum dolor sit amet"; // wrong printf("%s", str); return 0; } ```

  • %c là đặc tả dùng để nhập/xuất một ký tự có kiểu char.
    VD:

    int main()
    {
         char c;
         scanf("%c", &c);
         printf("%c", c);
         return 0;
    }
    

    Còn %s là đặc tả dùng để nhập/xuất một chuỗi (mảng các ký tự).
    VD:

    int main()
    {
         char str[30];
         scanf("%s", str);
         printf("%s", str);
         return 0;
    }
    

    Nhưng lưu ý là khi nhập chuỗi nên dùng hàm fgets(): fgets(str, sizeof(str), stdin);. Còn nếu dùng hàm scanf() thì khi truyền đặc tả nên giới hạn số lượng ký tự nhận vào stdin luôn: scanf("%30s", &str); để tránh chương trình bị crash khi người dùng nhập quá nhiều vượt số lượng phần tử mà array có thể chứa.
    Điều này cũng đồng nghĩa với việc tuyệt đối không nên dùng hàm gets() để nhập chuỗi.

    Còn về những ưu điểm và khuyết điểm của fgets() so với scanf() thì nó không liên quan ở topic này nên mình sẽ không đề cập đến, bạn có thể tự tìm hiểu thêm trên mạng.

    Trần Phúc viết 10:48 ngày 01/10/2018

    Cảm ơn rất rất nhiều ạ Cơ mà do em mới học C nên chưa hiểu những điểm anh viết Chắc phải học thêm, tìm hiểu thêm nhiều thứ nữa nữa rồi quay lại đây mới hiểu toàn bộ
    Cảm ơn nhiều nhiều ạ

    Người bí ẩn viết 10:43 ngày 01/10/2018

    Bạn đã học con trỏ chưa, nếu học qua con trỏ rồi thì vấn đề này sẽ dễ hiểu hơn thôi, nên không nhất thiết phải hiểu ngay tức thì, vì nó còn liên quan đến con trỏ và tổ chức bộ nhớ trong máy tính nữa.

    Quang Minh viết 10:45 ngày 01/10/2018

    Cá nhân mình thấy C/C++ xử lý chuỗi không hay.
    Ở trung học có Pascal làm việc với chuỗi hay hơn, rồi giờ biết đến Python xử lý chuỗi còn hay nữa.

    rogp10 viết 10:39 ngày 01/10/2018

    Đồng ý về nguyên tắc nhưng mà trong C thao tác trực tiếp được.

    Trần Phúc viết 10:44 ngày 01/10/2018

    Chưa anh ạ mình đọc cũng không hiểu mấy luôn nên cố học mấy phần sau để hiểu rõ rồi quay lại đây

    Nguyễn Quốc Hoàng viết 10:47 ngày 01/10/2018

    char *var - con trỏ chỉ đến một vùng nhớ kiểu char, muốn tạo một string thì trước hết phải cấp phát động cho nó (vùng nhớ ở heap)
    char var[(độ dài)] - mảng của một ký tự đã cấp phát sẵn vùng nhớ (ở stack segment)
    %c khi bạn cần lấy một ký tự ví dụ:
    char a;
    scanf("%c",&a);
    printf("%c",a);

    %s khi bạn cần in một chuôi, ví dụ
    char *s;
    s = (char *) malloc(100);
    scanf("%s",f);
    printf("%s",f);

    Bài liên quan
    0