การเริ่มต้นอาร์เรย์ถ่าน C


119

ฉันไม่แน่ใจว่าจะมีอะไรอยู่ในอาร์เรย์ถ่านหลังจากเริ่มต้นด้วยวิธีต่อไปนี้

1. char buf[10] = "";
2. char buf[10] = " ";
3.char buf[10] = "a";

สำหรับกรณีที่ 2 ผมคิดว่าbuf[0]ควรจะ' ', buf[1]ควรจะเป็น'\0'และจากbuf[2]ไปbuf[9]จะเป็นเนื้อหาที่สุ่ม สำหรับกรณีที่ 3 ผมคิดว่าbuf[0]ควรจะ'a', buf[1]ควรจะ '\ 0' และจากbuf[2]ไปbuf[9]จะเป็นเนื้อหาที่สุ่ม

ถูกต้องหรือไม่

และสำหรับกรณีที่ 1 จะเป็นbufอย่างไรใน? buf[0] == '\0'และจากbuf[1]ถึงbuf[9]จะเป็นเนื้อหาแบบสุ่ม?


2
คอมไพเลอร์ของฉันไม่ยอมรับรหัส (แก้ไข) ของคุณ: "ประเภทอาร์เรย์ 'char [10]' ไม่สามารถกำหนดได้"
Martin R

@MartinR ตอนนี้มันจะทำงาน ...
lkkeepmoving

1
@lkkeepmoving: char buf[10]; buf = "a";ไม่ได้รวบรวม - โปรดลองก่อนจากนั้นคัดลอก / วางรหัสจริงของคุณลงในคำถาม ซึ่งช่วยประหยัดงานได้มากสำหรับคุณและสำหรับผู้อ่านทุกคำถามของคุณ
Martin R

@MartinR ขออภัยที่. ฉันคิดว่าฉันสามารถกำหนด buf [] หลังได้ แต่ดูเหมือนจะไม่ใช่ ตอนนี้รหัสทำงาน
lkkeepmoving

คำตอบ:


222

นี่ไม่ใช่วิธีเริ่มต้นอาร์เรย์ แต่สำหรับ:

  1. คำประกาศแรก:

    char buf[10] = "";

    เทียบเท่ากับ

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. คำประกาศที่สอง:

    char buf[10] = " ";

    เทียบเท่ากับ

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. คำประกาศที่สาม:

    char buf[10] = "a";

    เทียบเท่ากับ

    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};

ในขณะที่คุณสามารถดูไม่มีเนื้อหาที่สุ่ม: ถ้ามี initializers 0น้อยที่เหลือของอาร์เรย์จะเริ่มต้นด้วย ในกรณีนี้แม้ว่าอาร์เรย์จะถูกประกาศภายในฟังก์ชัน


47
เพื่อประโยชน์ของผู้ถามคำถามคุณควรชี้ให้เห็นว่ามาตรฐาน C ต้องการการเริ่มต้นอาร์เรย์ที่สมบูรณ์บางส่วนเพื่อให้มีศูนย์สำหรับองค์ประกอบที่เหลือ (โดยคอมไพเลอร์) charนี้ไปสำหรับชนิดข้อมูลทั้งหมดไม่เพียง
ข้าวเปลือก

4
@ouah ทำไมไม่มี '\ 0' ต่อท้าย buf []?
lkkeepmoving

14
@lkkeepmoving 0และ'\0มีค่าเท่ากัน.
ouah

1
@lkkeepmoving การกำหนดค่าเริ่มต้นและการกำหนดเป็นสัตว์ร้ายสองตัวที่แตกต่างกันดังนั้น C ช่วยให้คุณจัดเตรียมสตริงเป็นตัวเริ่มต้นสำหรับอาร์เรย์ถ่าน แต่ห้ามการกำหนดอาร์เรย์ (ตามที่ ouah กล่าว)
Lorenzo Donati - Codidact.com

3
@Pacerier char buff[3] = "abcdefghijkl";ไม่ถูกต้อง char p3[5] = "String";ก็ไม่ถูกต้องเช่นกัน ถูกต้องและเป็นเช่นเดียวกับchar p[6] = "String"; char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};
ouah

28

แก้ไข: OP (หรือผู้แก้ไข) เปลี่ยนเครื่องหมายคำพูดเดี่ยวบางคำในคำถามเดิมเป็นเครื่องหมายคำพูดคู่ ณ จุดหนึ่งหลังจากที่ฉันให้คำตอบนี้

