मैं सी में अपनी सरणी का आकार कैसे निर्धारित करूं?


1028

मैं सी में अपनी सरणी का आकार कैसे निर्धारित करूं?

अर्थात्, सरणी को धारण करने वाले तत्वों की संख्या हो सकती है?


2
प्रकार-सुरक्षा के लिए देखें stackoverflow.com/questions/19452971/array-size-macro-that-rejects-pointers
TS

3
1000 तक पहुंचाने पर बधाई!
एसएस ऐनी

जवाबों:


1258

कार्यकारी सारांश:

int a[17];
size_t n = sizeof(a)/sizeof(a[0]);

पूर्ण उत्तर:

बाइट्स में अपने सरणी का आकार निर्धारित करने के लिए, आप sizeof ऑपरेटर का उपयोग कर सकते हैं :

int a[17];
size_t n = sizeof(a);

मेरे कंप्यूटर पर, ints 4 बाइट्स लंबे हैं, इसलिए n 68 है।

सरणी में तत्वों की संख्या निर्धारित करने के लिए, हम सरणी तत्व के आकार से सरणी के कुल आकार को विभाजित कर सकते हैं। आप इसे इस प्रकार से कर सकते हैं:

int a[17];
size_t n = sizeof(a) / sizeof(int);

और उचित उत्तर प्राप्त करें (68/4 = 17), लेकिन यदि आप जिस प्रकार के aबदले हुए हैं, तो यदि आपके पास एक बुरा बग है तो आप इसे बदलना भी भूल जाएंगे sizeof(int)

तो पसंदीदा भाजक sizeof(a[0])या समतुल्य है sizeof(*a), सरणी के पहले तत्व का आकार।

int a[17];
size_t n = sizeof(a) / sizeof(a[0]);

एक और लाभ यह है कि अब आप आसानी से एक मैक्रो में सरणी नाम को माप सकते हैं और प्राप्त कर सकते हैं:

#define NELEMS(x)  (sizeof(x) / sizeof((x)[0]))

int a[17];
size_t n = NELEMS(a);

6
उत्पन्न कोड समान होगा, क्योंकि संकलक को संकलन समय पर * int_arr का प्रकार पता है (और इसलिए sizeof (* int_arr) का मान)। यह एक स्थिरांक होगा, और संकलक तदनुसार अनुकूलित कर सकता है।
मार्क हैरिसन

10
यह सभी संकलक के मामले में होना चाहिए, क्योंकि आकार के परिणामों को एक संकलन-समय स्थिर के रूप में परिभाषित किया गया है।
मार्क हैरिसन

449
महत्वपूर्ण : यहां पढ़ना बंद न करें, अगला उत्तर पढ़ें! यह केवल स्टैक पर सरणियों के लिए काम करता है , उदाहरण के लिए यदि आप मॉलोक () का उपयोग कर रहे हैं या फ़ंक्शन पैरामीटर तक पहुंच रहे हैं, तो आप भाग्य से बाहर हैं। निचे देखो।
मार्कस

7
C या C ++ में Windows API प्रोग्रामिंग के लिए, इसमें ARRAYSIZEपरिभाषित किया गया makro है WinNT.h(जो अन्य हेडर द्वारा खींचा जाता है)। तो WinAPI उपयोगकर्ताओं को अपने स्वयं के makro को परिभाषित करने की आवश्यकता नहीं है।
लूमी

17
@ मर्कस यह किसी भी चर के लिए काम करता है जिसमें एक सरणी प्रकार होता है; यह "स्टैक पर" होना नहीं है। जैसे static int a[20];। लेकिन आपकी टिप्पणी उन पाठकों के लिए उपयोगी है जो किसी सरणी और पॉइंटर के बीच के अंतर को महसूस नहीं कर सकते हैं।
MM

807

sizeofजिस तरह से सही तरीका है iff आप पैरामीटर के रूप में प्राप्त नहीं सरणियों के साथ काम कर रहे हैं। किसी फ़ंक्शन के पैरामीटर के रूप में भेजे गए सरणी को पॉइंटर के रूप में माना जाता है, इसलिए sizeofएरे के सरणी के बजाय सूचक के आकार को वापस कर देगा।

इस प्रकार, कार्यों के अंदर यह विधि काम नहीं करती है। इसके बजाय, हमेशा size_t sizeसरणी में तत्वों की संख्या को इंगित करते हुए एक अतिरिक्त पैरामीटर पास करें ।

परीक्षा:

#include <stdio.h>
#include <stdlib.h>

void printSizeOf(int intArray[]);
void printLength(int intArray[]);

int main(int argc, char* argv[])
{
    int array[] = { 0, 1, 2, 3, 4, 5, 6 };

    printf("sizeof of array: %d\n", (int) sizeof(array));
    printSizeOf(array);

    printf("Length of array: %d\n", (int)( sizeof(array) / sizeof(array[0]) ));
    printLength(array);
}

void printSizeOf(int intArray[])
{
    printf("sizeof of parameter: %d\n", (int) sizeof(intArray));
}

void printLength(int intArray[])
{
    printf("Length of parameter: %d\n", (int)( sizeof(intArray) / sizeof(intArray[0]) ));
}

आउटपुट (64-बिट लिनक्स OS में):

sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2

आउटपुट (एक 32-बिट विंडोज़ ओएस में):

sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1

10
length of parameter:2यदि केवल एरे एरे तत्व का कोई संकेतक पास किया जाता है तो क्यों ?
Bbvarghe

16
@Bbvarghe ऐसा इसलिए है क्योंकि 64 बिट सिस्टम में पॉइंटर्स 8 बाइट्स (साइज़ोफ़ (इंट्रायरे)) हैं, लेकिन इन्टल्स अभी भी (आमतौर पर) 4 बाइट्स लंबे होते हैं (साइज़ोफ़ (इंट्रैरे [0]))।
एलाइड

13
@Pacerier: कोई सही कोड नहीं है - सामान्य समाधान यह है कि लंबाई को सरणी के साथ-साथ एक अलग तर्क के रूप में पारित किया जाए।
जीन होमिनल

10
रुको, तो एक सूचक से सीधे सरणी तक पहुंचने और उसके आकार को देखने का कोई तरीका नहीं है? यहां C से नया
सूदो

7
@Michael Trouw: यदि बनाता है आप बेहतर महसूस है आप ऑपरेटर सिंटैक्स का उपयोग कर सकते हैं: (sizeof array / sizeof *array)
चकरली

134

