मैं सी में स्ट्रिंग्स की एक सरणी कैसे बनाऊं?


263

मैं सी में स्ट्रिंग्स की एक सरणी बनाने की कोशिश कर रहा हूं। अगर मैं इस कोड का उपयोग करता हूं:

char (*a[2])[14];
a[0]="blah";
a[1]="hmm";

जीसीसी मुझे "चेतावनी: असंगत पॉइंटर प्रकार से असाइनमेंट" देता है। ऐसा करने का सही तरीका क्या है?

संपादित करें: मैं उत्सुक हूं कि यह संकलक चेतावनी क्यों दे सकता है यदि मैं करता हूं printf(a[1]);, तो यह "hmm" को सही ढंग से प्रिंट करता है।

c  arrays  string 

12
केवल रिकॉर्ड के लिए, char (*a[2])[14]दो बिंदुओं की एक सरणी 14 वर्णों की एक सरणी है।
अवकर 19

4
मुझे लगा कि यह चौदह पॉइंटर्स है, दो चर xD
फोरट्रान

74
सबसे उपयोगी सलाह जो मैंने कभी सी प्रकारों के निस्तारण के लिए पढ़ी: "नाम पर शुरू, सही पढ़ने के लिए जब आप कर सकते हैं, तो बाएं जब आपको चाहिए": char (*a[2])[14]- शुरू करें a, दाएं चलें: "दो की सरणी", बाएं जाएं: "पॉइंटर टू"। ब्रैकेट पूरा इतना सही पढ़ें: "फॉरेस्ट ऑफ़ फॉरेन्थ", लेफ्ट को पढ़ें: "चार" ... इसे एक साथ रखें और हमारे पास "फॉरेस्ट चार्ज़ के सरणियों के लिए दो पॉइंटर्स की सरणी है"
मार्क के कोवान

4
@dotancohen: यह टिप आखिरकार मुझे संकेत देने के char *strबजाय लिखने के लिए आश्वस्त करती है char* str। डेल्फी / पास्कल पृष्ठभूमि से आते हुए, मैं बाद के रास्ते में बहुत आदी हो गया था जब तक कि मैं अधिक जटिल प्रकारों में नहीं आया था। पूर्व तरीका अभी भी मुझे बदसूरत लगता है, लेकिन टाइप नोटेशन को अधिक सुसंगत (IMO) बनाता है।
मार्क के कोवन

@MarkKowan, अद्भुत! धन्यवाद! :)
डॉ। एसेन

जवाबों:


232

यदि आप स्ट्रिंग्स को बदलना नहीं चाहते हैं, तो आप बस कर सकते हैं

const char *a[2];
a[0] = "blah";
a[1] = "hmm";

जब आप इसे इस तरह करते हैं तो आप दो पॉइंटर्स की एक सरणी आवंटित करेंगे const char। ये संकेत तब स्टैटिक स्ट्रिंग्स के पते पर सेट हो जाएंगे "blah"और "hmm"

यदि आप वास्तविक स्ट्रिंग सामग्री को बदलने में सक्षम होना चाहते हैं, तो आपको कुछ ऐसा करना होगा

char a[2][14];
strcpy(a[0], "blah");
strcpy(a[1], "hmm");

यह charप्रत्येक 14 एस के दो लगातार सरणियों को आवंटित करेगा, जिसके बाद स्थैतिक तारों की सामग्री को उनमें कॉपी किया जाएगा।


185

C. में स्ट्रिंग्स की एक सरणी बनाने के कई तरीके हैं। यदि सभी स्ट्रिंग्स एक ही लंबाई (या कम से कम एक ही अधिकतम लंबाई) होने जा रहे हैं, तो आप बस 2-डी सरणी की घोषणा करते हैं और आवश्यकतानुसार असाइन करते हैं:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1];
...
strcpy(strs[0], aString); // where aString is either an array or pointer to char
strcpy(strs[1], "foo");

आप इनिशियलाइज़र की सूची भी जोड़ सकते हैं:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1] = {"foo", "bar", "bletch", ...};

यह मानता है कि इनिशियलाइज़र में स्ट्रिंग्स का आकार और संख्या आपके सरणी आयामों के साथ मेल खाती है। इस स्थिति में, प्रत्येक स्ट्रिंग शाब्दिक की सामग्री (जो कि स्वयं एक शून्य-समाप्त सारणी है) को strs के लिए आवंटित मेमोरी में कॉपी किया जाता है। इस दृष्टिकोण के साथ समस्या आंतरिक विखंडन की संभावना है; यदि आपके पास 99 तार हैं जो 5 वर्ण या उससे कम हैं, लेकिन 1 तार जो 20 वर्ण लंबा है, तो 99 तार कम से कम 15 अप्रयुक्त वर्ण रखने वाले हैं; यह अंतरिक्ष की बर्बादी है।

