'\ 0' และ printf () ใน C


21

ในหลักสูตรเบื้องต้นของ C ฉันได้เรียนรู้ว่าในขณะที่การจัดเก็บสตริงจะถูกเก็บไว้ด้วยตัวละคร null \0เมื่อสิ้นสุดมัน แต่ถ้าฉันต้องการที่จะพิมพ์สตริงพูดprintf("hello")แม้ว่าฉันจะพบว่ามันไม่ได้จบลงด้วย\0คำสั่งต่อไปนี้

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

Output: 5

แต่นี่ดูเหมือนจะไม่สอดคล้องกันเท่าที่ฉันรู้ว่าตัวแปรเช่นสายอักขระถูกเก็บไว้ในหน่วยความจำหลักและฉันเดาว่าในขณะที่พิมพ์บางอย่างมันอาจถูกเก็บไว้ในหน่วยความจำหลักแล้วทำไมจึงแตกต่างกัน


1
นอกจากความจริงที่ว่าโค้ดของคุณพลาดไปแล้วอย่างน้อย);คุณตั้งใจจะแสดงอะไรกับโค้ดนั้น? คุณจะพิสูจน์ได้อย่างไรว่ามันไม่ได้จบลงด้วย\0?
glglgl

และหน่วยความจำที่เก็บอยู่นั้นเกี่ยวข้องกับมันอย่างไร?
Tsakiroglou Fotis

ใน C สตริงตัวอักษรทั้งหมดเป็นอาร์เรย์ของตัวอักษรจริงๆซึ่งรวมถึง null-terminator
โปรแกรมเมอร์บางคนเพื่อน

@glglgl ฉันคิดว่า printf () คืนจำนวนอักขระที่ควรจะพิมพ์บนหน้าจอ
Ajay Mishra

4
@AjayMishra ใช่แล้วมันควรจะพิมพ์ 5 ตัวอักษร การยกเลิก 0 ไบต์จะไม่ถูกพิมพ์บนหน้าจอ
glglgl

คำตอบ:


13

ไบต์ว่างทำเครื่องหมายจุดสิ้นสุดของสตริง printfมันจะไม่นับความยาวของสตริงและไม่ได้พิมพ์เมื่อสตริงเป็นพิมพ์ด้วย โดยพื้นฐานแล้ว null bytes จะบอกฟังก์ชั่นที่ทำการจัดการสตริงเมื่อจะหยุด

ที่คุณจะเห็นความแตกต่างคือถ้าคุณสร้างcharอาร์เรย์เริ่มต้นด้วยสตริง การใช้sizeofโอเปอเรเตอร์จะแสดงขนาดของอาเรย์รวมถึงไบต์ว่าง ตัวอย่างเช่น:

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

printf()ผมคิดว่าเรื่องนี้จะแตกต่างกันด้วย TBH ฉันไม่รู้ว่าprintf()ทำงานอย่างไร
Ajay Mishra

8

printfส่งคืนจำนวนอักขระที่พิมพ์ '\0'ไม่ได้พิมพ์ - มันแค่ส่งสัญญาณว่าไม่มีตัวอักษรในสายนี้ มันจะไม่ถูกนับรวมกับความยาวของสตริงเช่นกัน

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

สมมติฐานของคุณผิด \0สายของคุณแน่นอนลงท้ายด้วย

มันมี 5 ตัวอักษรh, e, l, l, oและ 0 ตัวอักษร

สิ่งที่ " print()เอาท์พุท" การโทรออกเป็นจำนวนตัวอักษรที่ถูกพิมพ์และนั่นคือ 5


6

ใน C สตริงตัวอักษรทั้งหมดเป็นอาร์เรย์ของตัวอักษรจริงๆซึ่งรวมถึง null-terminator

อย่างไรก็ตามตัวสิ้นสุด null จะไม่ถูกนับในความยาวของสตริง (ตามตัวอักษรหรือไม่) และจะไม่ถูกพิมพ์ การพิมพ์หยุดลงเมื่อพบว่าตัวสิ้นสุด null


มีอยู่เพื่อตรวจสอบนี้โดยไม่ต้องเก็บสตริงในอาร์เรย์?
Ajay Mishra

1
@AjayMishra ดีสตริงที่มีอยู่แล้วคือในอาร์เรย์ (ดังกล่าว) ... แต่ถ้ามีก็ไม่ได้เทอร์มิ null แล้วprintfจะออกไปจากขอบเขตของสตริงและพิมพ์ "สุ่ม" หรือ "ขยะ" ตัวอักษรและผลตอบแทน ตัวเลขที่แตกต่างจากความยาวของสตริง หากคุณทราบความยาวของสตริงแล้วคุณสามารถตรวจสอบได้ว่าอักขระที่ดัชนีนั้นคืออะไร'\0'ซึ่งจะใช้งานได้ แต่เป็นพฤติกรรมที่ไม่ได้กำหนดในทางเทคนิคหากขนาดของอาร์เรย์ไม่รวมถึงตัวยุติ (เช่นในchar arr[5] = "hello";ซึ่งจะไม่เพิ่ม สิ้นสุดลงในอาร์เรย์)
โปรแกรมเมอร์บางคนเพื่อน