यह ध्यान देने योग्य है कि sizeofकिसी सरणी मान के साथ काम करते समय मदद नहीं करता है जो एक सूचक को क्षय हो गया है: भले ही यह एक सरणी की शुरुआत की ओर इशारा करता है, संकलक के लिए यह उस सरणी के एकल तत्व के लिए सूचक के समान है । एक पॉइंटर उस सरणी के बारे में और कुछ भी "याद" नहीं करता है जिसका उपयोग इसे आरंभ करने के लिए किया गया था।

int a[10];
int* p = a;

assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));

1
@ मैग्नस: मानक आकार को आकार में परिभाषित करता है क्योंकि ऑब्जेक्ट में बाइट्स की संख्या पैदावार होती है और यह आकार (चार) हमेशा एक होता है। एक बाइट में बिट्स की संख्या कार्यान्वयन विशिष्ट है। संपादित करें: ANSI C ++ मानक खंड 5.3.3 Sizeof: "आकारऑफ़ ऑपरेटर अपने ऑपरेटर के ऑब्जेक्ट प्रतिनिधित्व में बाइट्स की संख्या पैदा करता है। [...] sizeof (char), sizeof (हस्ताक्षर किए गए चार) और sizeof (अहस्ताक्षरित चार)। 1, किसी भी अन्य मौलिक प्रकार पर लागू आकार का परिणाम कार्यान्वयन-परिभाषित है। "
स्किज़

धारा 1.6 C ++ मेमोरी मॉडल: "C ++ मेमोरी मॉडल में मूलभूत स्टोरेज बाइट है। एक बाइट कम से कम इतनी बड़ी होती है कि इसमें बेसिक एक्ज़ीक्यूटिव कैरेक्टर सेट का कोई भी सदस्य होता है और यह बिट्स के एक क्रमबद्ध अनुक्रम से बना होता है। जिनमें से कार्यान्वयन-परिभाषित है। "
स्किज़

2
मुझे याद है कि CRAY charमें 32 बिट्स के साथ C था । सभी मानक कहते हैं कि 0 से 127 तक पूर्णांक मानों का प्रतिनिधित्व किया जा सकता है, और इसकी सीमा कम से कम या तो -127 से 127 (चार पर हस्ताक्षर किए गए) या 0 से 255 (चार्ट अहस्ताक्षरित) है।
वॉनब्रांड

5
यह एक उत्कृष्ट प्रतिक्रिया है। मैं टिप्पणी करना चाहता हूं कि उपरोक्त सभी सिद्धांतों का मूल्यांकन TRUE में किया जाता है।
जावद

49

आकार का "ट्रिक" सबसे अच्छा तरीका है जिसे मैं जानता हूं, एक छोटे से लेकिन (मेरे लिए, यह एक प्रमुख पालतू जानवर है) कोष्ठक के उपयोग में महत्वपूर्ण परिवर्तन।

जैसा कि विकिपीडिया प्रविष्टि स्पष्ट करती है, सी sizeofएक फ़ंक्शन नहीं है; यह एक ऑपरेटर है । इस प्रकार, इसके तर्क के आसपास कोष्ठक की आवश्यकता नहीं है, जब तक कि तर्क एक प्रकार का नाम न हो। यह याद रखना आसान है, क्योंकि यह तर्क को एक कास्ट एक्सप्रेशन की तरह बनाता है, जो कोष्ठक का भी उपयोग करता है।

इसलिए: यदि आपके पास निम्नलिखित हैं:

int myArray[10];

आप इस तरह कोड के साथ तत्वों की संख्या पा सकते हैं:

size_t n = sizeof myArray / sizeof *myArray;

मेरे लिए, कोष्ठक के साथ विकल्प की तुलना में बहुत आसान पढ़ता है। मैं विभाजन के दाहिने हिस्से में तारांकन के उपयोग का पक्ष भी लेता हूं, क्योंकि यह अनुक्रमण की तुलना में अधिक संक्षिप्त है।

बेशक, यह सब संकलन-समय भी है, इसलिए कार्यक्रम के प्रदर्शन को प्रभावित करने वाले विभाजन के बारे में चिंता करने की कोई आवश्यकता नहीं है। इसलिए जहां भी आप कर सकते हैं इस फॉर्म का उपयोग करें।

जब आप एक के बजाय एक वास्तविक वस्तु पर साइज़ोफ़ का उपयोग करना सबसे अच्छा होता है, तब से आपको एक त्रुटि बनाने और गलत प्रकार के बारे में बताने की चिंता करने की आवश्यकता नहीं है।

उदाहरण के लिए, मान लें कि आपके पास एक फ़ंक्शन है जो कुछ डेटा को बाइट्स की एक धारा के रूप में आउटपुट करता है, उदाहरण के लिए एक नेटवर्क में। चलो फ़ंक्शन को कॉल करते हैं send(), और इसे ऑब्जेक्ट के पास भेजने के लिए तर्क के रूप में लेते हैं, और ऑब्जेक्ट में बाइट्स की संख्या। तो, प्रोटोटाइप बन जाता है:

void send(const void *object, size_t size);

और फिर आपको एक पूर्णांक भेजने की आवश्यकता है, इसलिए आप इसे इस तरह से कोड करते हैं:

int foo = 4711;
send(&foo, sizeof (int));

अब, आपने fooदो स्थानों के प्रकार को निर्दिष्ट करके, पैर में खुद को गोली मारने का एक सूक्ष्म तरीका पेश किया है । यदि एक बदलता है, लेकिन दूसरा नहीं बदलता है, तो कोड टूट जाता है। इस प्रकार, इसे हमेशा इस तरह से करें:

send(&foo, sizeof foo);

अब तुम सुरक्षित हो। ज़रूर, आप चर के नाम की नक़ल करते हैं, लेकिन यह एक तरह से टूटने की उच्च संभावना है जो संकलक का पता लगा सकता है, अगर आप इसे बदलते हैं।


Btw, क्या वे प्रोसेसर स्तर पर समान निर्देश हैं? करता है sizeof(int)की तुलना में कम निर्देश की आवश्यकता होती है sizeof(foo)?
पेसियर

@ स्पेसर: नहीं, वे समान हैं। int x = 1+1;बनाम के बारे में सोचो int x = (1+1);। यहाँ, कोष्ठक विशुद्ध रूप से बिल्कुल सौंदर्यपूर्ण हैं।
quetzalcoatl

@ अदीकापी यह सच नहीं है, C99 VLAs पर विचार करें।
खोलना

@ धन्यवाद धन्यवाद, मैं सही हूं। मेरी टिप्पणी को ठीक करने के लिए, sizeofC ++ और C89 में हमेशा स्थिर रहेंगे। C99 की चर लंबाई सरणियों के साथ, इसका मूल्यांकन रनटाइम पर किया जा सकता है।
ऐदीकापी १३'१६ को