2-डी सरणी का उपयोग करने के बजाय, आप 1-डी सरणी के संकेत को चार में स्टोर कर सकते हैं:

char *strs[NUMBER_OF_STRINGS];

ध्यान दें कि इस स्थिति में, आपने केवल स्ट्रिंगर्स को पॉइंटर्स रखने के लिए मेमोरी आवंटित की है; स्ट्रिंग्स के लिए मेमोरी को कहीं और आवंटित किया जाना चाहिए (या तो स्थिर सरणियों के रूप में या उपयोग करके malloc()या calloc())। आप पहले के उदाहरण की तरह इनिशियलाइज़र सूची का उपयोग कर सकते हैं:

char *strs[NUMBER_OF_STRINGS] = {"foo", "bar", "bletch", ...};

स्ट्रिंग स्थिरांक की सामग्री की प्रतिलिपि बनाने के बजाय, आप बस उन्हें संकेत भेज रहे हैं। ध्यान दें कि स्ट्रिंग स्थिरांक लेखन योग्य नहीं हो सकते हैं; आप पॉइंटर को पुन: असाइन कर सकते हैं, जैसे:

strs[i] = "bar";
strs[i] = "foo"; 

लेकिन आप स्ट्रिंग की सामग्री को बदलने में सक्षम नहीं हो सकते हैं; अर्थात,

strs[i] = "bar";
strcpy(strs[i], "foo");

अनुमति नहीं दी जा सकती।

आप malloc()प्रत्येक स्ट्रिंग के लिए बफर को गतिशील रूप से आवंटित करने और उस बफर को कॉपी करने के लिए उपयोग कर सकते हैं :

strs[i] = malloc(strlen("foo") + 1);
strcpy(strs[i], "foo");

Btw,

char (*a[2])[14];

14-तत्व सरणियों के लिए संकेत के 2-तत्व सरणी के रूप में घोषित करता है।


3
@ स्लेटर: हाँ, अगर यह एक mallocकॉल का परिणाम है ।
जॉन बोडे

इस बहुत विस्तृत जवाब के लिए धन्यवाद। इससे वास्तव में मुझे मदद मिली।
कोकेड

1
हम केवल स्ट्रिंग सरणी पर एक 2D सरणी के रूप में घोषित स्ट्रॉपी का उपयोग क्यों कर सकते हैं। मानक असाइनमेंट विफल क्यों होता है?
एंड्रयू एस

4
@AndrewS: पूरा उत्तर एक टिप्पणी में फिट नहीं होगा, लेकिन मूल रूप से यह एक आर्टवर्क है कि C कैसे एरे एक्सप्रेशन का व्यवहार करता है; अधिकांश परिस्थितियों में, प्रकार की अभिव्यक्ति प्रकार की अभिव्यक्ति में T [N]बदल जाती है T *, और अभिव्यक्ति का मूल्य पहले तत्व का पता है। इसलिए यदि आपने लिखा है str = "foo", तो आप "foo"सरणी के पहले वर्ण का पता निर्दिष्ट करने का प्रयास करेंगे str, जो काम नहीं करता है। देख इस उत्तर अधिक जानकारी के लिए।
जॉन बोडे

@ जॉनबोड क्या आप कृपया छोटे ट्विस्ट जोड़ सकते हैं? char *strs[NUMBER_OF_STRINGS] = {0}; यह आरंभिक समस्याओं को रोकने में मदद करता strsहै NULL। बहुत सारे लोग इस पोस्ट को पढ़ते हैं जब Google सी में स्ट्रिंग की सरणी पर खोज करता है
coccude

94

एसीके! लगातार तार:

const char *strings[] = {"one","two","three"};

अगर मुझे ठीक से याद है।

ओह, और आप असाइनमेंट के लिए strcpy का उपयोग करना चाहते हैं , = ऑपरेटर नहीं। strcpy_s अधिक सुरक्षित है, लेकिन यह न तो C89 में है और न ही C99 मानकों में।

char arr[MAX_NUMBER_STRINGS][MAX_STRING_SIZE]; 
strcpy(arr[0], "blah");

अद्यतन: थॉमस कहते हैं strlcpyकि जाने का रास्ता है।


