To sizeof ’(किसी पॉइंटर की ओर इशारा करते हुए सूचक) को कैसे खोजें?


309

सबसे पहले, यहाँ कुछ कोड है:

int main() 
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

क्या उस सरणी के आकार का पता लगाने का एक तरीका है जो ptrइंगित कर रहा है (केवल इसके आकार देने के बजाय, जो 32-बिट सिस्टम पर चार बाइट्स है)?


84
मैंने हमेशा साइज़ोफ़ के साथ पैरेंस का उपयोग किया है - यकीन है कि यह फ़ंक्शन कॉल की तरह दिखता है, लेकिन मुझे लगता है कि यह स्पष्ट है।
पॉल टॉम्बलिन

20
क्यों नहीं? क्या आपके पास अति सुंदर कोष्ठकों के खिलाफ कुछ है? मुझे लगता है कि यह उनके साथ, खुद को थोड़ा और आसानी से पढ़ता है।
डेविड थॉर्नले

6
@Paul: अच्छी तरह से .. उस कॉल के बाएं हाथ को मान लेना int का एक सूचक है, मैं इसे int * ptr = malloc (4 * sizeof * ptr) के रूप में लिखूंगा; जो मेरे लिए बहुत स्पष्ट है। गणित पढ़ने की तरह, और पढ़ने के लिए शाब्दिक अड़चन को सामने लाना कमतर है।
खोलना

4
जब आप ints का एक सरणी मतलब @unwind - संकेत की एक सरणी आवंटित नहीं करते!
पॉल टॉम्बलिन

6
यहाँ कोई "सूचक इंगित करने के लिए कोई सरणी" नहीं है। बस एक सूचक एक इंट की ओर इशारा करता है।
newacct

जवाबों:


269

नहीं, तुम नहीं कर सकते। संकलक को पता नहीं है कि सूचक किस ओर इशारा कर रहा है। चालें हैं, जैसे कि एक ज्ञात आउट-ऑफ-बैंड मान के साथ सरणी को समाप्त करना और फिर उस मूल्य तक आकार की गिनती करना, लेकिन यह उपयोग नहीं कर रहा है sizeof()

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


12
मुझे इतनी देर से एक टिप्पणी पोस्ट करने के लिए खेद है, लेकिन अगर संकलक को पता नहीं है कि सूचक क्या इंगित कर रहा है, तो यह कैसे पता चलेगा कि स्मृति को कितना खाली करना है? मुझे पता है कि इस जानकारी को मुफ्त में उपयोग किए जाने वाले कार्यों के लिए आंतरिक रूप से संग्रहीत किया जाता है। तो मेरा सवाल यह है कि 'कंपाइलर ऐसा क्यों कर सकता है?
viki.omega9

11
@ viki.omega9, क्योंकि फ्री रनटाइम पर साइज का पता चलता है। संकलक आकार का पता नहीं लगा सकता क्योंकि आप रनटाइम कारकों (कमांड लाइन तर्क, एक फ़ाइल की सामग्री, चंद्रमा का चरण, आदि) के आधार पर सरणी को एक अलग आकार दे सकते हैं।
पॉल टॉम्बलिन

15
त्वरित पालन करें, ऐसा कोई फ़ंक्शन क्यों नहीं है जो आकार को मुफ्त में वापस कर सकता है?
viki.omega9

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

9
@ viki.omega9: ध्यान रखने योग्य एक और बात यह है कि आपके द्वारा मांगे गए आकार में मॉकॉक / फ्री सिस्टम द्वारा दर्ज किया गया आकार नहीं हो सकता है। आप मॉलॉक 9 बाइट्स और 16 प्राप्त करें। मलोक 3K बाइट्स और 4K प्राप्त करें। या ऐसी ही स्थिति।
ज़ान लिंक्स

85

जवाब न है।"

सी प्रोग्रामर क्या करते हैं, वह सरणी के आकार को कहीं स्टोर करता है। यह एक संरचना का हिस्सा हो सकता है, या प्रोग्रामर malloc()सरणी की शुरुआत से पहले एक लंबाई मान को स्टोर करने के लिए अनुरोध की तुलना में थोड़ा और अधिक मेमोरी को धोखा दे सकता है ।


3
पास्कल के तार कैसे लागू होते हैं
dsm

6
और जाहिरा तौर पर पास्कल स्ट्रिंग्स क्यों एक्सेल इतनी तेजी से चलता है!
एडम नायलर