2
sizeofएक ऑपरेटर हो सकता है लेकिन इसे लिनुस टॉर्वाल्ड्स के अनुसार एक फ़ंक्शन के रूप में माना जाना चाहिए। मैं सहमत हूँ। यहां उनके तर्कसंगत पढ़ें: lkml.org/lkml/2012/7/11/103
डॉ। पर्सन पर्सन II

37
int size = (&arr)[1] - arr;

की जाँच करें इस लिंक विवरण के लिए


7
लघु नाइटिक: पॉइंटर घटाव का परिणाम प्रकार होता है ptrdiff_t। (आमतौर पर 64-बिट सिस्टम पर, यह तुलना में एक बड़ा प्रकार होगा int)। यहां तक कि अगर आप बदलना intकरने के लिए ptrdiff_tइस कोड में, यह अभी भी एक बग अगर है arrपता स्थान के आधे से अधिक लेता है।
एमएम

2
@MM एक और छोटा नाइटपिक: आपके सिस्टम आर्किटेक्चर के आधार पर, पता स्पेस लगभग अधिकांश सिस्टम पर पॉइंटर साइज़ जितना बड़ा नहीं है। उदाहरण के लिए विंडोज 64-बिट अनुप्रयोगों के लिए 8TB या 44 बिट्स के लिए पता स्थान सीमित करता है। इसलिए, भले ही आपके पास अपने पते के आधे से बड़े हिस्से की जगह 4.1TB हो, उदाहरण के लिए, यह बग नहीं होगा। केवल अगर आपका पता स्थान उन सिस्टम पर 63-बिट्स से अधिक है, तो इस तरह के बग का सामना करना भी संभव है। सामान्य तौर पर, इसके बारे में चिंता न करें।
इतियाकापी

1
32-बिट x86 लिनक्स पर या विंडोज पर /3Gविकल्प के साथ @Aidiakapi आपके पास 3G / 1G उपयोगकर्ता / कर्नेल विभाजन है, जिससे आपको पता स्थान आकार का 75% तक सरणियाँ मिल सकती हैं।
रुस्लान

1
foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];वैश्विक चर के रूप में विचार करें । buf3[]घोषणा विफल हो जाती (&buf1)[1] - buf1है क्योंकि कोई स्थिर नहीं है।
chux

2
यह तकनीकी रूप से अपरिभाषित व्यवहार है क्योंकि मानक एक सरणी के अंत में स्पष्ट रूप से डेरेफेरिंग को रोक देता है (भले ही आप संग्रहीत मूल्य को पढ़ने की कोशिश नहीं करते हैं)
एमएम

26

आप sizeof ऑपरेटर का उपयोग कर सकते हैं, लेकिन यह फ़ंक्शन के लिए काम नहीं करेगा क्योंकि यह पॉइंटर का संदर्भ लेगा जो आप एक सरणी की लंबाई का पता लगाने के लिए निम्न कार्य कर सकते हैं:

len = sizeof(arr)/sizeof(arr[0])

कोड मूल रूप से यहां पाया गया: सी प्रोग्राम एक सरणी में तत्वों की संख्या को खोजने के लिए


21

यदि आप सरणी का डेटा प्रकार जानते हैं, तो आप कुछ का उपयोग कर सकते हैं:

int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};

int noofele = sizeof(arr)/sizeof(int);

या यदि आप डेटा प्रकार के सरणी को नहीं जानते हैं, तो आप कुछ का उपयोग कर सकते हैं:

noofele = sizeof(arr)/sizeof(arr[0]);

नोट: यह चीज़ केवल तभी काम करती है जब सरणी रन टाइम (जैसे मॉलॉक) में परिभाषित नहीं होती है और सरणी किसी फ़ंक्शन में पारित नहीं होती है। दोनों मामलों में, arr(सरणी नाम) एक सूचक है।


4
int noofele = sizeof(arr)/sizeof(int);कोडिंग की तुलना में केवल आधा रास्ता बेहतर है int noofele = 9;sizeof(arr)लचीलेपन का उपयोग करके सरणी का आकार बदलना चाहिए। फिर भी sizeof(int)एक arr[]बदलाव की आवश्यकता है एक अद्यतन चाहिए । sizeof(arr)/sizeof(arr[0])यदि प्रकार अच्छी तरह से जाना जाता है, तब भी उपयोग करने के लिए बेहतर है । अस्पष्ट क्यों बनाम के intलिए उपयोग करके , प्रकार द्वारा लौटा दिया गया । noofelesize_tsizeof()
चक्स -

19

मैक्रो ARRAYELEMENTCOUNT(x)जिसे हर कोई गलत तरीके से मूल्यांकन का उपयोग कर रहा है । यह, वास्तविक रूप से, सिर्फ एक संवेदनशील मामला है, क्योंकि आपके पास 'सरणी' प्रकार के परिणामस्वरूप अभिव्यक्ति नहीं हो सकती है।

/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))

ARRAYELEMENTCOUNT(p + 1);

वास्तव में मूल्यांकन करता है:

(sizeof (p + 1) / sizeof (p + 1[0]));

जहाँ तक

/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])

ARRAYELEMENTCOUNT(p + 1);

यह सही तरीके से मूल्यांकन करता है:

(sizeof (p + 1) / sizeof (p + 1)[0]);

यह वास्तव में स्पष्ट रूप से सरणियों के आकार के साथ बहुत कुछ नहीं करता है। मैंने अभी-अभी देखा है कि C प्रीप्रोसेसर कैसे काम करता है, वास्तव में बहुत सी त्रुटियों पर ध्यान नहीं दिया है। आप हमेशा मैक्रो पैरामीटर को लपेटते हैं, एक अभिव्यक्ति में शामिल नहीं हो सकते हैं।


यह सही है; मेरा उदाहरण एक बुरा था। लेकिन वास्तव में ऐसा ही होना चाहिए। जैसा कि मैंने पहले बतायाp + 1 था कि एक पॉइंटर प्रकार के रूप में समाप्त हो जाएगा और पूरे मैक्रो को अमान्य कर देगा (जैसे कि यदि आपने पॉइंटर पैरामीटर के साथ फ़ंक्शन में मैक्रो का उपयोग करने का प्रयास किया है)।

दिन के अंत में, इस विशेष उदाहरण में, गलती वास्तव में मायने नहीं रखती है (इसलिए मैं हर किसी के समय को बर्बाद कर रहा हूं; हुज़ाह!), क्योंकि आपके पास एक प्रकार के 'सरणी' के साथ अभिव्यक्ति नहीं है। लेकिन वास्तव में प्रीप्रोसेसर मूल्यांकन के बारे में बिंदु मुझे लगता है कि एक महत्वपूर्ण है।