โค้ดของคุณจะส่งผลให้คอมไพเลอร์ผิดพลาด ส่วนรหัสแรกของคุณ:

char buf[10] ; buf = ''

ผิดกฎหมายทวีคูณ ครั้งแรกใน C charไม่มีสิ่งดังกล่าวเป็นที่ว่างเปล่า คุณสามารถใช้เครื่องหมายคำพูดคู่เพื่อกำหนดสตริงว่างได้เช่นเดียวกับ:

char* buf = ""; 

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

char buf = '\0';

'0'เครื่องหมายเป็นสิ่งจำเป็นเพื่อกระจ่างจากตัวอักษร

char buf = 0;

ฉันคิดว่าสำเร็จในสิ่งเดียวกัน แต่อดีตนั้นมีความคลุมเครือน้อยกว่าที่จะอ่านฉันคิดว่า

ประการที่สองคุณไม่สามารถเริ่มต้นอาร์เรย์ได้หลังจากที่ได้กำหนดไว้แล้ว

char buf[10];

ประกาศและกำหนดอาร์เรย์ bufขณะนี้ตัวระบุอาร์เรย์เป็นที่อยู่ในหน่วยความจำและคุณไม่สามารถเปลี่ยนbufจุดที่กำหนดผ่านการกำหนดได้ ดังนั้น

buf =     // anything on RHS

ผิดกฎหมาย ชิ้นส่วนรหัสที่สองและสามของคุณผิดกฎหมายด้วยเหตุนี้

ในการเริ่มต้นอาร์เรย์คุณต้องทำในเวลาที่กำหนด:

char buf [10] = ' ';

จะทำให้คุณมีอาร์เรย์ 10 ตัวอักษรกับถ่านแรกเป็นพื้นที่'\040'และเป็นส่วนที่เหลือคือNUL '\0'เมื่ออาร์เรย์มีการประกาศและกำหนดค่าเริ่มต้นที่มีองค์ประกอบอาร์เรย์ (ถ้ามี) 0ที่ผ่านมาคนที่มีค่าเริ่มต้นที่ระบุมีเบาะโดยอัตโนมัติด้วย จะไม่มี "เนื้อหาสุ่ม" ใด ๆ

หากคุณประกาศและกำหนดอาร์เรย์ แต่ไม่ได้กำหนดค่าเริ่มต้นดังต่อไปนี้:

char buf [10];

คุณจะมีเนื้อหาแบบสุ่มในทุกองค์ประกอบ


"ในการเริ่มต้นอาร์เรย์คุณต้องทำในช่วงเวลาที่กำหนด ... " สิ่งนี้และบรรทัดต่อไปนี้จะดีกว่าคำตอบที่ยอมรับ
Laurie Stearn

26
  1. สิ่งเหล่านี้เทียบเท่า

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2. สิ่งเหล่านี้เทียบเท่า

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
  3. สิ่งเหล่านี้เทียบเท่า

    char buf[10] = "a";
    char buf[10] = {'a'};
    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};

8

ส่วนที่เกี่ยวข้องของร่างมาตรฐาน C11 n1570 6.7.9 การเริ่มต้นกล่าวว่า:

14 อาร์เรย์ของประเภทอักขระอาจเริ่มต้นด้วยสตริงอักขระลิเทอรัลหรือสตริงลิเทอรัล UTF-8 ซึ่งอยู่ในวงเล็บปีกกา ไบต์ที่ต่อเนื่องกันของสตริงลิเทอรัล (รวมถึงการสิ้นสุดอักขระว่างหากมีห้องหรืออาร์เรย์มีขนาดที่ไม่รู้จัก) เริ่มต้นองค์ประกอบของอาร์เรย์

และ

21 หากมีตัวเริ่มต้นในรายการที่ปิดด้วยวงเล็บปีกกาน้อยกว่าที่มีองค์ประกอบหรือสมาชิกของการรวมหรือมีอักขระน้อยกว่าในสตริงลิเทอรัลที่ใช้ในการเริ่มต้นอาร์เรย์ที่มีขนาดที่รู้จักมากกว่าที่มีองค์ประกอบในอาร์เรย์ส่วนที่เหลือของการรวม จะต้องเริ่มต้นโดยปริยายเช่นเดียวกับวัตถุที่มีระยะเวลาการจัดเก็บแบบคงที่