क्या वह C99 है? मुझे विश्वास नहीं है कि यह एएनएसआई सी में संभव है
नोल्डोरिन

6
यह C89 और C99 दोनों में संभव है। यह भी कोई फर्क नहीं पड़ता कि यह कास्ट के साथ है या इसके बिना, हालांकि पूर्व पसंद किया जाता है।
अवकर

1
खैर, कास्ट नया है, और आपको बाहरी सरणी (इस मामले में 3) के आकार को निर्दिष्ट करना पड़ता था, लेकिन अन्यथा यह पूरी तरह से स्वीकार्य है K & R C. मेरे पास एक पुरानी सी पुस्तक कॉपीराइट 1984 है जिसमें एक अनुभाग है जो दिखा रहा है कि कैसे यह करो। वे इसे "रैग्ड ऐरे" कहते हैं। बेशक यह कोई "ऑपरेटर" नहीं था, और strcpy_s मुझ पर एक नया है।
TED

6
strcpy_s एक Microsoft फ़ंक्शन है। शायद इसे टाला जाना चाहिए क्योंकि यह मानक सी में नहीं है
Cromulent

5
strcpy_s और अन्य "सुरक्षित कार्य" आईएसओ / आईईसी टीआर 24731 के रूप में मानकीकृत हैं (यह एक आईएसओ प्रकाशित मानक है और जैसे कि मुफ्त में ऑनलाइन उपलब्ध नहीं है; सबसे हाल का मसौदा खुला है-std.org/jtc1/sc22-wg14/www /docs/n1225.pdf )
पावेल

14

यहाँ आपके कुछ विकल्प हैं:

char a1[][14] = { "blah", "hmm" };
char* a2[] = { "blah", "hmm" };
char (*a3[])[] = { &"blah", &"hmm" };  // only since you brought up the syntax -

printf(a1[0]); // prints blah
printf(a2[0]); // prints blah
printf(*a3[0]); // prints blah

इसका लाभ a2यह है कि आप बाद में स्ट्रिंग शाब्दिक के साथ कर सकते हैं

a2[0] = "hmm";
a2[1] = "blah";

और a3आप निम्न कार्य कर सकते हैं:

a3[0] = &"hmm";
a3[1] = &"blah";

के लिए a1आप का उपयोग करना होगा strcpy()(बेहतर अभी तक strncpy()) यहाँ तक कि जब स्ट्रिंग शाब्दिक बताए। इसका कारण यह है a2, और a3पॉइंटर्स के सरणियाँ हैं और आप उनके तत्वों (यानी पॉइंटर्स) को किसी भी स्टोरेज की ओर ले जा सकते हैं, जबकि a1'एरे ऑफ़ चार्ज़' का एक सरणी है और इसलिए प्रत्येक एलीमेंट एक ऐसा सरणी है जो "स्वयं" स्टोरेज का मालिक है ( इसका मतलब है कि यह तब नष्ट हो जाता है जब यह दायरे से बाहर हो जाता है) - आप केवल इसके भंडारण में सामान कॉपी कर सकते हैं।

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

बाह - मुझे C ++ पहले से याद है;)

ps मुझे पता है अगर आप उदाहरण की जरूरत है।


मुझे एक Arduino प्रोजेक्ट के लिए स्ट्रिंग सरणियों की आवश्यकता थी। अंत में मैंने a2 शैली का उपयोग किया। मैंने शुरू में a1 शैली को अपने स्ट्रिंग सरणी को char a1 [] [2] = {"F3", "G3" ... आदि के रूप में परिभाषित किया। } जैसा कि 2-कैरेक्टर लंबे स्ट्रिंग्स को स्टोर करने का इरादा था। इसने अप्रत्याशित उत्पादन दिया क्योंकि मैं भूल गया था कि नल-टर्मिनेटर का अर्थ होगा कि प्रत्येक स्ट्रिंग में 2 वर्णों को संग्रहीत करने के लिए कम से कम 3 का आकार होना चाहिए। A2 शैली का उपयोग करते हुए, मुझे स्ट्रिंग की लंबाई निर्दिष्ट करने की आवश्यकता नहीं थी, और यह अलग-अलग स्ट्रिंग की लंबाई को समायोजित कर सकती है और इसलिए मैंने उस के साथ छड़ी करने का फैसला किया है :-)
जेरोमी एडोफो

char (* a3 []) [] = {& "blah", और "hmm"}; => g ++ Apple LLVM संस्करण 9.1.0 में काम नहीं करता है, लेकिन यह gcc में काम करता है
1234

12