2
स्पष्टीकरण के लिए धन्यवाद। मूल संस्करण एक संकलन-समय त्रुटि का परिणाम देता है। क्लैंग की रिपोर्ट "सबस्क्रिप्टेड वैल्यू एक सरणी, पॉइंटर या वेक्टर नहीं है"। इस उदाहरण में यह बेहतर व्यवहार लगता है, हालांकि मैक्रोज़ में मूल्यांकन आदेश के बारे में आपकी टिप्पणी अच्छी तरह से ली गई है।
मार्क हैरिसन

1
मैंने कंपाइलर शिकायत के बारे में गलत प्रकार के स्वचालित अधिसूचना के रूप में नहीं सोचा था। धन्यवाद!

3
उपयोग न करने का कोई कारण है (sizeof (x) / sizeof (*x))?
गंभीरदेव

16

के लिए बहुआयामी सरणियों यह एक बालक अधिक जटिल है। अक्सर लोग स्पष्ट स्थूल स्थिरांक को परिभाषित करते हैं, अर्थात

#define g_rgDialogRows   2
#define g_rgDialogCols   7

static char const* g_rgDialog[g_rgDialogRows][g_rgDialogCols] =
{
    { " ",  " ",    " ",    " 494", " 210", " Generic Sample Dialog", " " },
    { " 1", " 330", " 174", " 88",  " ",    " OK",        " " },
};

लेकिन इन स्थिरांक का संकलन-समय पर आकार के साथ भी मूल्यांकन किया जा सकता है :

#define rows_of_array(name)       \
    (sizeof(name   ) / sizeof(name[0][0]) / columns_of_array(name))
#define columns_of_array(name)    \
    (sizeof(name[0]) / sizeof(name[0][0]))

static char* g_rgDialog[][7] = { /* ... */ };

assert(   rows_of_array(g_rgDialog) == 2);
assert(columns_of_array(g_rgDialog) == 7);

ध्यान दें कि यह कोड C और C ++ में काम करता है। दो से अधिक आयामों वाले सरणियों के लिए उपयोग करें

sizeof(name[0][0][0])
sizeof(name[0][0][0][0])

आदि, एड इन्फिनिटम।


15
sizeof(array) / sizeof(array[0])

प्रकार पर निर्भर होने पर array, आपको उपयोग करने की आवश्यकता नहीं है sizeof(array) / sizeof(array[0])यदि या arrayतो एक सरणी है char, unsigned charया signed char- C18,6.5.3.4 / 4 से उद्धरण: "जब आकारऑफ़ को एक ऑपरेंड पर लागू किया जाता है जिसमें टाइप चार, अहस्ताक्षरित चार या हस्ताक्षरित चार होते हैं , (या उसके योग्य संस्करण) परिणाम 1. है। " इस मामले में आप बस sizeof(array)मेरे समर्पित उत्तर में बताए अनुसार कर सकते हैं ।
रॉबर्ट्स

15

सी में एक सरणी का आकार:

int a[10];
size_t size_of_array = sizeof(a);      // Size of array a
int n = sizeof (a) / sizeof (a[0]);    // Number of elements in array a
size_t size_of_element = sizeof(a[0]); // Size of each element in array a                                          
                                       // Size of each element = size of type

4
जिज्ञासु कोड का इस्तेमाल किया है कि size_t size_of_elementअभी तक intके साथ int n = sizeof (a) / sizeof (a[0]); और नहींsize_t n = sizeof (a) / sizeof (a[0]);
chux - को पुनः स्थापित मोनिका

1
हाय @Yogeesh HT, क्या आप कृपया chux के संदेह का उत्तर दे सकते हैं। मुझे यह जानने के लिए भी बहुत उत्सुकता है कि int n = sizeof (a) / sizeof ([0]) सरणी की लंबाई कैसे दे रहा है और हम सरणी की लंबाई के लिए size_t का उपयोग क्यों नहीं कर रहे हैं। क्या कोई इसका जवाब दे सकता है?
ब्रेन

1
@Brain sizeof (a) सरणी में मौजूद सभी तत्वों के आकार का आकार देता है (a [0]) 1 तत्वों का आकार देता है। मान लीजिए एक = {1,2,3,4,5}; sizeof (a) = 20bytes (यदि sizeof (int) = 4bytes गुणा 5), sizeof (एक [0]) = 4bytes, तो 20/4 = 5 अर्थात कोई भी तत्व नहीं
योगेश HT

2
@YogeeshHT जैसे बहुत बड़े सरणियों के लिए char a[INT_MAX + 1u];, int nजैसा int n = sizeof (a) / sizeof (a[0]);कि अपर्याप्त है (यह यूबी है)। उपयोग करने से size_t n = sizeof (a) / sizeof (a[0]);यह समस्या उत्पन्न नहीं होती है।
chux

13

मैं sizeofकिसी भी सरणी के दो अलग-अलग आकार, या तत्वों की संख्या या बाइट्स में से किसी एक को प्राप्त करने के लिए (भले ही इसका उपयोग किया जा सकता है) का उपयोग न करने की सलाह दूंगा, जो कि पिछले दो मामले हैं जो मैं यहां दिखाता हूं। प्रत्येक दो आकारों के लिए, नीचे दिखाए गए मैक्रो का उपयोग इसे सुरक्षित बनाने के लिए किया जा सकता है। कारण देखरेख करने के लिए कोड का स्पष्ट इरादा है, और फर्क है sizeof(ptr)से sizeof(arr)पहली नजर में तो यह है कि कीड़े तो हर कोई कोड को पढ़ने के लिए स्पष्ट हैं (जो इस तरह से लिखा स्पष्ट नहीं है),।


टी एल; डॉ:

#define ARRAY_SIZE(arr)     (sizeof(arr) / sizeof((arr)[0]) + must_be_array(arr))

#define ARRAY_SSIZE(arr)    ((ptrdiff_t)ARRAY_SIZE(arr))

#define ARRAY_BYTES(arr)    (sizeof((arr)[0]) * ARRAY_SIZE(arr))

must_be_array(arr)(नीचे परिभाषित किया गया है) आईएस की जरूरत -Wsizeof-pointer-divहै जो छोटी गाड़ी (अप्रैल / 2020 तक) है:

#define is_same_type(a, b)      __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a)             (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a)  _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a)        (                                       \
        0 * (int)sizeof(                                                \
                struct {                                                \
                        Static_assert_array(a);                         \
                        char ISO_C_forbids_a_struct_with_no_members__;  \
                }                                                       \
        )                                                               \
)

इस विषय के बारे में महत्वपूर्ण कीड़े हैं: https://lkml.org/lkml/2015/9/3/428