ดังนั้น '\ 0' จะถูกต่อท้ายหากมีพื้นที่เพียงพอและอักขระที่เหลือจะเริ่มต้นด้วยค่าที่static char c;จะเริ่มต้นภายในฟังก์ชัน

สุดท้าย

10 หากอ็อบเจ็กต์ที่มีระยะเวลาการจัดเก็บอัตโนมัติไม่ได้ถูกเตรียมใช้งานอย่างชัดเจนค่าของมันจะไม่แน่นอน หากอ็อบเจ็กต์ที่มีระยะเวลาการจัดเก็บแบบคงที่หรือเธรดไม่ได้รับการเตรียมใช้งานอย่างชัดเจน:

[-]

  • ถ้ามีประเภทเลขคณิตจะเริ่มต้นเป็นศูนย์ (บวกหรือไม่ได้ลงนาม)

[-]

ดังนั้นcharการเป็นประเภทเลขคณิตส่วนที่เหลือของอาร์เรย์จึงรับประกันได้ว่าจะเริ่มต้นด้วยศูนย์


3

ที่น่าสนใจก็คือเป็นไปได้ที่จะเริ่มต้นอาร์เรย์ด้วยวิธีใดก็ได้ในโปรแกรมได้ตลอดเวลาหากพวกเขาเป็นสมาชิกของ a structหรือunion.

ตัวอย่างโปรแกรม:

#include <stdio.h>

struct ccont
{
  char array[32];
};

struct icont
{
  int array[32];
};

int main()
{
  int  cnt;
  char carray[32] = { 'A', 66, 6*11+1 };    // 'A', 'B', 'C', '\0', '\0', ...
  int  iarray[32] = { 67, 42, 25 };

  struct ccont cc = { 0 };
  struct icont ic = { 0 };

  /*  these don't work
  carray = { [0]=1 };           // expected expression before '{' token
  carray = { [0 ... 31]=1 };    // (likewise)
  carray = (char[32]){ [0]=3 }; // incompatible types when assigning to type 'char[32]' from type 'char *'
  iarray = (int[32]){ 1 };      // (likewise, but s/char/int/g)
  */

  // but these perfectly work...
  cc = (struct ccont){ .array='a' };        // 'a', '\0', '\0', '\0', ...
  // the following is a gcc extension, 
  cc = (struct ccont){ .array={ [0 ... 2]='a' } };  // 'a', 'a', 'a', '\0', '\0', ...
  ic = (struct icont){ .array={ 42,67 } };      // 42, 67, 0, 0, 0, ...
  // index ranges can overlap, the latter override the former
  // (no compiler warning with -Wall -Wextra)
  ic = (struct icont){ .array={ [0 ... 1]=42, [1 ... 2]=67 } }; // 42, 67, 67, 0, 0, ...

  for (cnt=0; cnt<5; cnt++)
    printf("%2d %c %2d %c\n",iarray[cnt], carray[cnt],ic.array[cnt],cc.array[cnt]);

  return 0;
}

1

ฉันไม่แน่ใจ แต่ฉันมักจะเริ่มต้นอาร์เรย์เป็น "" ในกรณีนั้นฉันไม่จำเป็นต้องกังวลเกี่ยวกับจุดสิ้นสุดว่างของสตริง

main() {
    void something(char[]);
    char s[100] = "";

    something(s);
    printf("%s", s);
}

void something(char s[]) {
    // ... do something, pass the output to s
    // no need to add s[i] = '\0'; because all unused slot is already set to '\0'
}

คุณไม่ควรใช้ประโยชน์จากกฎint โดยปริยายจริงๆ คุณควรระบุประเภทสำหรับmain()(และคุณควรใช้voidด้วยเช่นint main(void) { ... }C99 ได้กำจัดกฎนี้ดังนั้นรหัสนี้จะไม่รวบรวมสำหรับ C99 และใหม่กว่าสิ่งอื่นที่ควรทราบก็คือเริ่มต้นด้วย C99 หากคุณละreturnไว้ หลักมีการreturn 0;วาง / โดยนัยโดยอัตโนมัติก่อน}ที่ส่วนท้ายของ main คุณกำลังใช้กฎ int โดยนัยซึ่งใช้ได้เฉพาะก่อน C99 แต่คุณกำลังใช้ประโยชน์จากนัยreturnที่ใช้ได้กับ C99 และใหม่กว่าเท่านั้นทั้งสองขัดแย้งกันอย่างเห็นได้ชัด .
RastaJedi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.