'\ 0' và printf () bằng C


21

Trong một khóa học giới thiệu về C, tôi đã học được rằng trong khi lưu trữ các chuỗi được lưu trữ với ký tự null \0ở cuối của nó. Nhưng nếu tôi muốn in một chuỗi, hãy nói printf("hello")mặc dù tôi đã thấy rằng nó không kết thúc \0bằng câu lệnh sau

printf("%d", printf("hello"));

Output: 5

Nhưng điều này dường như không nhất quán, cho đến nay tôi biết rằng biến như chuỗi được lưu trữ trong bộ nhớ chính và tôi đoán trong khi in một cái gì đó nó cũng có thể được lưu trữ trong bộ nhớ chính, vậy thì tại sao lại có sự khác biệt?


1
Bên cạnh thực tế là mã của bạn bỏ lỡ ít nhất );, bạn dự định thể hiện điều gì với mã đó? Làm thế nào để bạn chứng minh rằng nó không kết thúc với một \0?
glglgl

Và bộ nhớ được lưu trữ trong đó, phải làm gì với nó?
Tsakiroglou Fotis

Trong C, tất cả các chuỗi ký tự thực sự là các mảng ký tự, bao gồm cả bộ kết thúc null.
Một số lập trình viên anh chàng

@glglgl Tôi nghĩ printf () trả về số lượng ký tự được cho là in trên màn hình.
Ajay Mishra

4
@AjayMishra Vâng, và nó thực sự đã in 5 ký tự. 0 byte kết thúc không được in trên màn hình.
glglgl

Câu trả lời:


13

Byte null đánh dấu sự kết thúc của một chuỗi. Nó không được tính theo chiều dài của chuỗi và không được in khi một chuỗi được in printf. Về cơ bản, byte null cho biết các hàm thực hiện thao tác chuỗi khi dừng.

Nơi bạn sẽ thấy sự khác biệt là nếu bạn tạo một charmảng được khởi tạo bằng một chuỗi. Sử dụng sizeoftoán tử sẽ phản ánh kích thước của mảng bao gồm byte null. Ví dụ:

char str[] = "hello";
printf("len=%zu\n", strlen(str));     // prints 5
printf("size=%zu\n", sizeof(str));    // prints 6

Tôi nghĩ rằng câu chuyện sẽ khác với printf(). TBH Tôi không biết bao printf()công trình.
Ajay Mishra

8

printftrả về số lượng ký tự được in. '\0'không được in - nó chỉ báo hiệu rằng không còn ký tự trong chuỗi này. Nó cũng không được tính vào chiều dài chuỗi

int main()
{
    char string[] = "hello";

    printf("szieof(string) = %zu, strlen(string) = %zu\n", sizeof(string), strlen(string));
}

https://godbolt.org/z/wYn33e

sizeof(string) = 6, strlen(string) = 5

6

Giả định của bạn là sai. Chuỗi của bạn thực sự kết thúc bằng một \0.

Nó chứa 5 ký tự h, e, l, l, ovà nhân vật 0.

print()Đầu ra cuộc gọi "bên trong" là số lượng ký tự được in và 5 ký tự đó.


6

Trong C, tất cả các chuỗi ký tự thực sự là các mảng ký tự, bao gồm cả bộ kết thúc null.

Tuy nhiên, dấu kết thúc null không được tính theo độ dài của chuỗi (bằng chữ hoặc không) và nó không được in. In dừng lại khi kết thúc null được tìm thấy.


Có cách nào để xác minh điều này mà không lưu trữ chuỗi trong một mảng không?
Ajay Mishra

1
@AjayMishra Vâng, chuỗi đã trong một mảng (như đã đề cập) ... Nhưng nếu không có dấu kết thúc null thì printfsẽ thoát khỏi giới hạn của chuỗi và in các ký tự "ngẫu nhiên" hoặc "rác" và trả về một số khác với độ dài của chuỗi. Nếu bạn đã biết độ dài của chuỗi, bạn cũng có thể kiểm tra xem ký tự trong chỉ mục '\0'đó có hoạt động hay không nhưng là hành vi không xác định về mặt kỹ thuật nếu kích thước của mảng không bao gồm dấu kết thúc (như trong char arr[5] = "hello";, sẽ không thêm terminator đến mảng).
Một số lập trình viên anh chàng

@AjayMishra Có E. g., Bạn có thể làm char * p = "Hello"; int i = 0; while (p[i] != '\0') { printf("%d: %c", i, p[i]); i++; }và xem cách nó chạy: nó hiển thị các dòng có chỉ mục và nội dung tại dòng đó. Sau chỉ số 4, nó tìm thấy ký tự 0 và phá vỡ vòng lặp while. Ở đó bạn thấy rằng có một ký tự 0.
glglgl