मैं उस समाधान से असहमत हूं जो लिनुस प्रदान करता है, जो कि कार्यों के मापदंडों के लिए सरणी संकेतन का उपयोग कभी नहीं करना है।

मुझे प्रलेखन के रूप में सरणी संकेतन पसंद है कि एक सूचक एक सरणी के रूप में उपयोग किया जा रहा है। लेकिन इसका मतलब यह है कि एक मूर्ख-प्रूफ समाधान को लागू करने की आवश्यकता है ताकि छोटी गाड़ी कोड लिखना असंभव हो।

एक सरणी से हमारे तीन आकार होते हैं जिन्हें हम जानना चाहते हैं:

  • सरणी के तत्वों का आकार
  • सरणी में तत्वों की संख्या
  • स्मृति में सरणी का उपयोग करने वाले बाइट्स में आकार

सरणी के तत्वों का आकार

पहला एक बहुत ही सरल है, और इससे कोई फर्क नहीं पड़ता कि हम किसी सरणी या पॉइंटर के साथ काम कर रहे हैं, क्योंकि यह उसी तरह से किया गया है।

उपयोग का उदाहरण:

void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
        qsort(arr, nmemb, sizeof(arr[0]), cmp);
}

qsort() इसके तीसरे तर्क के रूप में इस मूल्य की आवश्यकता है।


अन्य दो आकारों के लिए, जो प्रश्न का विषय हैं, हम यह सुनिश्चित करना चाहते हैं कि हम एक सरणी के साथ काम कर रहे हैं, और संकलन को तोड़ दें यदि नहीं, क्योंकि यदि हम एक सूचक के साथ काम कर रहे हैं, तो हमें गलत मान मिलेंगे । जब संकलन टूट जाता है, तो हम आसानी से देख पाएंगे कि हम किसी एरे से काम नहीं कर रहे हैं, बल्कि एक पॉइंटर के साथ, और हमें कोड को एक वैरिएबल या मैक्रो के साथ लिखना होगा, जो साइज़ को स्टोर करता है सूचक के पीछे सरणी।


सरणी में तत्वों की संख्या

यह सबसे आम है, और कई जवाबों ने आपको विशिष्ट मैक्रो ARRAY_SIZE प्रदान किया है:

#define ARRAY_SIZE(arr)     (sizeof(arr) / sizeof((arr)[0]))

यह देखते हुए कि ARRAY_SIZE के परिणाम का आमतौर पर हस्ताक्षरित चर प्रकार के साथ उपयोग किया जाता है ptrdiff_t, इस मैक्रो के एक हस्ताक्षरित संस्करण को परिभाषित करना अच्छा है:

#define ARRAY_SSIZE(arr)    ((ptrdiff_t)ARRAY_SIZE(arr))

PTRDIFF_MAXमैक्रो के इस हस्ताक्षर किए गए संस्करण के लिए सदस्यों से अधिक के साथ अमान्य मूल्य देने जा रहे हैं, लेकिन C17 :: 6.5.6.9 को पढ़ने से, जैसे कि पहले से ही आग से खेल रहे हैं। केवल ARRAY_SIZEऔर size_tउन मामलों में उपयोग किया जाना चाहिए।

संकलक के हाल के संस्करण, जैसे कि जीसीसी 8, जब आप इस मैक्रो को एक पॉइंटर पर लागू करते हैं, तो यह आपको चेतावनी देगा, इसलिए यह सुरक्षित है (पुराने संकलक के साथ इसे सुरक्षित बनाने के अन्य तरीके हैं)।

यह प्रत्येक तत्व के आकार से पूरे सरणी के बाइट्स में आकार को विभाजित करके काम करता है।

उपयोग के उदाहरण:

void foo(ptrdiff_t nmemb)
{
        char buf[nmemb];

        fgets(buf, ARRAY_SIZE(buf), stdin);
}

void bar(ptrdiff_t nmemb)
{
        int arr[nmemb];

        for (ptrdiff_t i = 0; i < ARRAY_SSIZE(arr); i++)
                arr[i] = i;
}

यदि ये फ़ंक्शन सरणियों का उपयोग नहीं करते हैं, लेकिन उन्हें मापदंडों के रूप में मिला है, तो पूर्व कोड संकलित नहीं करेगा, इसलिए बग होना असंभव होगा (यह देखते हुए कि हाल ही में संकलक संस्करण का उपयोग किया गया है, या कि कुछ अन्य चाल का उपयोग किया जाता है) , और हमें मूल्य द्वारा मैक्रो कॉल को बदलने की आवश्यकता है:

void foo(ptrdiff_t nmemb, char buf[nmemb])
{

        fgets(buf, nmemb, stdin);
}

void bar(ptrdiff_t nmemb, int arr[nmemb])
{

        for (ptrdiff_t i = 0; i < nmemb; i++)
                arr[i] = i;
}

स्मृति में सरणी का उपयोग करने वाले बाइट्स में आकार

ARRAY_SIZE आमतौर पर पिछले मामले के समाधान के रूप में उपयोग किया जाता है, लेकिन यह मामला शायद ही कभी सुरक्षित रूप से लिखा जाता है, शायद इसलिए कि यह कम आम है।

इस मान को प्राप्त करने का सामान्य तरीका उपयोग करना है sizeof(arr)। समस्या: पिछले वाले के समान ही; यदि आपके पास एक सरणी के बजाय एक सूचक है, तो आपका कार्यक्रम पागल हो जाएगा।

समस्या के समाधान में पहले की तरह ही मैक्रो का उपयोग करना शामिल है, जिसे हम सुरक्षित होना जानते हैं (यह संकलक पर लागू होता है तो यह संकलक को तोड़ता है):

#define ARRAY_BYTES(arr)        (sizeof((arr)[0]) * ARRAY_SIZE(arr))

यह कैसे काम करता है बहुत सरल है: यह उस विभाजन को पूर्ववत ARRAY_SIZEकरता है, जो गणितीय रद्दीकरण के बाद आप केवल एक के साथ समाप्त होता है sizeof(arr), लेकिन ARRAY_SIZEनिर्माण की अतिरिक्त सुरक्षा के साथ ।

उपयोग का उदाहरण:

void foo(ptrdiff_t nmemb)
{
        int arr[nmemb];

        memset(arr, 0, ARRAY_BYTES(arr));
}

memset() इसके तीसरे तर्क के रूप में इस मूल्य की आवश्यकता है।

पहले की तरह, यदि सरणी को एक पैरामीटर (एक सूचक) के रूप में प्राप्त किया जाता है, तो यह संकलन नहीं करेगा, और हमें मूल्य द्वारा मैक्रो कॉल को बदलना होगा:

void foo(ptrdiff_t nmemb, int arr[nmemb])
{

        memset(arr, 0, sizeof(arr[0]) * nmemb);
}