या आप एक संरचना प्रकार की घोषणा कर सकते हैं, जिसमें एक वर्ण अर्री (1 स्ट्रिंग) होता है, वे संरचना का एक सरणी बनाते हैं और इस प्रकार एक बहु-तत्व सरणी बनाते हैं

typedef struct name
{
   char name[100]; // 100 character array
}name;

main()
{
   name yourString[10]; // 10 strings
   printf("Enter something\n:);
   scanf("%s",yourString[0].name);
   scanf("%s",yourString[1].name);
   // maybe put a for loop and a few print ststements to simplify code
   // this is just for example 
 }

किसी भी अन्य विधि पर इसके फायदे में से एक यह है कि यह आपको बिना उपयोग किए सीधे स्ट्रिंग में स्कैन करने की अनुमति देता है strcpy;


10

ANSI C में:

char* strings[3];
strings[0] = "foo";
strings[1] = "bar";
strings[2] = "baz";

8
@ ज़िफ्रे: मैं पूरी तरह असहमत हूं। यह बहुत कुछ इस प्रकार का हिस्सा है - इस मामले में "चार पॉइंटर"। वैसे भी आप क्या कहेंगे ... यह चर नाम का हिस्सा है? मैंने कई सक्षम प्रोग्रामर को इस शैली का उपयोग करते देखा है।
Noldorin

14
बस इसे पढ़ने वाले किसी और के लिए, मैं यह बताना चाहूंगा कि ब्रेज़न स्ट्रॉस्ट्रुप इस प्रकार से * डालता है ...
मिररफाइरेट

1
@MirroredFate: सही है। वास्तव में, यह C ++ में अभ्यास की सिफारिश की जाती है जो मुझे पता है। शब्दार्थ यह मेरे लिए कोई मतलब नहीं है कि इसे पहचानकर्ता द्वारा डाल दिया जाए, क्योंकि इसका उपयोग किया जाता है। : /
नोल्डोरिन

16
@ नोल्डोरिन char* foo, bar;किस प्रकार का है bar?
mASOUD

10
सी को डेनिस रिची द्वारा 1972 में विकसित किया गया था और 1988 में उन्होंने और ब्रायन केर्निघन ने के एंड आर - द सी प्रोग्रामिंग लैंग्वेज के दूसरे संस्करण को प्रकाशित किया था। सी। के लिए एक पुस्तक कई डी फैक्टो मानक के रूप में रखती है। उन्होंने पहचानकर्ता द्वारा * डाल दिया।
मारियस लियान

10

यदि तार स्थिर हैं, तो आप इसके साथ सर्वश्रेष्ठ हैं:

const char *my_array[] = {"eenie","meenie","miney"};

जबकि मूल ANSI C का हिस्सा नहीं है, संभावना है कि आपका वातावरण वाक्यविन्यास का समर्थन करता है। ये तार अपरिवर्तनीय (केवल पढ़ने के लिए) हैं, और इस प्रकार कई वातावरणों में गतिशील रूप से स्ट्रिंग सरणी बनाने की तुलना में कम ओवरहेड का उपयोग किया जाता है।

उदाहरण के लिए छोटे सूक्ष्म नियंत्रक परियोजनाओं में, यह वाक्यविन्यास प्रोग्राम मेमोरी का उपयोग करता है (आमतौर पर) अधिक कीमती राम मेमोरी के बजाय। AVR-C इस सिंटैक्स का समर्थन करने वाला एक उदाहरण वातावरण है, लेकिन इसलिए अधिकांश अन्य को करते हैं।


10

यदि आप सरणी में स्ट्रिंग की संख्या पर नज़र नहीं रखना चाहते हैं और उन पर पुनरावृति करना चाहते हैं, तो अंत में NULL स्ट्रिंग जोड़ें:

char *strings[]={ "one", "two", "three", NULL };

int i=0;
while(strings[i]) {
  printf("%s\n", strings[i]);
  //do something
  i++;
};

मेरा मानना ​​है कि यह केवल C ++ में मान्य है। सी में, NULL शून्य होने की गारंटी नहीं है, इसलिए लूप तब नहीं टूट सकता है जब इसे करना चाहिए। अगर मैं ग़लत हूं तो मेरी गलती सुझाएं।
19ec में पालेक

2
कोई विचार नहीं :) यदि आप चाहें तो NULL के साथ तुलना कर सकते हैं।
सेर्गेई

9

स्ट्रिंग शाब्दिक हैं const char *

और कोष्ठक का आपका उपयोग विषम है। आप शायद मतलब है

const char *a[2] = {"blah", "hmm"};