@AjayMishra ใช่ E. กรัมคุณสามารถทำchar * p = "Hello"; int i = 0; while (p[i] != '\0') { printf("%d: %c", i, p[i]); i++; }และดูว่ามันทำงานอย่างไร: มันแสดงบรรทัดที่มีดัชนีและเนื้อหาที่บรรทัดนั้น หลังจากดัชนี 4 จะค้นหาอักขระ 0 และแบ่งลูป while ที่นั่นคุณเห็นว่ามีอักขระ 0 ตัว
glglgl

6

คำตอบทั้งหมดดีมาก แต่ฉันต้องการเพิ่มอีกตัวอย่างหนึ่งเพื่อทำสิ่งเหล่านี้ให้สมบูรณ์

#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;
}

สำหรับผู้ที่ไม่ต้องการลองออนไลน์ gdb ผลลัพธ์คือ:

สวัสดีชาวโลก

นรก

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

สิ่งนี้มีประโยชน์หรือไม่ที่จะเข้าใจว่า escape terminator ทำอะไร ไม่ใช่ขอบเขตสำหรับอาร์เรย์อักขระหรือสตริง มันเป็นตัวละครที่จะพูดกับผู้ชายที่แยกวิเคราะห์ -STOP (พิมพ์) แยกวิเคราะห์จนถึงที่นี่

PS: และถ้าคุณแยกวิเคราะห์และพิมพ์เป็นอาร์เรย์ถ่าน

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

คุณได้รับ:

โลกนรก

โดยที่ whitespace หลังจาก double l เป็นตัวทำลายค่า null อย่างไรก็ตามการแยกอาร์เรย์ char จะเป็นเพียงค่าถ่านของทุกไบต์ หากคุณแยกวิเคราะห์และพิมพ์ค่า int ของแต่ละไบต์ ("% d%, char_array [i]) คุณจะเห็นว่า (คุณได้รับการแทนรหัส ASCII) ช่องว่างมีค่าเป็น 0


4

ในCฟังก์ชั่นprintf()จะคืนค่าจำนวนตัวอักษรที่พิมพ์ออกมา\0เป็นเทอร์nullมิเนเตอร์ที่ใช้เพื่อระบุจุดสิ้นสุดของสตริงในภาษา c และไม่มีstringชนิดบิวด์อินเป็นของc++อย่างไรก็ตามขนาดอาร์เรย์ของคุณจะต้องมากกว่าจำนวนที่charคุณต้องการ ในการจัดเก็บ

นี่คือการอ้างอิง: cpp ref printf ()


3

แต่ถ้าฉันต้องการพิมพ์สตริงให้พูด printf ("hello") แม้ว่าฉันจะพบว่ามันไม่ได้จบด้วย \ 0 ตามข้อความต่อไปนี้

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

Output: 5

คุณผิด. คำสั่งนี้ไม่ได้ยืนยันว่าตัวอักษรสตริงไม่ได้จบด้วยตัวอักษรยุติศูนย์"hello" '\0'คำสั่งนี้ยืนยันว่าฟังก์ชั่นการprintfส่งออกองค์ประกอบของสตริงจนกว่าจะพบอักขระศูนย์สิ้นสุด

เมื่อคุณใช้สตริงตัวอักษรในคำสั่งด้านบนคอมไพเลอร์จะสร้างอาร์เรย์อักขระที่มีระยะเวลาคงที่ที่มีองค์ประกอบของสตริงตัวอักษร

ดังนั้นในความเป็นจริงการแสดงออกนี้

printf("hello")

ถูกประมวลผลโดยคอมไพเลอร์บางอย่างดังต่อไปนี้

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

การกระทำของฟังก์ชั่น printf ในนี้คุณสามารถจินตนาการวิธีต่อไปนี้

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

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

    return result;
}

ในการรับจำนวนอักขระที่เก็บอยู่ในสตริง "hello" ตามตัวอักษรคุณสามารถเรียกใช้โปรแกรมต่อไปนี้

#include <stdio.h>

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

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

    return 0;
}

ผลลัพธ์ของโปรแกรมคือ

The size of the literal "hello" is 6

0

คุณต้องล้างแนวคิดของคุณก่อน .. มันจะถูกล้างออกเมื่อคุณจัดการกับอาเรย์คำสั่งพิมพ์ที่คุณใช้อยู่นั้นเป็นเพียงการนับจำนวนตัวอักษรที่อยู่ภายในขอบเขต จำเป็นในสตริงอาเรย์ที่มันจะลงท้ายด้วย \ 0


0

สตริงเป็นเวกเตอร์ของตัวละคร มีลำดับของอักขระที่เป็นสตริงตามด้วยสตริงอักขระสิ้นสุดพิเศษ: '\ 0'

ตัวอย่าง: char str [10] = {'H', 'e', ​​'l', 'l', 'o', '\ 0'};

ตัวอย่าง: เวกเตอร์อักขระต่อไปนี้ไม่ใช่หนึ่งสตริงเนื่องจากไม่ได้ลงท้ายด้วย '\ 0'

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


ฉันคิดว่าไม่มีเวกเตอร์ใน C
Ajay Mishra
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.