अद्यतन (23 / अप्रैल / 2020): -Wsizeof-pointer-divछोटी गाड़ी है :

आज मुझे पता चला कि जीसीसी में नई चेतावनी केवल तभी काम करती है जब मैक्रो को एक हेडर में परिभाषित किया गया है जो सिस्टम हेडर नहीं है। यदि आप अपने सिस्टम (आमतौर पर /usr/local/include/या /usr/include/) ( #include <foo.h>) में स्थापित हैडर में मैक्रो को परिभाषित करते हैं , तो संकलक एक चेतावनी का उत्सर्जन नहीं करेगा (मैंने जीसीसी 9.3.0 की कोशिश की)।

इसलिए हम #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))इसे सुरक्षित बनाना चाहते हैं। हमें C11 _Static_assert()और कुछ GCC एक्सटेंशन की आवश्यकता होगी : अभिव्यक्ति और कथन में अभिव्यक्तियाँ , __builtin_types_compatible_p :

#define is_same_type(a, b)      __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a)             (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a)  _Static_assert(is_array(a), "Not a `[]` !")

#define ARRAY_SIZE(arr)         (                                       \
{                                                                       \
        Static_assert_array(arr);                                       \
        sizeof(arr) / sizeof((arr)[0]);                                \
}                                                                       \
)

अब ARRAY_SIZE()पूरी तरह से सुरक्षित है, और इसलिए इसके सभी डेरिवेटिव सुरक्षित होंगे।


अद्यतन: libbsd प्रदान करता है __arraycount() :

Libbsd में मैक्रो प्रदान करता __arraycount()है<sys/cdefs.h> , जो असुरक्षित है क्योंकि इसमें कोष्ठक की एक जोड़ी का अभाव है, लेकिन हम उन कोष्ठक को स्वयं जोड़ सकते हैं, और इसलिए हमें अपने हेडर में विभाजन लिखने की आवश्यकता नहीं है (हम पहले से मौजूद कोड की नकल क्यों करेंगे? )। उस मैक्रो को सिस्टम हेडर में परिभाषित किया गया है, इसलिए यदि हम इसका उपयोग करते हैं तो हम उपरोक्त मैक्रोज़ का उपयोग करने के लिए मजबूर हो जाते हैं।

#include <sys/cdefs.h>


#define is_same_type(a, b)      __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a)             (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a)  _Static_assert(is_array(a), "Not a `[]` !")

#define ARRAY_SIZE(arr)         (                                       \
{                                                                       \
        Static_assert_array(arr);                                       \
        __arraycount((arr));                                            \
}                                                                       \
)

#define ARRAY_SSIZE(arr)        ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr)        (sizeof((arr)[0]) * ARRAY_SIZE(arr))

कुछ सिस्टम में प्रदान करते nitems()हैं<sys/param.h> बजाय, और कुछ सिस्टम दोनों प्रदान करते हैं। आपको अपनी प्रणाली की जांच करनी चाहिए, और आपके पास जो भी है उसका उपयोग करें, और शायद पोर्टेबिलिटी के लिए कुछ प्रीप्रोसेसर कंडिशनर का उपयोग करें और दोनों का समर्थन करें।


अद्यतन: मैक्रो को फ़ाइल स्कोप पर उपयोग करने की अनुमति दें:

दुर्भाग्य से, ({})फ़ाइल एक्सटेंशन में gcc एक्सटेंशन का उपयोग नहीं किया जा सकता है। फ़ाइल स्कोप पर मैक्रो का उपयोग करने में सक्षम होने के लिए, स्थैतिक अभिकथन अंदर होना चाहिए sizeof(struct {})। फिर, 0परिणाम को प्रभावित नहीं करने के लिए इसे गुणा करें । एक कास्ट (int)एक फ़ंक्शन को अनुकरण करने के लिए अच्छा हो सकता है जो रिटर्न करता है (int)0(इस मामले में यह आवश्यक नहीं है, लेकिन फिर यह कुछ चीजों के लिए पुन: प्रयोज्य है)।

#include <sys/cdefs.h>


#define is_same_type(a, b)      __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a)             (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a)  _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a)        (                                       \
        0 * (int)sizeof(                                                \
                struct {                                                \
                        Static_assert_array(a);                         \
                        char ISO_C_forbids_a_struct_with_no_members__;  \
                }                                                       \
        )                                                               \
)

#define ARRAY_SIZE(arr)         (__arraycount((arr)) + must_be_array(arr))
#define ARRAY_SSIZE(arr)        ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr)        (sizeof((arr)[0]) * ARRAY_SIZE(arr))

3
क्या आप यह समझाना चाहेंगे कि नीचे की ओर क्यों? यह एक असुरक्षित और सामान्य निर्माण ( sizeof(arr)) का समाधान दिखाता है जो कहीं और नहीं दिखाया गया है ARRAY_BYTES(arr):।
काकाहुइट फ्रिटो

2
ARRAY_SIZE का उपयोग आम तौर पर स्वतंत्र रूप से किया जाना है, और ARRAY_BYTES इसके नाम में बहुत स्पष्ट है, ARRAY_SIZE के बगल में परिभाषित किया जाना चाहिए, ताकि उपयोगकर्ता दोनों को आसानी से देख सके, और इसके उपयोग से, मुझे नहीं लगता कि किसी को भी कोड को पढ़ने में कोई संदेह है। ऐसा होता है। मेरा मतलब है कि एक साधारण का उपयोग न करें sizeof, लेकिन इसके बजाय इस निर्माण का उपयोग करें; अगर आपको हर बार इन निर्माणों को लिखने का मन करता है, तो आप संभवतः एक गलती करेंगे (यदि आप कॉपी पेस्ट करते हैं, तो बहुत सामान्य है और यदि आप उन्हें हर बार लिखते हैं क्योंकि उनके पास बहुत सारे कोष्ठक हैं) ...
Cacahuete Frito

3
..., इसलिए मैं मुख्य निष्कर्ष पर खड़ा हूं: एक sizeofस्पष्ट रूप से असुरक्षित है (उत्तर में कारण हैं), और मैक्रोज़ का उपयोग नहीं कर रहे हैं, लेकिन मेरे द्वारा प्रदान किए गए निर्माणों का उपयोग करते हुए, हर बार, और भी असुरक्षित है, इसलिए जाने का एकमात्र तरीका मैक्रोज़ है।
काकाहुइट फ्रिटो

3
@MarkHarrison मुझे संकेत और सरणियों के बीच का अंतर पता है। लेकिन कई बार मेरे पास एक समारोह था जिसे मैंने बाद में छोटे कार्यों में बदल दिया, और जो पहले एक सरणी था, बाद में एक सूचक था, और यह एक बिंदु है जहां अगर आप आकार बदलना भूल जाते हैं, तो आप इसे पेंच करते हैं, और यह नहीं देखना आसान है उनमें से एक।
काकाहुइते फ्रिटो

