मैं सी में अपनी सरणी का आकार कैसे निर्धारित करूं?
अर्थात्, सरणी को धारण करने वाले तत्वों की संख्या हो सकती है?
मैं सी में अपनी सरणी का आकार कैसे निर्धारित करूं?
अर्थात्, सरणी को धारण करने वाले तत्वों की संख्या हो सकती है?
जवाबों:
कार्यकारी सारांश:
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);
ARRAYSIZE
परिभाषित किया गया makro है WinNT.h
(जो अन्य हेडर द्वारा खींचा जाता है)। तो WinAPI उपयोगकर्ताओं को अपने स्वयं के makro को परिभाषित करने की आवश्यकता नहीं है।
static int a[20];
। लेकिन आपकी टिप्पणी उन पाठकों के लिए उपयोगी है जो किसी सरणी और पॉइंटर के बीच के अंतर को महसूस नहीं कर सकते हैं।
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
length of parameter:2
यदि केवल एरे एरे तत्व का कोई संकेतक पास किया जाता है तो क्यों ?
(sizeof array / sizeof *array)
।
यह ध्यान देने योग्य है कि sizeof
किसी सरणी मान के साथ काम करते समय मदद नहीं करता है जो एक सूचक को क्षय हो गया है: भले ही यह एक सरणी की शुरुआत की ओर इशारा करता है, संकलक के लिए यह उस सरणी के एकल तत्व के लिए सूचक के समान है । एक पॉइंटर उस सरणी के बारे में और कुछ भी "याद" नहीं करता है जिसका उपयोग इसे आरंभ करने के लिए किया गया था।
int a[10];
int* p = a;
assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
char
में 32 बिट्स के साथ C था । सभी मानक कहते हैं कि 0 से 127 तक पूर्णांक मानों का प्रतिनिधित्व किया जा सकता है, और इसकी सीमा कम से कम या तो -127 से 127 (चार पर हस्ताक्षर किए गए) या 0 से 255 (चार्ट अहस्ताक्षरित) है।
आकार का "ट्रिक" सबसे अच्छा तरीका है जिसे मैं जानता हूं, एक छोटे से लेकिन (मेरे लिए, यह एक प्रमुख पालतू जानवर है) कोष्ठक के उपयोग में महत्वपूर्ण परिवर्तन।
जैसा कि विकिपीडिया प्रविष्टि स्पष्ट करती है, सी 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);
अब तुम सुरक्षित हो। ज़रूर, आप चर के नाम की नक़ल करते हैं, लेकिन यह एक तरह से टूटने की उच्च संभावना है जो संकलक का पता लगा सकता है, अगर आप इसे बदलते हैं।
sizeof(int)
की तुलना में कम निर्देश की आवश्यकता होती है sizeof(foo)
?
int x = 1+1;
बनाम के बारे में सोचो int x = (1+1);
। यहाँ, कोष्ठक विशुद्ध रूप से बिल्कुल सौंदर्यपूर्ण हैं।
sizeof
C ++ और C89 में हमेशा स्थिर रहेंगे। C99 की चर लंबाई सरणियों के साथ, इसका मूल्यांकन रनटाइम पर किया जा सकता है।
sizeof
एक ऑपरेटर हो सकता है लेकिन इसे लिनुस टॉर्वाल्ड्स के अनुसार एक फ़ंक्शन के रूप में माना जाना चाहिए। मैं सहमत हूँ। यहां उनके तर्कसंगत पढ़ें: lkml.org/lkml/2012/7/11/103
int size = (&arr)[1] - arr;
की जाँच करें इस लिंक विवरण के लिए
ptrdiff_t
। (आमतौर पर 64-बिट सिस्टम पर, यह तुलना में एक बड़ा प्रकार होगा int
)। यहां तक कि अगर आप बदलना int
करने के लिए ptrdiff_t
इस कोड में, यह अभी भी एक बग अगर है arr
पता स्थान के आधे से अधिक लेता है।
/3G
विकल्प के साथ @Aidiakapi आपके पास 3G / 1G उपयोगकर्ता / कर्नेल विभाजन है, जिससे आपको पता स्थान आकार का 75% तक सरणियाँ मिल सकती हैं।
foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];
वैश्विक चर के रूप में विचार करें । buf3[]
घोषणा विफल हो जाती (&buf1)[1] - buf1
है क्योंकि कोई स्थिर नहीं है।
आप sizeof ऑपरेटर का उपयोग कर सकते हैं, लेकिन यह फ़ंक्शन के लिए काम नहीं करेगा क्योंकि यह पॉइंटर का संदर्भ लेगा जो आप एक सरणी की लंबाई का पता लगाने के लिए निम्न कार्य कर सकते हैं:
len = sizeof(arr)/sizeof(arr[0])
कोड मूल रूप से यहां पाया गया: सी प्रोग्राम एक सरणी में तत्वों की संख्या को खोजने के लिए
यदि आप सरणी का डेटा प्रकार जानते हैं, तो आप कुछ का उपयोग कर सकते हैं:
int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};
int noofele = sizeof(arr)/sizeof(int);
या यदि आप डेटा प्रकार के सरणी को नहीं जानते हैं, तो आप कुछ का उपयोग कर सकते हैं:
noofele = sizeof(arr)/sizeof(arr[0]);
नोट: यह चीज़ केवल तभी काम करती है जब सरणी रन टाइम (जैसे मॉलॉक) में परिभाषित नहीं होती है और सरणी किसी फ़ंक्शन में पारित नहीं होती है। दोनों मामलों में, arr
(सरणी नाम) एक सूचक है।
int noofele = sizeof(arr)/sizeof(int);
कोडिंग की तुलना में केवल आधा रास्ता बेहतर है int noofele = 9;
। sizeof(arr)
लचीलेपन का उपयोग करके सरणी का आकार बदलना चाहिए। फिर भी sizeof(int)
एक arr[]
बदलाव की आवश्यकता है एक अद्यतन चाहिए । sizeof(arr)/sizeof(arr[0])
यदि प्रकार अच्छी तरह से जाना जाता है, तब भी उपयोग करने के लिए बेहतर है । अस्पष्ट क्यों बनाम के int
लिए उपयोग करके , प्रकार द्वारा लौटा दिया गया । noofele
size_t
sizeof()
मैक्रो 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
था कि एक पॉइंटर प्रकार के रूप में समाप्त हो जाएगा और पूरे मैक्रो को अमान्य कर देगा (जैसे कि यदि आपने पॉइंटर पैरामीटर के साथ फ़ंक्शन में मैक्रो का उपयोग करने का प्रयास किया है)।
दिन के अंत में, इस विशेष उदाहरण में, गलती वास्तव में मायने नहीं रखती है (इसलिए मैं हर किसी के समय को बर्बाद कर रहा हूं; हुज़ाह!), क्योंकि आपके पास एक प्रकार के 'सरणी' के साथ अभिव्यक्ति नहीं है। लेकिन वास्तव में प्रीप्रोसेसर मूल्यांकन के बारे में बिंदु मुझे लगता है कि एक महत्वपूर्ण है।
(sizeof (x) / sizeof (*x))
?
के लिए बहुआयामी सरणियों यह एक बालक अधिक जटिल है। अक्सर लोग स्पष्ट स्थूल स्थिरांक को परिभाषित करते हैं, अर्थात
#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])
आदि, एड इन्फिनिटम।
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)
मेरे समर्पित उत्तर में बताए अनुसार कर सकते हैं ।
सी में एक सरणी का आकार:
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
size_t size_of_element
अभी तक int
के साथ int n = sizeof (a) / sizeof (a[0]);
और नहींsize_t n = sizeof (a) / sizeof (a[0]);
char a[INT_MAX + 1u];
, int n
जैसा int n = sizeof (a) / sizeof (a[0]);
कि अपर्याप्त है (यह यूबी है)। उपयोग करने से size_t n = sizeof (a) / sizeof (a[0]);
यह समस्या उत्पन्न नहीं होती है।
मैं 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);
}
-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()
पूरी तरह से सुरक्षित है, और इसलिए इसके सभी डेरिवेटिव सुरक्षित होंगे।
__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))
sizeof(arr)
) का समाधान दिखाता है जो कहीं और नहीं दिखाया गया है ARRAY_BYTES(arr)
:।
sizeof
, लेकिन इसके बजाय इस निर्माण का उपयोग करें; अगर आपको हर बार इन निर्माणों को लिखने का मन करता है, तो आप संभवतः एक गलती करेंगे (यदि आप कॉपी पेस्ट करते हैं, तो बहुत सामान्य है और यदि आप उन्हें हर बार लिखते हैं क्योंकि उनके पास बहुत सारे कोष्ठक हैं) ...
sizeof
स्पष्ट रूप से असुरक्षित है (उत्तर में कारण हैं), और मैक्रोज़ का उपयोग नहीं कर रहे हैं, लेकिन मेरे द्वारा प्रदान किए गए निर्माणों का उपयोग करते हुए, हर बार, और भी असुरक्षित है, इसलिए जाने का एकमात्र तरीका मैक्रोज़ है।
"आपने खुद को पैर में गोली मारने का एक सूक्ष्म तरीका पेश किया है"
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();
enum
घोषणा का उपयोग करना है ।
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
यदि आप वास्तव में ऐसा करना चाहते हैं तो अपने एरे के आस-पास से गुजरने का सुझाव दें। मैं आपको एक व्यूअर को स्टोर करने के लिए एक संरचना को लागू करने का सुझाव देता हूं, जिसमें आप एक सरणी चाहते हैं और एक पूर्णांक सरणी के आकार का प्रतिनिधित्व करते हैं। फिर आप इसे अपने कार्यों के लिए पास कर सकते हैं। बस उस पॉइंटर को ऐरे वेरिएबल वैल्यू (पॉइंटर टू फर्स्ट एलिमेंट) असाइन करें। तब आप 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;
}
strcpy(d.name, name);
अतिप्रवाह की हैंडलिंग के साथ नहीं करता है कि upvote कोड नहीं कर सकता ।
इस जानकारी को सहेजने का सबसे अच्छा तरीका है, उदाहरण के लिए, संरचना में:
typedef struct {
int *array;
int elements;
} list_s;
सभी आवश्यक कार्यों को लागू करें जैसे कि बनाना, नष्ट करना, समानता की जांच करना, और बाकी सब कुछ जो आपको चाहिए। पैरामीटर के रूप में पास करना आसान है।
int elements
बनाम का कोई कारण size_t elements
?
फ़ंक्शन sizeof
बाइट्स की संख्या देता है जो मेमोरी में आपके एरे द्वारा उपयोग की जाती है। यदि आप अपने सरणी में तत्वों की संख्या की गणना करना चाहते हैं, तो आपको उस संख्या को sizeof
चर के प्रकार के साथ विभाजित करना चाहिए । मान लीजिए int array[10];
, यदि आपके कंप्यूटर में चर प्रकार पूर्णांक 32 बिट (या 4 बाइट्स) है, तो आपके सरणी का आकार प्राप्त करने के लिए, आपको निम्न कार्य करना चाहिए:
int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
आप &
ऑपरेटर का उपयोग कर सकते हैं । यहाँ स्रोत कोड है:
#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
ptrdiff_t
। sizeof()
में परिणाम 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]);
पर्याप्त है।
(char *)(&a+1)-(char *)a
एक स्थिर नहीं है और एक निश्चित आकार के साथ, रन-टाइम पर गणना की जा सकती है a[10]
। sizeof(a)/sizeof(a[0])
इस मामले में लगातार संकलन समय पर किया जाता है।
अधिक सुरुचिपूर्ण समाधान होगा
size_t size = sizeof(a) / sizeof(*a);
पहले से उपलब्ध कराए गए उत्तरों के अलावा, मैं एक विशेष मामले का उपयोग करके बताना चाहता हूं
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 / 1
a
char
unsigned char
signed char
इस मामले में, आप बस संक्षिप्त और कर सकते हैं:
sizeof(a)
उदाहरण के लिए:
char a[10];
size_t length = sizeof(a);
यदि आप एक प्रमाण चाहते हैं, तो यहां गॉडबोल्ट की एक कड़ी है ।
फिर भी, यदि विभाजन महत्वपूर्ण रूप से बदलता है, तो डिवीजन सुरक्षा बनाए रखता है (हालांकि ये मामले दुर्लभ हैं)।
नोट: यह एक आपको अपरिभाषित व्यवहार दे सकता है जैसा कि एमएम ने टिप्पणी में बताया है।
int a[10];
int size = (*(&a+1)-a) ;
*
ऑपरेटर एक पास्ट अंत सूचक के लिए लागू नहीं किया जा सकता है
*(&a+1) - a;
से अलग है (&a)[1] - a;
, दोनों नहीं *(&a+1)
और (&a)[1]
अंत में 1 अतीत के रूप में गिना जाता है?
x[y]
को परिभाषित किया गया है*(x + (y))