6

Tất cả các câu trả lời thực sự tốt nhưng tôi muốn thêm một ví dụ khác để hoàn thành tất cả những câu trả lời này

#include <stdio.h>

int main()
{
    char a_char_array[12] = "Hello world";

    printf("%s", a_char_array);
    printf("\n");

    a_char_array[4] = 0; //0 is ASCII for null terminator

    printf("%s", a_char_array);
    printf("\n");

    return 0;
}

Đối với những người không muốn thử điều này trên gdb trực tuyến, đầu ra là:

Chào thế giới

Địa ngục

https://linux.die.net/man/3/printf

Điều này có hữu ích để hiểu những gì terminator thoát không? Nó không phải là một ranh giới cho một mảng char hoặc một chuỗi. Đó là nhân vật sẽ nói với anh chàng phân tích cú pháp -STOP, (in) cho đến đây.

PS: Và nếu bạn phân tích và in nó dưới dạng một mảng char

for(i=0; i<12; i++)
{
    printf("%c", a_char_array[i]);
}
printf("\n");

bạn lấy:

Thế giới địa ngục

trong đó, khoảng trắng sau double l, là bộ kết thúc null, tuy nhiên, phân tích cú pháp một mảng char, sẽ chỉ là giá trị char của mỗi byte. Nếu bạn thực hiện một phân tích cú pháp khác và in giá trị int của từng byte ("% d%, char_array [i]), bạn sẽ thấy rằng (bạn nhận được biểu diễn mã ASCII) khoảng trắng có giá trị 0.


4

Trong C chức năng printf()trả về số nhân vật in, \0là một nullterminator được dùng để báo hiệu kết thúc chuỗi trong ngôn ngữ c và không có xây dựng vào stringloại tính c++, tuy nhiên nhu cầu kích thước mảng của bạn trở thành một lớn hơn ít nhất hơn sốchar bạn muốn để lưu trữ.

Đây là tài liệu tham khảo: cpp ref printf ()


3

Nhưng nếu tôi muốn in một chuỗi, hãy nói printf ("xin chào") mặc dù tôi đã thấy rằng nó không kết thúc bằng \ 0 bằng cách làm theo tuyên bố sau

printf("%d", printf("hello"));

Output: 5

Bạn sai rồi. Tuyên bố này không xác nhận rằng chuỗi ký tự "hello"không kết thúc bằng ký tự zero kết thúc'\0' . Tuyên bố này đã xác nhận rằng hàm printfxuất các phần tử của chuỗi cho đến khi gặp ký tự zero kết thúc.

Khi bạn đang sử dụng một chuỗi ký tự như trong câu lệnh trên thì trình biên dịch sẽ tạo ra một mảng ký tự với thời lượng lưu trữ tĩnh có chứa các phần tử của chuỗi ký tự.

Vì vậy, trên thực tế biểu hiện này

printf("hello")

được xử lý bởi trình biên dịch một cái gì đó như sau

static char string_literal_hello[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
printf( string_literal_hello );

Hành động của hàm printf trong này bạn có thể tưởng tượng theo cách sau

int printf( const char *string_literal )
{
    int result = 0;

    for ( ; *string_literal != '\0'; ++string_literal )
    {    
        putchar( *string_literal );
        ++result;
    }

    return result;
}

Để có được số lượng ký tự được lưu trữ trong chuỗi "xin chào" bằng chữ, bạn có thể chạy chương trình sau

#include <stdio.h>

int main(void) 
{
    char literal[] = "hello";

    printf( "The size of the literal \"%s\" is %zu\n", literal, sizeof( literal ) );

    return 0;
}

Đầu ra của chương trình là

The size of the literal "hello" is 6

0

Bạn phải xóa khái niệm của bạn trước .. Vì nó sẽ bị xóa khi bạn xử lý mảng, Lệnh in mà bạn đang sử dụng chỉ là đếm các ký tự được đặt trong phép liệt kê. Nó cần thiết trong chuỗi mảng mà nó sẽ kết thúc bằng \ 0


0

Một chuỗi là một vectơ của các ký tự. Chứa chuỗi ký tự tạo thành chuỗi, theo sau là chuỗi ký tự kết thúc đặc biệt: '\ 0'

Ví dụ: char str [10] = {'H', 'e', ​​'l', 'l', 'o', '\ 0'};

Ví dụ: vectơ ký tự sau không phải là một chuỗi vì nó không kết thúc bằng '\ 0'

char str [2] = {'h', 'e'};


Không có vectơ trong C, tôi đoán.
Ajay Mishra
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.