जो निरंतर वर्णों को दो बिंदुओं की एक सरणी घोषित करता है, और उन्हें दो हार्डकोड स्ट्रिंग स्थिरांक पर इंगित करने के लिए प्रारंभ करता है।


3

आपका कोड फ़ंक्शन पॉइंटर्स की एक सरणी बना रहा है। प्रयत्न

char* a[size];

या

char a[size1][size2];

बजाय।

सरणियों और संकेत करने के लिए wikibooks देखें


1
अपने अलग दृष्टिकोण के लिए हैट ... आप जैसे लोग ओवरफ्लो करने के लिए स्टैक बनाते हैं ...
साहू वी कुमार

1

हैलो आप इस bellow की कोशिश कर सकते हैं:

 char arr[nb_of_string][max_string_length]; 
 strcpy(arr[0], "word");

यदि आप चाहते हैं तो सी में तार का उपयोग करने का एक अच्छा उदाहरण है

#include <stdio.h>
#include <string.h>


int main(int argc, char *argv[]){

int i, j, k;

// to set you array
//const arr[nb_of_string][max_string_length]
char array[3][100];

char temp[100];
char word[100];

for (i = 0; i < 3; i++){
    printf("type word %d : ",i+1);
    scanf("%s", word);
    strcpy(array[i], word);
}

for (k=0; k<3-1; k++){
    for (i=0; i<3-1; i++)
    {
        for (j=0; j<strlen(array[i]); j++)
        {
            // if a letter ascii code is bigger we swap values
            if (array[i][j] > array[i+1][j])
            {
                strcpy(temp, array[i+1]);
                strcpy(array[i+1], array[i]);
                strcpy(array[i], temp);

                j = 999;
            }

            // if a letter ascii code is smaller we stop
            if (array[i][j] < array[i+1][j])
            {
                    j = 999;
            }

        }
    }
}

for (i=0; i<3; i++)
{
    printf("%s\n",array[i]);
}

return 0;
}

0
char name[10][10]
int i,j,n;//here "n" is number of enteries
printf("\nEnter size of array = ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
    for(j=0;j<1;j++)
    {
        printf("\nEnter name = ");
        scanf("%s",&name[i]);
    }
}
//printing the data
for(i=0;i<n;i++)
{
    for(j=0;j<1;j++)
    {
        printf("%d\t|\t%s\t|\t%s",rollno[i][j],name[i],sex[i]);
    }
    printf("\n");
}

यहाँ यह कोशिश करो !!!


1
क्या आप बता सकते हैं कि आपको चर j के साथ, यानी, (j = 0; j <? j ++) के लिए लूप की आवश्यकता क्यों है?
सौविकमाजी

0

मुझे स्ट्रिंग्स के किसी भी अधिक गतिशील सरणी को याद कर रहा था, जहां रन-टाइम चयन के आधार पर स्ट्रिंग्स की मात्रा भिन्न हो सकती है, लेकिन अन्यथा स्ट्रिंग्स को तय किया जाना चाहिए।

मैंने कोडिंग कोड स्निपेट को इस तरह समाप्त किया है:

#define INIT_STRING_ARRAY(...)          \
    {                                   \
        char* args[] = __VA_ARGS__;     \
        ev = args;                      \
        count = _countof(args);         \
    }

void InitEnumIfAny(String& key, CMFCPropertyGridProperty* item)
{
    USES_CONVERSION;
    char** ev = nullptr;
    int count = 0;

    if( key.Compare("horizontal_alignment") )
        INIT_STRING_ARRAY( { "top", "bottom" } )

    if (key.Compare("boolean"))
        INIT_STRING_ARRAY( { "yes", "no" } )

    if( ev == nullptr )
        return;

    for( int i = 0; i < count; i++)
        item->AddOption(A2T(ev[i]));

    item->AllowEdit(FALSE);
}

char** evअरेंज स्ट्रिंग्स के लिए पॉइंटर को उठाता है, और _countofफ़ंक्शन का उपयोग करके स्ट्रिंग्स की मात्रा को चुनता है । (समान sizeof(arr) / sizeof(arr[0]))।

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


-6

एक अच्छा तरीका यह है कि एक स्ट्रिंग को अपने आप को परिभाषित करें।

#include <stdio.h>
typedef char string[]
int main() {
    string test = "string";
    return 0;
}

यह वास्तव में इतना आसान है।


4
आप एक को याद कर रहे हैं ;, और यह कैसे स्ट्रिंग की एक सरणी बनाता है ?
कीसर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.