3
@ मुझे यह भी पता है कि अंतर का मतलब यह नहीं है कि हर कोई अंतर जानता है, और क्यों न उन चीजों का उपयोग किया जाए जो मूल रूप से उन बगों का 100% निकालते हैं? उस बग ने लगभग इसे लिनक्स में बनाया; यह लिनुस तक पहुंच गया, जिसका अर्थ है कि यह बहुत जांच से गुजर गया, और जिसका अर्थ यह भी है कि एक ही बग ने इसे कर्नेल के दूसरे भाग में लिनक्स में बनाया है, जैसा कि वह कहता है।
काकाहुइट फ्रिटो

11

"आपने खुद को पैर में गोली मारने का एक सूक्ष्म तरीका पेश किया है"

C 'देशी' सरणियाँ अपने आकार को संग्रहीत नहीं करती हैं। इसलिए यह एक अलग चर / कास्ट में सरणी की लंबाई को बचाने के लिए अनुशंसित है, और जब भी आप सरणी पास करते हैं, तो इसे पास करें:

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

आप हमेशा मूल सरणियों से बचें (जब तक आप ऐसा नहीं कर सकते, जिस स्थिति में, अपने पैर का ध्यान रखें)। यदि आप C ++ लिख रहे हैं, तो STL के 'वेक्टर' कंटेनर का उपयोग करें। "सरणियों की तुलना में, वे लगभग समान प्रदर्शन प्रदान करते हैं", और वे कहीं अधिक उपयोगी हैं!

// vector is a template, the <int> means it is a vector of ints
vector<int> numbers;  

// push_back() puts a new value at the end (or back) of the vector
for (int i = 0; i < 10; i++)
    numbers.push_back(i);

// Determine the size of the array
cout << numbers.size();

देखें: http://www.cplusplus.com/reference/stl/vector/


मैंने पढ़ा है कि C में पूर्णांक स्थिरांक घोषित करने का उचित तरीका एक enumघोषणा का उपयोग करना है ।
रफी खाचदौरियन 23

प्रश्न C के बारे में है, C ++ के बारे में नहीं। तो कोई एस.टी.एल.
काकाहुइट फ्रिटो

11
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))

6
ध्यान दें कि यह केवल वास्तविक सरणियों के लिए काम करता है, न कि बिंदु जो सरणियों को इंगित करने के लिए होता है।
डेविड श्वार्ट्ज

5

यदि आप वास्तव में ऐसा करना चाहते हैं तो अपने एरे के आस-पास से गुजरने का सुझाव दें। मैं आपको एक व्यूअर को स्टोर करने के लिए एक संरचना को लागू करने का सुझाव देता हूं, जिसमें आप एक सरणी चाहते हैं और एक पूर्णांक सरणी के आकार का प्रतिनिधित्व करते हैं। फिर आप इसे अपने कार्यों के लिए पास कर सकते हैं। बस उस पॉइंटर को ऐरे वेरिएबल वैल्यू (पॉइंटर टू फर्स्ट एलिमेंट) असाइन करें। तब आप Array.arr[i]i-th तत्व प्राप्त करने और उपयोग करने के लिए जा सकते हैंArray.size सरणी में तत्वों की संख्या प्राप्त करने के लिए ।

मैंने आपके लिए कुछ कोड शामिल किए हैं। यह बहुत उपयोगी नहीं है, लेकिन आप इसे और अधिक सुविधाओं के साथ विस्तारित कर सकते हैं। हालांकि, ईमानदार होने के लिए, अगर ये चीजें हैं जो आप चाहते हैं कि आपको सी का उपयोग करना बंद कर देना चाहिए और इन सुविधाओं के साथ एक और भाषा का उपयोग करना चाहिए।

/* Absolutely no one should use this...
   By the time you're done implementing it you'll wish you just passed around
   an array and size to your functions */
/* This is a static implementation. You can get a dynamic implementation and 
   cut out the array in main by using the stdlib memory allocation methods,
   but it will work much slower since it will store your array on the heap */

#include <stdio.h>
#include <string.h>
/*
#include "MyTypeArray.h"
*/
/* MyTypeArray.h 
#ifndef MYTYPE_ARRAY
#define MYTYPE_ARRAY
*/
typedef struct MyType
{
   int age;
   char name[20];
} MyType;
typedef struct MyTypeArray
{
   int size;
   MyType *arr;
} MyTypeArray;

MyType new_MyType(int age, char *name);
MyTypeArray newMyTypeArray(int size, MyType *first);
/*
#endif
End MyTypeArray.h */

/* MyTypeArray.c */
MyType new_MyType(int age, char *name)
{
   MyType d;
   d.age = age;
   strcpy(d.name, name);
   return d;
}

MyTypeArray new_MyTypeArray(int size, MyType *first)
{
   MyTypeArray d;
   d.size = size;
   d.arr = first;
   return d;
}
/* End MyTypeArray.c */


void print_MyType_names(MyTypeArray d)
{
   int i;
   for (i = 0; i < d.size; i++)
   {
      printf("Name: %s, Age: %d\n", d.arr[i].name, d.arr[i].age);
   }
}

int main()
{
   /* First create an array on the stack to store our elements in.
      Note we could create an empty array with a size instead and
      set the elements later. */
   MyType arr[] = {new_MyType(10, "Sam"), new_MyType(3, "Baxter")};
   /* Now create a "MyTypeArray" which will use the array we just
      created internally. Really it will just store the value of the pointer
      "arr". Here we are manually setting the size. You can use the sizeof
      trick here instead if you're sure it will work with your compiler. */
   MyTypeArray array = new_MyTypeArray(2, arr);
   /* MyTypeArray array = new_MyTypeArray(sizeof(arr)/sizeof(arr[0]), arr); */
   print_MyType_names(array);
   return 0;
}

1
strcpy(d.name, name);अतिप्रवाह की हैंडलिंग के साथ नहीं करता है कि upvote कोड नहीं कर सकता ।
chux -

4

इस जानकारी को सहेजने का सबसे अच्छा तरीका है, उदाहरण के लिए, संरचना में:

typedef struct {
     int *array;
     int elements;
} list_s;

सभी आवश्यक कार्यों को लागू करें जैसे कि बनाना, नष्ट करना, समानता की जांच करना, और बाकी सब कुछ जो आपको चाहिए। पैरामीटर के रूप में पास करना आसान है।


6
int elementsबनाम का कोई कारण size_t elements?
चक्स

3