8
@ अदम: यह तेज़ है। मैं इसे मेरे कार्यान्वयन के तार की सूची में उपयोग करता हूं। यह सुपर-लीनियर टू लीनियर सर्च है क्योंकि यह है: लोड साइज, प्रीफैच पॉस + साइज, साइज को सर्च साइज से तुलना करें, यदि बराबर स्ट्रैन्कैंप, नेक्स्ट स्ट्रिंग में जाएं, रिपीट करें। यह बाइनरी सर्च से लगभग 500 स्ट्रिंग्स तक तेज है।
ज़ैन लिंक्स

47

गतिशील सरणियों के लिए ( मॉलोक या सी ++ नया ) के लिए आपको सरणी के आकार को दूसरों द्वारा बताए गए स्टोर करने की आवश्यकता है या शायद एक सरणी प्रबंधक संरचना का निर्माण करें जो ऐड, रिमूव, काउंट आदि को हैंडल करता है। दुर्भाग्य से सी लगभग ऐसा नहीं करता है। C ++ चूंकि आपको मूल रूप से प्रत्येक अलग-अलग सरणी प्रकार के लिए इसका निर्माण करना है, जो आप संग्रहीत कर रहे हैं जो कि बोझिल है यदि आपके पास कई प्रकार के सरणियाँ हैं जिन्हें आपको प्रबंधित करने की आवश्यकता है।

स्थिर सरणियों के लिए, जैसे कि आपके उदाहरण में, आकार प्राप्त करने के लिए उपयोग किया जाने वाला एक सामान्य मैक्रो है, लेकिन यह है अनुशंसित नहीं है क्योंकि यह जांच नहीं करता है कि क्या पैरामीटर वास्तव में एक स्थिर सरणी है। मैक्रो का उपयोग वास्तविक कोड में किया जाता है, उदाहरण के लिए लिनक्स कर्नेल हेडर में, हालांकि यह नीचे दिए गए से थोड़ा अलग हो सकता है:

#if !defined(ARRAY_SIZE)
    #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
#endif

int main()
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", ARRAY_SIZE(days));
    printf("%u\n", sizeof(ptr));
    return 0;
}

आप इस तरह से मैक्रोज़ से सावधान रहने के कारणों के लिए Google कर सकते हैं। सावधान रहे।

यदि संभव हो तो, C ++ stdlib जैसे वेक्टर, जो बहुत सुरक्षित और उपयोग करने में आसान है।


11
ARRAY_SIZE एक सामान्य प्रतिमान है जिसका प्रयोग व्यावहारिक प्रोग्रामर हर जगह करते हैं।
संजय आर

5
हाँ यह एक सामान्य प्रतिमान है। आपको अभी भी इसे सावधानी से उपयोग करने की आवश्यकता है, हालांकि इसे भूलना और डायनेमिक सरणी पर इसका उपयोग करना आसान है।
रयान

2
हां, अच्छी बात है, लेकिन जो सवाल पूछा जा रहा है, वह सूचक एक के बारे में था, न कि स्थिर सरणी एक के बारे में।
पॉल टॉम्बलिन

2
यह ARRAY_SIZEमैक्रो हमेशा काम करता है यदि इसका तर्क एक सरणी है (अर्थात सरणी प्रकार की अभिव्यक्ति)। आपके तथाकथित "गतिशील सरणी" के लिए, आपको कभी भी वास्तविक "सरणी" (सरणी प्रकार की अभिव्यक्ति) नहीं मिलती है। (बेशक, आप नहीं कर सकते, क्योंकि सरणी प्रकारों का संकलन-समय पर उनका आकार शामिल है।) आपको बस पहले तत्व के लिए एक संकेतक मिलता है। आपकी आपत्ति "जाँच नहीं करती है कि क्या पैरामीटर वास्तव में एक स्थिर सरणी है" वास्तव में मान्य नहीं है, क्योंकि वे भिन्न हैं क्योंकि एक एक सरणी है और दूसरा नहीं है।
नवागंतुक

2
एक टेम्पलेट फ़ंक्शन है जो चारों ओर तैर रहा है जो समान कार्य करता है लेकिन संकेत के उपयोग को रोक देगा।
नेटली एडम्स

18

साइलोफ () का उपयोग किए बिना, सी ++ टेम्पलेट्स के साथ एक स्वच्छ समाधान है । निम्नलिखित getSize () फ़ंक्शन किसी भी स्थिर सरणी का आकार लौटाता है:

#include <cstddef>

template<typename T, size_t SIZE>
size_t getSize(T (&)[SIZE]) {
    return SIZE;
}

