2010-06-28 22 views
37

मैं समझने की कोशिश कर रहा हूं कि सी में इस छोटी सी समस्या को साफ/सुरक्षित तरीके से कैसे हल किया जाए।एक नया स्ट्रिंग मान सही तरीके से कैसे असाइन करें?

#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    typedef struct 
    { 
     char name[20]; 
     char surname[20]; 
     int unsigned age; 
    } person; 

    //Here i can pass strings as values...how does it works? 
    person p = {"John", "Doe",30}; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 
    // This works as expected... 
    p.age = 25; 
    //...but the same approach doesn't work with a string 
    p.name = "Jane"; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    return 1; 
} 

संकलक की त्रुटि है:

main.c: In function ‘main’: main.c:18: error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’

मैं समझता हूँ कि सी (नहीं सी ++) कोई स्ट्रिंग प्रकार है और बदले तो एक और तरीका यह करना था ऐसा करने के लिए वर्ण की सरणियों का उपयोग करता है, यहाँ मेरी उदाहरण है वर्ण के संकेत पकड़ करने के लिए उदाहरण struct बदल:

#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    typedef struct 
    { 
     char *name; 
     char *surname; 
     int unsigned age; 
    } person; 

    person p = {"John", "Doe",30}; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    p.age = 25; 

    p.name = "Jane"; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    return 1; 
} 

यह अपेक्षा के अनुरूप काम करता है लेकिन मुझे आश्चर्य है कि अगर वहाँ एक बेहतर तरीका यह करने के लिए। धन्यवाद।

+0

यदि हम 'मुख्य()' में संरचना घोषित करते हैं, तो व्यक्ति केवल इसके अंदर पहुंच सकता है। इसे वैश्विक – EsmaeelE

उत्तर

29

पहला उदाहरण काम नहीं करता है क्योंकि आप इस संबंध में कॉन्स्ट पॉइंटर्स जैसे सरणी - सरणी कार्य (प्रकार) को असाइन नहीं कर सकते हैं।

strcpy(p.name, "Jane"); 

चार सरणियों, अगर आप पहले से स्ट्रिंग का अधिकतम आकार पता उपयोग करने के लिए ठीक हैं उदहारण के लिए: क्या आप क्या कर सकते हैं, हालांकि सरणी में एक नया मान की प्रतिलिपि है पहले उदाहरण में आप 100% सुनिश्चित हैं कि नाम 1 9 अक्षरों में फिट होगा (20 नहीं) क्योंकि शून्य वर्ण को समाप्त करने के लिए हमेशा एक वर्ण की आवश्यकता होती है)।

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

अद्यतन: गतिशील रूप से आवंटित बफर (अपने 2 उदाहरण में struct परिभाषा का उपयोग) के उदाहरण:

char* firstName = "Johnnie"; 
char* surname = "B. Goode"; 
person p; 

p.name = malloc(strlen(firstName) + 1); 
p.surname = malloc(strlen(surname) + 1); 

p.age = 25; 
strcpy(p.name, firstName); 
strcpy(p.surname, surname); 

printf("Name: %s; Age: %d\n",p.name,p.age); 

free(p.surname); 
free(p.name); 
7

कंटेनर के रूप में सार वस्तुओं, और चार सरणियों के रूप में तार के Think। स्ट्रिंग किसी भी आकार का हो सकता है लेकिन कंटेनर स्ट्रिंग लम्बाई से कम से कम 1 और होना चाहिए (शून्य टर्मिनेटर को पकड़ने के लिए)।

सी तारों के लिए बहुत कम वाक्य रचनात्मक समर्थन है। कोई स्ट्रिंग ऑपरेटर नहीं हैं (केवल चार-सरणी और चार-सूचक ऑपरेटर)। आप स्ट्रिंग असाइन नहीं कर सकते हैं।

लेकिन आप जो भी चाहते हैं उसे प्राप्त करने में सहायता के लिए आप कार्यों को कॉल कर सकते हैं।

strncpy() फ़ंक्शन का उपयोग यहां किया जा सकता है।

strncpy(p.name, "Jane", 19); 
p.name[19] = '\0'; //add null terminator just in case 

इसके अलावा strncat() और memcpy() कार्यों पर एक नजर है: अधिकतम सुरक्षा के लिए मैं इस पैटर्न निम्नलिखित सुझाव देते हैं।

+1

के रूप में उपयोग करने के लिए मुख्य से बाहर निकलने का प्रयास करें, अब सबसे अच्छा जवाब है, लेकिन पेटर का भी अच्छा है (यह दिखाता है कि पॉइंटर्स के साथ इसे कैसे करना है) ताकि मैं यह देखने के लिए थोड़ा और इंतजार कर रहा हूं कि अधिक लोग और युक्तियां जोड़ सकते हैं या नहीं/विषय पर सुझाव। –

4

दो structs अलग हैं। जब आप पहली संरचना शुरू करते हैं, तो स्मृति के लगभग 40 बाइट आवंटित किए जाते हैं। जब आप दूसरी संरचना को प्रारंभ करते हैं, तो लगभग 10 बाइट्स मेमोरी आवंटित की जाती है। (वास्तविक राशि आर्किटेक्चर निर्भर है)

आप वर्ण सरणी को निष्क्रिय करने के लिए स्ट्रिंग अक्षर (स्ट्रिंग स्थिरांक) का उपयोग कर सकते हैं। यही कारण है कि

person p = {"John", "Doe",30};

पहले उदाहरण में काम करता है।

आप सी

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

char* string = "Hello"; 
*string = 'C' 

संकलन या क्रम त्रुटियों के कारण हो सकता (मुझे यकीन है कि नहीं कर रहा हूँ।) यह एक बुरा विचार है, क्योंकि आप शाब्दिक स्ट्रिंग "नमस्ते" जो, एक microcontroler पर उदाहरण के लिए, स्थित किया जा सकता है संशोधित कर रहे हैं केवल पढ़ने योग्य स्मृति में।

+0

आप सही हैं, आपके द्वारा लिखे गए असाइनमेंट सेगफॉल्ट का कारण बनता है क्योंकि आप पॉइंटर वैल्यू को बदलने की कोशिश कर रहे हैं, लेकिन मेरे उदाहरण का जिक्र करते हुए चीजें char * string = "Hello" की तरह होती हैं; स्ट्रिंग = "सी"; (ध्यान दें कि अंतिम कथन पर कोई सूचक असाइनमेंट नहीं है) जो अपेक्षित के रूप में काम करता है। –

+1

मैं यह उल्लेख करना चाहूंगा कि "पॉइंटर वैल्यू को बदलना" जरूरी नहीं है कि एक सेगफॉल्ट हो। कारण है कि मेरे मूल पोस्ट में स्निपेट एक segfault का कारण बनता है क्योंकि आप प्रतिबंधित पता स्थान में स्थित स्मृति को संशोधित करने का प्रयास कर रहे हैं। – Gus

संबंधित मुद्दे