फ़ंक्शन sizeofबाइट्स की संख्या देता है जो मेमोरी में आपके एरे द्वारा उपयोग की जाती है। यदि आप अपने सरणी में तत्वों की संख्या की गणना करना चाहते हैं, तो आपको उस संख्या को sizeofचर के प्रकार के साथ विभाजित करना चाहिए । मान लीजिए int array[10];, यदि आपके कंप्यूटर में चर प्रकार पूर्णांक 32 बिट (या 4 बाइट्स) है, तो आपके सरणी का आकार प्राप्त करने के लिए, आपको निम्न कार्य करना चाहिए:

int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);

2

आप &ऑपरेटर का उपयोग कर सकते हैं । यहाँ स्रोत कोड है:

#include<stdio.h>
#include<stdlib.h>
int main(){

    int a[10];

    int *p; 

    printf("%p\n", (void *)a); 
    printf("%p\n", (void *)(&a+1));
    printf("---- diff----\n");
    printf("%zu\n", sizeof(a[0]));
    printf("The size of array a is %zu\n", ((char *)(&a+1)-(char *)a)/(sizeof(a[0])));


    return 0;
};

यहाँ नमूना आउटपुट है

1549216672
1549216712
---- diff----
4
The size of array a is 10

7
मैं नीचे नहीं गया, लेकिन यह ईंट के साथ एक कील को मारने जैसा है क्योंकि आपने अपने बगल में पड़े एक हथौड़ा को नोटिस नहीं किया था। इसके अलावा, लोग असिंचित चर का उपयोग करने पर भड़क जाते हैं ... लेकिन यहां मुझे लगता है कि यह आपके उद्देश्य को अच्छी तरह से पूरा करता है।
दिमित्री

2
@ डमित्री कोई भी असिंचित चर यहां तक ​​नहीं पहुँचा है
MM

1
हममम। सूचक घटाव की ओर जाता है ptrdiff_tsizeof()में परिणाम size_t। C यह परिभाषित नहीं करता है कि कौन सी व्यापक या उच्च / समान रैंक है। तो भागफल ((char *)(&a+1)-(char *)a)/(sizeof(a[0]))का size_tप्रकार निश्चित रूप से नहीं है और इस प्रकार मुद्रण zसे यूबी हो सकता है। बस उपयोग printf("The size of array a is %zu\n", sizeof a/sizeof a[0]);पर्याप्त है।
chux

1
(char *)(&a+1)-(char *)aएक स्थिर नहीं है और एक निश्चित आकार के साथ, रन-टाइम पर गणना की जा सकती है a[10]sizeof(a)/sizeof(a[0])इस मामले में लगातार संकलन समय पर किया जाता है।
chux -

1

सबसे सरल उत्तर:

#include <stdio.h>

int main(void) {

    int a[] = {2,3,4,5,4,5,6,78,9,91,435,4,5,76,7,34};//for Example only
    int size;

    size = sizeof(a)/sizeof(a[0]);//Method

    printf ("size = %d",size);
    return 0;
}

1

अधिक सुरुचिपूर्ण समाधान होगा

size_t size = sizeof(a) / sizeof(*a);

0

पहले से उपलब्ध कराए गए उत्तरों के अलावा, मैं एक विशेष मामले का उपयोग करके बताना चाहता हूं

sizeof(a) / sizeof (a[0])

यदि aया तो एक सरणी है char, unsigned charया signed charआपको sizeofदो बार उपयोग करने की आवश्यकता नहीं है क्योंकि sizeofइन प्रकारों के एक ऑपरेंड के साथ एक अभिव्यक्ति हमेशा परिणाम देती है 1

C18,6.5.3.4 / 4 से उद्धरण:

" जब sizeofएक संकार्य प्रकार है कि करने के लिए लागू किया जाता है char, unsigned charया signed char, (या उसके एक योग्य संस्करण) परिणाम है 1।"

इस प्रकार, यदि प्रकार की एक सरणी है , या के sizeof(a) / sizeof (a[0])बराबर होगा । 1 के माध्यम से विभाजन निरर्थक है।NUMBER OF ARRAY ELEMENTS / 1acharunsigned charsigned char

इस मामले में, आप बस संक्षिप्त और कर सकते हैं:

sizeof(a)

उदाहरण के लिए:

char a[10];
size_t length = sizeof(a);

यदि आप एक प्रमाण चाहते हैं, तो यहां गॉडबोल्ट की एक कड़ी है ।


फिर भी, यदि विभाजन महत्वपूर्ण रूप से बदलता है, तो डिवीजन सुरक्षा बनाए रखता है (हालांकि ये मामले दुर्लभ हैं)।


1
आप शायद अभी भी विभाजन के साथ एक मैक्रो लागू करना पसंद करते हैं, क्योंकि भविष्य में प्रकार बदल सकता है (हालांकि शायद संभावना नहीं है), और विभाजन को संकलन समय पर जाना जाता है, इसलिए संकलक इसे दूर अनुकूलित करेगा (यदि यह कृपया नहीं बदलता है अपने संकलक)।
काकाहुए फ्रिटो

1
@CacahueteFrito हाँ, मैं उस समय के बारे में भी सोचा था। मैंने इसे उत्तर में एक साइड नोट के रूप में लिया। धन्यवाद।
रॉबर्ट्स मोनिका सेलियो

-1

नोट: यह एक आपको अपरिभाषित व्यवहार दे सकता है जैसा कि एमएम ने टिप्पणी में बताया है।

int a[10];
int size = (*(&a+1)-a) ;

अधिक जानकारी के लिए यहां और यहां भी देखें ।


2
यह तकनीकी रूप से अपरिभाषित व्यवहार है; *ऑपरेटर एक पास्ट अंत सूचक के लिए लागू नहीं किया जा सकता है
एम एम

3
"अपरिभाषित व्यवहार" का अर्थ है कि C मानक व्यवहार को परिभाषित नहीं करता है। यदि आप इसे अपने कार्यक्रम में
MM

@MM आप कह रहे हैं कि ऊपर *(&a+1) - a;से अलग है (&a)[1] - a;, दोनों नहीं *(&a+1)और (&a)[1]अंत में 1 अतीत के रूप में गिना जाता है?
क्वेंटिनुक

@QuentinUK आपके दो भाव दोनों समान हैं, x[y]को परिभाषित किया गया है*(x + (y))
MM

@MM मैंने ऐसा सोचा। लेकिन अर्जुन श्रीधरन द्वारा दिए गए दूसरे उत्तर में 38 अप ऐरो हैं और इसमें -1 हैं। और अर्जुन श्रीधरन के जवाब में अपरिभाषित व्यवहार का कोई उल्लेख नहीं है।
क्वेंटिनुक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.