यहाँ एक foo_t संरचना के साथ एक उदाहरण दिया गया है :

#include <cstddef>

template<typename T, size_t SIZE>
size_t getSize(T (&)[SIZE]) {
    return SIZE;
}

struct foo_t {
    int ball;
};

int main()
{
    foo_t foos3[] = {{1},{2},{3}};
    foo_t foos5[] = {{1},{2},{3},{4},{5}};
    printf("%u\n", getSize(foos3));
    printf("%u\n", getSize(foos5));

    return 0;
}

आउटपुट:

3
5

मैंने कभी नोटेशन नहीं देखा T (&)[SIZE]। क्या आप इसका मतलब बता सकते हैं? इसके अलावा आप इस संदर्भ में अड़चन का उल्लेख कर सकते हैं।
WorldSEnder

2
यह अच्छा है अगर आप c ++ का उपयोग करते हैं और आपके पास वास्तव में एक सरणी प्रकार का एक चर है। न तो उनमें से प्रश्न में मामला है: भाषा सी है, और ओपी जिस चीज से सरणी का आकार प्राप्त करना चाहता है वह एक साधारण सूचक है।
ओगुक

क्या यह कोड प्रत्येक भिन्न आकार / प्रकार के संयोजन के लिए एक ही कोड को पुन: कोड करके ब्लोट का नेतृत्व करेगा या क्या यह संकलक द्वारा अस्तित्व से बाहर अनुकूलित है?
user2796283

@WorldSEnder: यह सरणी प्रकार के संदर्भ के लिए C ++ सिंटैक्स है (कोई चर नाम नहीं, बस एक आकार और तत्व-प्रकार के साथ)।
पीटर कॉर्डेस

@ user2796283: यह फ़ंक्शन पूरी तरह से संकलन समय पर दूर अनुकूलित है; किसी जादू की जरूरत नहीं है; यह एक एकल परिभाषा के लिए कुछ भी नहीं मिला रहा है, यह बस इसे संकलन-स्थिर समय तक दूर कर रहा है। (लेकिन डिबग बिल्ड में, हां, आपके पास अलग-अलग कार्यों का एक गुच्छा होगा जो विभिन्न स्थिरांक लौटाता है। लिंकर मैजिक उन लोगों को मर्ज कर सकता है जो एक ही निरंतर का उपयोग करते हैं। कॉलर SIZEएक arg के रूप में पास नहीं होता है , यह एक टेम्पलेट परम है जिसमें है पहले से ही फ़ंक्शन परिभाषा से जाना जाता है।)
पीटर कॉर्ड्स

5

इस विशिष्ट उदाहरण के लिए, हाँ, वहाँ है, यदि आप टाइप करें (तो नीचे देखें)। बेशक, यदि आप इसे इस तरह से करते हैं, तो आप SIZEOF_DAYS का उपयोग करने के लिए बंद हैं, क्योंकि आपको पता है कि सूचक क्या इंगित कर रहा है।

यदि आपके पास (शून्य *) पॉइंटर है, जैसा कि मॉलॉक () या उसके द्वारा लौटाया जाता है, तो, नहीं, नहीं, यह निर्धारित करने का कोई तरीका नहीं है कि पॉइंटर किस डेटा संरचना की ओर इशारा कर रहा है और इस प्रकार, इसके आकार को निर्धारित करने का कोई तरीका नहीं है।

#include <stdio.h>

#define NUM_DAYS 5
typedef int days_t[ NUM_DAYS ];
#define SIZEOF_DAYS ( sizeof( days_t ) )

int main() {
    days_t  days;
    days_t *ptr = &days; 

    printf( "SIZEOF_DAYS:  %u\n", SIZEOF_DAYS  );
    printf( "sizeof(days): %u\n", sizeof(days) );
    printf( "sizeof(*ptr): %u\n", sizeof(*ptr) );
    printf( "sizeof(ptr):  %u\n", sizeof(ptr)  );

    return 0;
} 

आउटपुट:

SIZEOF_DAYS:  20
sizeof(days): 20
sizeof(*ptr): 20
sizeof(ptr):  4

5

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

यहाँ एक सुझाव दिया गया है जो इस प्रकार प्रदान किया गया है कि अब तक, यह काम करेगा: इसके बजाय सरणी के लिए एक पॉइंटर पास करें। यह सुझाव C ++ शैली के सुझावों के समान है, सिवाय इसके कि C टेम्पलेट या संदर्भों का समर्थन नहीं करता है:

#define ARRAY_SZ 10

void foo (int (*arr)[ARRAY_SZ]) {
    printf("%u\n", (unsigned)sizeof(*arr)/sizeof(**arr));
}

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

int x[20];
int y[10];
foo(&x); /* error */
foo(&y); /* ok */

यदि फ़ंक्शन किसी भी आकार के सरणी पर संचालित करने में सक्षम माना जाता है, तो आपको अतिरिक्त जानकारी के रूप में फ़ंक्शन को आकार प्रदान करना होगा।


1
+1 के लिए "आपको यह जानकारी अकेले सरणी के क्षयकारी सूचक मान से नहीं मिल सकती है" और वर्कअराउंड प्रदान करता है।
मैक्स

4

कोई जादू समाधान नहीं है। C एक चिंतनशील भाषा नहीं है। ऑब्जेक्ट स्वचालित रूप से नहीं जानते कि वे क्या हैं।

लेकिन आपके पास कई विकल्प हैं:

  1. जाहिर है, एक पैरामीटर जोड़ें
  2. कॉल को मैक्रो में लपेटें और स्वचालित रूप से एक पैरामीटर जोड़ें
  3. अधिक जटिल वस्तु का उपयोग करें। ऐसी संरचना को परिभाषित करें जिसमें डायनेमिक एरे हो और एरे का आकार भी हो। फिर, संरचना के पते को पास करें।

वस्तुओं को पता है कि वे क्या हैं। लेकिन अगर आप किसी सब -जेक्ट की ओर इशारा करते हैं, तो संपूर्ण ऑब्जेक्ट या किसी बड़े सब -जेक्ट के बारे में जानकारी प्राप्त करने का कोई तरीका नहीं है
MM 14

2

इस समस्या का मेरा समाधान सरणी के बारे में मेटा-जानकारी के रूप में सरणी की लंबाई को एक संरचना एरे में सहेजना है।

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

struct Array
{
    int length;

    double *array;
};

typedef struct Array Array;

Array* NewArray(int length)
{
    /* Allocate the memory for the struct Array */
    Array *newArray = (Array*) malloc(sizeof(Array));

    /* Insert only non-negative length's*/
    newArray->length = (length > 0) ? length : 0;

    newArray->array = (double*) malloc(length*sizeof(double));

    return newArray;
}

void SetArray(Array *structure,int length,double* array)
{
    structure->length = length;
    structure->array = array;
}

void PrintArray(Array *structure)
{       
    if(structure->length > 0)
    {
        int i;
        printf("length: %d\n", structure->length);
        for (i = 0; i < structure->length; i++)
            printf("%g\n", structure->array[i]);
    }
    else
        printf("Empty Array. Length 0\n");
}

int main()
{
    int i;
    Array *negativeTest, *days = NewArray(5);

    double moreDays[] = {1,2,3,4,5,6,7,8,9,10};

    for (i = 0; i < days->length; i++)
        days->array[i] = i+1;

    PrintArray(days);

    SetArray(days,10,moreDays);

    PrintArray(days);

    negativeTest = NewArray(-5);

    PrintArray(negativeTest);

    return 0;
}

लेकिन आपको उस सरणी की सही लंबाई निर्धारित करने की परवाह करनी होगी जिसे आप स्टोर करना चाहते हैं, क्योंकि इस लंबाई को जांचने का कोई तरीका नहीं है, जैसे कि हमारे दोस्तों ने बड़े पैमाने पर समझाया।


2

आप ऐसा कुछ कर सकते हैं:

int days[] = { /*length:*/5, /*values:*/ 1,2,3,4,5 };
int *ptr = days + 1;
printf("array length: %u\n", ptr[-1]);
return 0;

1

नहीं, आप उपयोग नहीं कर सकते sizeof(ptr)सरणी ptrका आकार इंगित करने के लिए इंगित कर रहा है।

यद्यपि आप अतिरिक्त मेमोरी आवंटित करना चाहते हैं (सरणी के आकार से अधिक) यदि आप अतिरिक्त स्थान में लंबाई संग्रहीत करना चाहते हैं तो यह सहायक होगा।


1
int main() 
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

दिनों का आकार [] 20 है जो तत्वों का नहीं है * इसका आकार डेटा प्रकार है। जबकि पॉइंटर का साइज़ 4 है कोई बात नहीं यह किस ओर इशारा कर रहा है। क्योंकि एक पॉइंटर दूसरे तत्व की ओर इशारा करता है, जिससे उसका पता चलता है।


1
sizeof (ptr) पॉइंटर का आकार है और sizeof (* ptr) पॉइंटर का आकार है जिससे
अमिताभ

0
 #define array_size 10

 struct {
     int16 size;
     int16 array[array_size];
     int16 property1[(array_size/16)+1]
     int16 property2[(array_size/16)+1]
 } array1 = {array_size, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

 #undef array_size

array_size आकार चर में पास हो रहा है :

#define array_size 30

struct {
    int16 size;
    int16 array[array_size];
    int16 property1[(array_size/16)+1]
    int16 property2[(array_size/16)+1]
} array2 = {array_size};

#undef array_size

उपयोग है:

void main() {

    int16 size = array1.size;
    for (int i=0; i!=size; i++) {

        array1.array[i] *= 2;
    }
}

0

तार '\0'में अंत में एक पात्र होता है इसलिए स्ट्रिंग की लंबाई जैसे कार्यों का उपयोग करके प्राप्त की जा सकती है strlen। उदाहरण के लिए, एक पूर्णांक सरणी के साथ समस्या यह है कि आप किसी भी मूल्य को अंतिम मूल्य के रूप में उपयोग नहीं कर सकते हैं, इसलिए एक संभावित समाधान सरणी को संबोधित करने और NULLसूचक के अंत मूल्य के रूप में उपयोग करना है ।

#include <stdio.h>
/* the following function will produce the warning:
 * ‘sizeof’ on array function parameter ‘a’ will
 * return size of ‘int *’ [-Wsizeof-array-argument]
 */
void foo( int a[] )
{
    printf( "%lu\n", sizeof a );
}
/* so we have to implement something else one possible
 * idea is to use the NULL pointer as a control value
 * the same way '\0' is used in strings but this way
 * the pointer passed to a function should address pointers
 * so the actual implementation of an array type will
 * be a pointer to pointer
 */
typedef char * type_t; /* line 18 */
typedef type_t ** array_t;
int main( void )
{
    array_t initialize( int, ... );
    /* initialize an array with four values "foo", "bar", "baz", "foobar"
     * if one wants to use integers rather than strings than in the typedef
     * declaration at line 18 the char * type should be changed with int
     * and in the format used for printing the array values 
     * at line 45 and 51 "%s" should be changed with "%i"
     */
    array_t array = initialize( 4, "foo", "bar", "baz", "foobar" );

    int size( array_t );
    /* print array size */
    printf( "size %i:\n", size( array ));

    void aprint( char *, array_t );
    /* print array values */
    aprint( "%s\n", array ); /* line 45 */

    type_t getval( array_t, int );
    /* print an indexed value */
    int i = 2;
    type_t val = getval( array, i );
    printf( "%i: %s\n", i, val ); /* line 51 */

    void delete( array_t );
    /* free some space */
    delete( array );

    return 0;
}
/* the output of the program should be:
 * size 4:
 * foo
 * bar
 * baz
 * foobar
 * 2: baz
 */
#include <stdarg.h>
#include <stdlib.h>
array_t initialize( int n, ... )
{
    /* here we store the array values */
    type_t *v = (type_t *) malloc( sizeof( type_t ) * n );
    va_list ap;
    va_start( ap, n );
    int j;
    for ( j = 0; j < n; j++ )
        v[j] = va_arg( ap, type_t );
    va_end( ap );
    /* the actual array will hold the addresses of those
     * values plus a NULL pointer
     */
    array_t a = (array_t) malloc( sizeof( type_t *) * ( n + 1 ));
    a[n] = NULL;
    for ( j = 0; j < n; j++ )
        a[j] = v + j;
    return a;
}
int size( array_t a )
{
    int n = 0;
    while ( *a++ != NULL )
        n++;
    return n;
}
void aprint( char *fmt, array_t a )
{
    while ( *a != NULL )
        printf( fmt, **a++ );   
}
type_t getval( array_t a, int i )
{
    return *a[i];
}
void delete( array_t a )
{
    free( *a );
    free( a );
}

आपका कोड टिप्पणियों से भरा है, लेकिन मुझे लगता है कि अगर आपने सामान्य पाठ के रूप में कोड के बाहर यह कैसे काम करता है, तो कुछ सामान्य विवरण जोड़ दिए तो यह सब कुछ आसान कर देगा। क्या आप कृपया अपना प्रश्न संपादित कर सकते हैं और कर सकते हैं? धन्यवाद!
फैबियो का कहना है कि मोनिका

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