C Language
स्ट्रिंग्स
खोज…
परिचय
सी में, एक स्ट्रिंग एक आंतरिक प्रकार नहीं है। एक सी-स्ट्रिंग एक ऐसा कन्वेंशन है जिसमें एक-आयामी कैरेक्टर होता है जिसे '\0'
द्वारा '\0'
null-character '\0'
द्वारा समाप्त किया जाता है।
इसका अर्थ है कि "abc"
की सामग्री वाले C- स्ट्रिंग में चार अक्षर 'a'
, 'b'
, 'c'
और '\0'
।
स्ट्रिंग के उदाहरण के लिए मूल परिचय देखें।
वाक्य - विन्यास
- char str1 [] = "हैलो, दुनिया!"; / * परिवर्तनीय * /
- char str2 [14] = "हैलो, दुनिया!"; / * परिवर्तनीय * /
- char * str3 = "हैलो, दुनिया!"; /* संशोधन योग्य नहीं*/
लंबाई की गणना करें: strlen ()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
/* Exit if no second argument is found. */
if (argc != 2)
{
puts("Argument missing.");
return EXIT_FAILURE;
}
size_t len = strlen(argv[1]);
printf("The length of the second argument is %zu.\n", len);
return EXIT_SUCCESS;
}
यह कार्यक्रम अपने दूसरे इनपुट तर्क की लंबाई की गणना करता है और परिणाम को len
में संग्रहीत करता है। यह तब टर्मिनल तक उस लंबाई को प्रिंट करता है। उदाहरण के लिए, जब पैरामीटर program_name "Hello, world!"
साथ चलाया जाता है program_name "Hello, world!"
, प्रोग्राम आउटपुट करेगा The length of the second argument is 13.
क्योंकि स्ट्रिंग Hello, world!
13 वर्ण लंबा है।
strlen
स्ट्रिंग की शुरुआत से सभी बाइट्स को गिनता है, लेकिन शामिल नहीं, समाप्त करने वाला NUL वर्ण, '\0'
। जैसे, यह केवल तब उपयोग किया जा सकता है जब स्ट्रिंग को एनयूएल-समाप्त होने की गारंटी दी जाती है।
यह भी ध्यान रखें कि यदि स्ट्रिंग में कोई यूनिकोड वर्ण हैं, तो strlen
आपको यह नहीं बताएगा कि स्ट्रिंग में कितने वर्ण हैं (क्योंकि कुछ वर्ण एकाधिक बाइट्स लंबे हो सकते हैं)। ऐसे मामलों में, आपको पात्रों ( यानी , कोड इकाइयों) को स्वयं गिनने की आवश्यकता है। निम्नलिखित उदाहरण के उत्पादन पर विचार करें:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char asciiString[50] = "Hello world!";
char utf8String[50] = "Γειά σου Κόσμε!"; /* "Hello World!" in Greek */
printf("asciiString has %zu bytes in the array\n", sizeof(asciiString));
printf("utf8String has %zu bytes in the array\n", sizeof(utf8String));
printf("\"%s\" is %zu bytes\n", asciiString, strlen(asciiString));
printf("\"%s\" is %zu bytes\n", utf8String, strlen(utf8String));
}
आउटपुट:
asciiString has 50 bytes in the array
utf8String has 50 bytes in the array
"Hello world!" is 12 bytes
"Γειά σου Κόσμε!" is 27 bytes
कॉपी और कॉनटेनटेशन: strcpy (), strcat ()
#include <stdio.h>
#include <string.h>
int main(void)
{
/* Always ensure that your string is large enough to contain the characters
* and a terminating NUL character ('\0')!
*/
char mystring[10];
/* Copy "foo" into `mystring`, until a NUL character is encountered. */
strcpy(mystring, "foo");
printf("%s\n", mystring);
/* At this point, we used 4 chars of `mystring`, the 3 characters of "foo",
* and the NUL terminating byte.
*/
/* Append "bar" to `mystring`. */
strcat(mystring, "bar");
printf("%s\n", mystring);
/* We now use 7 characters of `mystring`: "foo" requires 3, "bar" requires 3
* and there is a terminating NUL character ('\0') at the end.
*/
/* Copy "bar" into `mystring`, overwriting the former contents. */
strcpy(mystring, "bar");
printf("%s\n", mystring);
return 0;
}
आउटपुट:
foo
foobar
bar
यदि आप किसी मौजूदा स्ट्रिंग से या उससे या उससे कॉपी करते हैं, तो यह सुनिश्चित करें कि यह NUL- टर्मिनेटेड है!
स्ट्रिंग शाब्दिक (उदाहरण के लिए "foo"
) हमेशा संकलक द्वारा एनयूएल-समाप्त होगा।
मजबूरी: strcmp (), strncmp (), strcasecmp (), strncasmp ()
strcase*
मानक C नहीं हैं, लेकिन एक POSIX एक्सटेंशन हैं।
strcmp
फंक्शन strcmp
दो अशक्त-वर्ण वर्ण सरणियों की तुलना करता है। यदि ऋणात्मक क्रम में दूसरे के सामने पहला तर्क दिखाई देता है तो शून्य ऋणात्मक मान लौटाता है, यदि वे समान या तुलनात्मक रूप से शून्य हों, तो पहला तर्क दूसरी क्रमांक के बाद प्रकट होता है।
#include <stdio.h>
#include <string.h>
void compare(char const *lhs, char const *rhs)
{
int result = strcmp(lhs, rhs); // compute comparison once
if (result < 0) {
printf("%s comes before %s\n", lhs, rhs);
} else if (result == 0) {
printf("%s equals %s\n", lhs, rhs);
} else { // last case: result > 0
printf("%s comes after %s\n", lhs, rhs);
}
}
int main(void)
{
compare("BBB", "BBB");
compare("BBB", "CCCCC");
compare("BBB", "AAAAAA");
return 0;
}
आउटपुट:
BBB equals BBB
BBB comes before CCCCC
BBB comes after AAAAAA
strcmp
रूप में, strcasecmp
फ़ंक्शन प्रत्येक अक्षर को उसके strcasecmp
अक्षरों में अनुवाद करने के बाद उसके तर्क की तुलना करता है:
#include <stdio.h>
#include <string.h>
void compare(char const *lhs, char const *rhs)
{
int result = strcasecmp(lhs, rhs); // compute case-insensitive comparison once
if (result < 0) {
printf("%s comes before %s\n", lhs, rhs);
} else if (result == 0) {
printf("%s equals %s\n", lhs, rhs);
} else { // last case: result > 0
printf("%s comes after %s\n", lhs, rhs);
}
}
int main(void)
{
compare("BBB", "bBB");
compare("BBB", "ccCCC");
compare("BBB", "aaaaaa");
return 0;
}
आउटपुट:
BBB equals bBB
BBB comes before ccCCC
BBB comes after aaaaaa
strncmp
और strncasecmp
अधिकांश n वर्णों पर तुलना करते हैं:
#include <stdio.h>
#include <string.h>
void compare(char const *lhs, char const *rhs, int n)
{
int result = strncmp(lhs, rhs, n); // compute comparison once
if (result < 0) {
printf("%s comes before %s\n", lhs, rhs);
} else if (result == 0) {
printf("%s equals %s\n", lhs, rhs);
} else { // last case: result > 0
printf("%s comes after %s\n", lhs, rhs);
}
}
int main(void)
{
compare("BBB", "Bb", 1);
compare("BBB", "Bb", 2);
compare("BBB", "Bb", 3);
return 0;
}
आउटपुट:
BBB equals Bb
BBB comes before Bb
BBB comes before Bb
Tokenisation: strtok (), strtok_r () और strtok_s ()
फ़ंक्शन strtok
एक स्ट्रिंग को छोटे स्ट्रिंग्स, या टोकन में विभाजित करता है, जो कि सीमांकक का उपयोग करता है।
#include <stdio.h>
#include <string.h>
int main(void)
{
int toknum = 0;
char src[] = "Hello,, world!";
const char delimiters[] = ", !";
char *token = strtok(src, delimiters);
while (token != NULL)
{
printf("%d: [%s]\n", ++toknum, token);
token = strtok(NULL, delimiters);
}
/* source is now "Hello\0, world\0\0" */
}
आउटपुट:
1: [Hello]
2: [world]
सीमांकक की स्ट्रिंग एक या अधिक परिसीमक हो सकती है और अलग अलग सीमांकक तार प्रत्येक कॉल करने के साथ इस्तेमाल किया जा सकता strtok
।
एक ही स्रोत स्ट्रिंग को जारी रखने के लिए strtok
को कॉल करने के लिए स्रोत स्ट्रिंग को फिर से पास नहीं करना चाहिए, लेकिन इसके बजाय NULL
को पहले तर्क के रूप में पास करें। एक ही स्रोत स्ट्रिंग पारित हो जाता है तो पहले टोकन के बजाय फिर से tokenized हो जाएगा। यही कारण है कि एक ही सीमांकक दिया जाता है, strtok
पहले टोकन को फिर से लौटाएगा।
ध्यान दें कि strtok
टोकन के लिए नई मेमोरी आवंटित नहीं करता है, यह स्रोत स्ट्रिंग को संशोधित करता है । यही है, उपरोक्त उदाहरण में, स्ट्रिंग src
को टोकन का उत्पादन करने के लिए हेरफेर किया जाएगा जो कि कॉल द्वारा strtok
को लौटाए गए पॉइंटर द्वारा strtok
। इसका मतलब यह है कि स्रोत स्ट्रिंग const
नहीं हो सकती है (इसलिए यह स्ट्रिंग शाब्दिक नहीं हो सकती है)। इसका अर्थ यह भी है कि परिसीमन बाइट की पहचान खो जाती है (उदाहरण में "," और "!" को प्रभावी रूप से स्रोत स्ट्रिंग से हटा दिया जाता है और आप यह नहीं बता सकते हैं कि कौन सी परिसीमा वर्ण से मेल खाती है)।
यह भी ध्यान दें कि स्रोत स्ट्रिंग में कई लगातार परिसीमन को एक माना जाता है; उदाहरण में, दूसरे अल्पविराम को अनदेखा किया जाता है।
strtok
न तो थ्रेड सेफ है और न ही री-एंट्रेंट क्योंकि पार्स करते समय यह स्टैटिक बफर का उपयोग करता है। इसका मतलब है कि एक समारोह कॉल strtok
, कोई समारोह है कि यह कॉल, जबकि यह उपयोग कर रहा है strtok
भी उपयोग कर सकते हैं strtok
, और यह किसी भी समारोह है जो अपने आप का उपयोग करके नहीं कहा जा सकता strtok
।
एक उदाहरण जो इस तथ्य के कारण होने वाली समस्याओं को दर्शाता है कि strtok
फिर से प्रवेश नहीं करता है, इस प्रकार है:
char src[] = "1.2,3.5,4.2";
char *first = strtok(src, ",");
do
{
char *part;
/* Nested calls to strtok do not work as desired */
printf("[%s]\n", first);
part = strtok(first, ".");
while (part != NULL)
{
printf(" [%s]\n", part);
part = strtok(NULL, ".");
}
} while ((first = strtok(NULL, ",")) != NULL);
आउटपुट:
[1.2]
[1]
[2]
अपेक्षित संचालन यह है कि बाहरी do while
लूप को प्रत्येक दशमलव संख्या स्ट्रिंग ( "1.2"
, "3.5"
, "4.2"
) से युक्त तीन टोकन बनाने चाहिए, जिनमें से प्रत्येक के लिए आंतरिक लूप के strtok
कॉल को अलग-अलग विभाजित करना चाहिए। अंक तार ( "1"
, "2"
, "3"
, "5"
, "4"
, "2"
)।
हालाँकि, क्योंकि strtok
फिर से प्रवेश नहीं करता है, ऐसा नहीं होता है। इसके बजाय पहले strtok
सही ढंग से "1.2 \ 0" टोकन बनाता है, और आंतरिक लूप सही ढंग से टोकन "1"
और "2"
बनाता है। लेकिन फिर बाहरी लूप में strtok
आंतरिक लूप द्वारा उपयोग किए जाने वाले स्ट्रिंग के अंत में है, और तुरंत नल लौटाता है। src
सरणी के दूसरे और तीसरे सबस्ट्रिंग का विश्लेषण बिल्कुल नहीं किया जाता है।
मानक C लाइब्रेरी में थ्रेड-सुरक्षित या री-एंट्रेंट संस्करण नहीं होता है, लेकिन कुछ अन्य जैसे POSIX ' strtok_r
। ध्यान दें कि MSVC पर strtok
समतुल्य, strtok_s
थ्रेड-सुरक्षित है।
C11 का एक वैकल्पिक हिस्सा है, अनुलग्नक K, जो strtok_s
नाम का एक थ्रेड-सुरक्षित और पुन: strtok_s
संस्करण strtok_s
। आप __STDC_LIB_EXT1__
साथ सुविधा के लिए परीक्षण कर सकते हैं। यह वैकल्पिक हिस्सा व्यापक रूप से समर्थित नहीं है।
strtok_s
फ़ंक्शन, POSIX strtok_r
फ़ंक्शन से भिन्न होता है, जो स्ट्रिंग के बाहर रख रहे हैं, और टोकन संचय की जाँच करके, उसके बाहर रखवाली करके। सही ढंग से लिखे गए कार्यक्रमों पर, हालांकि, strtok_s
और strtok_r
समान व्यवहार करते हैं।
उदाहरण के साथ strtok_s
का उपयोग करके अब सही प्रतिक्रिया strtok_s
, जैसे:
/* you have to announce that you want to use Annex K */
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#ifndef __STDC_LIB_EXT1__
# error "we need strtok_s from Annex K"
#endif
char src[] = "1.2,3.5,4.2";
char *next = NULL;
char *first = strtok_s(src, ",", &next);
do
{
char *part;
char *posn;
printf("[%s]\n", first);
part = strtok_s(first, ".", &posn);
while (part != NULL)
{
printf(" [%s]\n", part);
part = strtok_s(NULL, ".", &posn);
}
}
while ((first = strtok_s(NULL, ",", &next)) != NULL);
और उत्पादन होगा:
[1.2]
[1]
[2]
[3.5]
[3]
[5]
[4.2]
[4]
[2]
किसी विशिष्ट वर्ण की पहली / अंतिम घटना ज्ञात करें: strchr (), strrchr ()
strchr
और strrchr
फ़ंक्शंस एक स्ट्रिंग में एक चरित्र पाते हैं, जो कि एनयूएल-टर्मिनेटेड कैरेक्टर एरे में है। strchr
पहली घटना के लिए एक सूचक strrchr
है और पिछले एक को strrchr
।
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char toSearchFor = 'A';
/* Exit if no second argument is found. */
if (argc != 2)
{
printf("Argument missing.\n");
return EXIT_FAILURE;
}
{
char *firstOcc = strchr(argv[1], toSearchFor);
if (firstOcc != NULL)
{
printf("First position of %c in %s is %td.\n",
toSearchFor, argv[1], firstOcc-argv[1]); /* A pointer difference's result
is a signed integer and uses the length modifier 't'. */
}
else
{
printf("%c is not in %s.\n", toSearchFor, argv[1]);
}
}
{
char *lastOcc = strrchr(argv[1], toSearchFor);
if (lastOcc != NULL)
{
printf("Last position of %c in %s is %td.\n",
toSearchFor, argv[1], lastOcc-argv[1]);
}
}
return EXIT_SUCCESS;
}
आउटपुट (एक निष्पादन योग्य नाम pos
उत्पन्न करने के बाद):
$ ./pos AAAAAAA
First position of A in AAAAAAA is 0.
Last position of A in AAAAAAA is 6.
$ ./pos BAbbbbbAccccAAAAzzz
First position of A in BAbbbbbAccccAAAAzzz is 1.
Last position of A in BAbbbbbAccccAAAAzzz is 15.
$ ./pos qwerty
A is not in qwerty.
एक पथ से एक फ़ाइल नाम निकालने के लिए strrchr
का एक सामान्य उपयोग है। उदाहरण के लिए C:\Users\eak\myfile.txt
से myfile.txt
निकालने के लिए:
char *getFileName(const char *path)
{
char *pend;
if ((pend = strrchr(path, '\')) != NULL)
return pend + 1;
return NULL;
}
एक स्ट्रिंग में वर्ण से अधिक Iterating
यदि हम स्ट्रिंग की लंबाई जानते हैं, तो हम लूप के लिए इसके पात्रों पर पुनरावृति करने के लिए उपयोग कर सकते हैं:
char * string = "hello world"; /* This 11 chars long, excluding the 0-terminator. */
size_t i = 0;
for (; i < 11; i++) {
printf("%c\n", string[i]); /* Print each character of the string. */
}
वैकल्पिक रूप से, हम एक स्ट्रिंग की लंबाई प्राप्त करने के लिए मानक फ़ंक्शन strlen()
का उपयोग कर सकते हैं यदि हम नहीं जानते कि स्ट्रिंग क्या है:
size_t length = strlen(string);
size_t i = 0;
for (; i < length; i++) {
printf("%c\n", string[i]); /* Print each character of the string. */
}
अंत में, हम तथ्य यह है कि सी में तार अशक्त-समाप्त होने की गारंटी कर रहे हैं का लाभ ले सकते हैं (जो हम पहले से ही था कि यह करने के लिए जब गुजर strlen()
पिछले उदाहरण में ;-))। हम अपने आकार की परवाह किए बिना सरणी पर पुनरावृत्ति कर सकते हैं और एक बार हम अशक्त चरित्र तक पहुँचने से रोकते हैं:
size_t i = 0;
while (string[i] != '\0') { /* Stop looping when we reach the null-character. */
printf("%c\n", string[i]); /* Print each character of the string. */
i++;
}
तार का मूल परिचय
सी में, एक स्ट्रिंग वर्णों का एक अनुक्रम है जो एक अशक्त चरित्र ('\ 0') द्वारा समाप्त किया जाता है।
हम स्ट्रिंग शाब्दिक का उपयोग करके तार बना सकते हैं, जो दोहरे उद्धरण चिह्नों से घिरे वर्णों के अनुक्रम हैं; उदाहरण के लिए, स्ट्रिंग शाब्दिक "hello world"
। स्ट्रिंग शाब्दिक स्वचालित रूप से शून्य-समाप्त हो जाते हैं।
हम कई तरीकों का उपयोग करके तार बना सकते हैं। उदाहरण के लिए, हम एक char *
घोषणा कर सकते हैं और इसे एक स्ट्रिंग के पहले चरित्र को इंगित करने के लिए इसे शुरू कर सकते हैं:
char * string = "hello world";
जब ऊपर की तरह एक स्ट्रिंग स्थिरांक पर char *
का इनिशियलाइज़ेशन किया जाता है, तो स्ट्रिंग को आमतौर पर केवल-पठन डेटा में आवंटित किया जाता है; string
सरणी के पहले तत्व का एक संकेतक है, जो कि वर्ण 'h'
।
चूंकि स्ट्रिंग शाब्दिक को केवल-पढ़ने के लिए मेमोरी में आवंटित किया जाता है, यह गैर-परिवर्तनीय 1 है । इसे संशोधित करने का कोई भी प्रयास अपरिभाषित व्यवहार को बढ़ावा देगा, इसलिए इस तरह संकलन-समय त्रुटि प्राप्त करने के लिए const
जोड़ना बेहतर होगा
char const * string = "hello world";
इसका प्रभाव 2 के समान है
char const string_arr[] = "hello world";
एक परिवर्तनीय स्ट्रिंग बनाने के लिए, आप एक वर्ण सरणी की घोषणा कर सकते हैं और एक स्ट्रिंग शाब्दिक का उपयोग करके इसकी सामग्री को इनिशियलाइज़ कर सकते हैं, जैसे:
char modifiable_string[] = "hello world";
यह निम्नलिखित के बराबर है:
char modifiable_string[] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'};
चूंकि दूसरा संस्करण ब्रेस-एनक्लोजर इनिशियलाइज़र का उपयोग करता है, स्ट्रिंग को स्वचालित रूप से शून्य-समाप्त नहीं किया जाता है जब तक कि एक '\0'
वर्ण स्पष्ट रूप से वर्ण सरणी में आमतौर पर इसके अंतिम तत्व के रूप में शामिल नहीं होता है।
1 गैर-परिवर्तनीय का अर्थ है कि स्ट्रिंग शाब्दिक में वर्णों को संशोधित नहीं किया जा सकता है, लेकिन याद रखें कि सूचक string
को संशोधित किया जा सकता है (कहीं और इंगित कर सकता है या बढ़ाया या घटाया जा सकता है)।
2 दोनों तारों का एक अर्थ में समान प्रभाव है कि दोनों तारों के पात्रों को संशोधित नहीं किया जा सकता है। यह ध्यान देने योग्य है कि string
के लिए सूचक है char
और यह एक है परिवर्तनीय एल-मूल्य तो यह या वृद्धि की जा सकती है किसी अन्य स्थान को इंगित करते हुए सरणी string_arr
एक गैर-परिवर्तनीय एल-मूल्य है, यह बदला नहीं जा सकता।
स्ट्रिंग्स का एरे बनाना
स्ट्रिंग की एक सरणी का मतलब कुछ चीजों से हो सकता है:
- एक सरणी जिसका तत्व
char *
s हैं - एक सरणी जिसका तत्व
char
एस की सरणियाँ हैं
हम चरित्र बिंदुओं की एक सरणी बना सकते हैं जैसे:
char * string_array[] = {
"foo",
"bar",
"baz"
};
याद रखें: जब हम स्ट्रिंग शाब्दिकों को char *
असाइन करते हैं, तो स्ट्रिंग्स स्वयं को केवल-पढ़ने के लिए मेमोरी में आवंटित किए जाते हैं। हालाँकि, string_array
को रीड / राइट मेमोरी में आवंटित किया जाता है। इसका मतलब है कि हम पॉइंटर्स को एरे में संशोधित कर सकते हैं, लेकिन हम उन स्ट्रिंग्स को संशोधित नहीं कर सकते हैं, जो वे इंगित करते हैं।
C में, मुख्य argv
का पैरामीटर (कमांड-लाइन आर्ग्युमेंट्स का अरेंजमेंट जब प्रोग्राम चलाया गया था) char *
का एक सरणी है char *
: char * argv[]
।
हम चरित्र सरणियों के ऐरे भी बना सकते हैं। चूंकि तार वर्णों के सरणियाँ हैं, तार का एक सरणी बस एक सरणी है जिसके तत्व वर्णों के सरणियाँ हैं:
char modifiable_string_array_literals[][4] = {
"foo",
"bar",
"baz"
};
यह इसके बराबर है:
char modifiable_string_array[][4] = {
{'f', 'o', 'o', '\0'},
{'b', 'a', 'r', '\0'},
{'b', 'a', 'z', '\0'}
};
ध्यान दें कि हम सरणी के दूसरे आयाम के आकार के रूप में 4
निर्दिष्ट करते हैं; हमारे एरे में प्रत्येक स्ट्रिंग्स वास्तव में 4 बाइट्स हैं क्योंकि हमें शून्य-समाप्ति वर्ण शामिल करना चाहिए।
strstr
/* finds the next instance of needle in haystack
zbpos: the zero-based position to begin searching from
haystack: the string to search in
needle: the string that must be found
returns the next match of `needle` in `haystack`, or -1 if not found
*/
int findnext(int zbpos, const char *haystack, const char *needle)
{
char *p;
if (((p = strstr(haystack + zbpos, needle)) != NULL)
return p - haystack;
return -1;
}
strstr
खोजें haystack
(प्रथम) स्ट्रिंग के लिए तर्क द्वारा की ओर इशारा किया needle
। यदि पाया जाता है, तो strstr
घटना का पता देता है। यदि उसे needle
नहीं मिली, तो वह NULL लौटाता है। हम zbpos
उपयोग zbpos
ताकि हम एक ही सुई को बार-बार ढूंढते न रहें। पहले उदाहरण को छोड़ने के लिए, हम zbpos
भरपाई zbpos
। नोटपैड क्लोन अपने "फाइंड नेक्स्ट" डायलॉग को लागू करने के लिए इस तरह से findnext
कह सकता है:
/*
Called when the user clicks "Find Next"
doc: The text of the document to search
findwhat: The string to find
*/
void onfindnext(const char *doc, const char *findwhat)
{
static int i;
if ((i = findnext(i, doc, findwhat)) != -1)
/* select the text starting from i and ending at i + strlen(findwhat) */
else
/* display a message box saying "end of search" */
}
स्ट्रिंग शाब्दिक
स्ट्रिंग शाब्दिक char
- शून्य, char
- चरण की स्थिर-अवधि सरणियों का प्रतिनिधित्व करते हैं। क्योंकि उनके पास स्थिर भंडारण अवधि है, एक स्ट्रिंग शाब्दिक या एक ही अंतर्निहित सरणी के लिए एक संकेतक सुरक्षित रूप से कई तरीकों से उपयोग किया जा सकता है जो कि एक स्वचालित सरणी के लिए एक सूचक नहीं कर सकता है। उदाहरण के लिए, एक फ़ंक्शन से एक स्ट्रिंग शाब्दिक वापस करने से अच्छी तरह से परिभाषित व्यवहार होता है:
const char *get_hello() {
return "Hello, World!"; /* safe */
}
ऐतिहासिक कारणों से, एक स्ट्रिंग के लिए इसी सरणी के तत्वों शाब्दिक औपचारिक रूप से नहीं कर रहे हैं const
। फिर भी, उन्हें संशोधित करने के किसी भी प्रयास में अपरिभाषित व्यवहार होता है । आमतौर पर, एक प्रोग्राम जो स्ट्रिंग स्ट्रिंग के अनुरूप सरणी को संशोधित करने का प्रयास करता है, दुर्घटनाग्रस्त हो जाएगा या अन्यथा खराबी।
char *foo = "hello";
foo[0] = 'y'; /* Undefined behavior - BAD! */
जहां एक सूचक एक स्ट्रिंग शाब्दिक की ओर इशारा करता है - या जहां यह कभी-कभी हो सकता है - यह घोषित करने के लिए सलाह दी जाती है कि गलती से इस तरह के अपरिभाषित व्यवहार को उलझाने से बचने के लिए पॉइंटर के संदर्भ const
।
const char *foo = "hello";
/* GOOD: can't modify the string pointed to by foo */
दूसरी ओर, एक स्ट्रिंग शाब्दिक के अंतर्निहित सरणी में एक सूचक स्वयं स्वाभाविक रूप से विशेष नहीं है; इसके मूल्य को स्वतंत्र रूप से कुछ और इंगित करने के लिए संशोधित किया जा सकता है:
char *foo = "hello";
foo = "World!"; /* OK - we're just changing what foo points to */
इसके अलावा, हालांकि के लिए initializers char
सरणियों स्ट्रिंग शाब्दिक, इस तरह के एक प्रारंभकर्ता के उपयोग initialized सरणी पर एक स्ट्रिंग शाब्दिक की विशेषताओं प्रदान नहीं करता है के रूप में एक ही रूप हो सकता है। इनिशलाइज़र बस सरणी की लंबाई और प्रारंभिक सामग्री को नामित करता है। विशेष रूप से, तत्वों यदि स्पष्ट रूप से घोषित नहीं परिवर्तनीय हैं const
:
char foo[] = "hello";
foo[0] = 'y'; /* OK! */
एक स्ट्रिंग बाहर शून्य
आप एक स्ट्रिंग (या किसी अन्य मेमोरी ब्लॉक) को शून्य करने के लिए memset
को कॉल कर सकते हैं।
कहाँ str
स्ट्रिंग को शून्य करने के लिए है, और n
स्ट्रिंग में बाइट्स की संख्या है।
#include <stdlib.h> /* For EXIT_SUCCESS */
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[42] = "fortytwo";
size_t n = sizeof str; /* Take the size not the length. */
printf("'%s'\n", str);
memset(str, '\0', n);
printf("'%s'\n", str);
return EXIT_SUCCESS;
}
प्रिंटों:
'fortytwo'
''
एक और उदाहरण:
#include <stdlib.h> /* For EXIT_SUCCESS */
#include <stdio.h>
#include <string.h>
#define FORTY_STR "forty"
#define TWO_STR "two"
int main(void)
{
char str[42] = FORTY_STR TWO_STR;
size_t n = sizeof str; /* Take the size not the length. */
char * point_to_two = strstr(str, TWO_STR);
printf("'%s'\n", str);
memset(point_to_two, '\0', n);
printf("'%s'\n", str);
memset(str, '\0', n);
printf("'%s'\n", str);
return EXIT_SUCCESS;
}
प्रिंटों:
'fortytwo'
'forty'
''
strspn और strcspn
एक स्ट्रिंग को देखते हुए, strspn
प्रारंभिक strspn
(स्पैन) की लंबाई की गणना करता है, जिसमें केवल पात्रों की एक विशिष्ट सूची होती है। strcspn
समान है, सिवाय इसके कि यह सूचीबद्ध किए गए को छोड़कर किसी भी वर्ण से मिलकर प्रारंभिक प्रतिस्थापन की लंबाई की गणना करता है:
/*
Provided a string of "tokens" delimited by "separators", print the tokens along
with the token separators that get skipped.
*/
#include <stdio.h>
#include <string.h>
int main(void)
{
const char sepchars[] = ",.;!?";
char foo[] = ";ball call,.fall gall hall!?.,";
char *s;
int n;
for (s = foo; *s != 0; /*empty*/) {
/* Get the number of token separator characters. */
n = (int)strspn(s, sepchars);
if (n > 0)
printf("skipping separators: << %.*s >> (length=%d)\n", n, s, n);
/* Actually skip the separators now. */
s += n;
/* Get the number of token (non-separator) characters. */
n = (int)strcspn(s, sepchars);
if (n > 0)
printf("token found: << %.*s >> (length=%d)\n", n, s, n);
/* Skip the token now. */
s += n;
}
printf("== token list exhausted ==\n");
return 0;
}
चौड़े चरित्र के तारों का उपयोग करने वाले अनुरूप कार्य wcsspn
और wcscspn
; वे उसी तरह उपयोग कर रहे हैं।
तार की नकल करना
सूचक असाइनमेंट स्ट्रिंग की प्रतिलिपि नहीं बनाते हैं
आप पूर्णांक कॉपी करने के लिए =
ऑपरेटर का उपयोग कर सकते हैं, लेकिन आप सी =
स्ट्रिंग में कॉपी करने के लिए =
ऑपरेटर का उपयोग नहीं कर सकते हैं। सी में स्ट्रिंग्स को एक समाप्ति नल-वर्ण वाले वर्णों के सरणियों के रूप में दर्शाया गया है, इसलिए =
ऑपरेटर का उपयोग केवल पते को बचाएगा; एक तार का सूचक)।
#include <stdio.h>
int main(void) {
int a = 10, b;
char c[] = "abc", *d;
b = a; /* Integer is copied */
a = 20; /* Modifying a leaves b unchanged - b is a 'deep copy' of a */
printf("%d %d\n", a, b); /* "20 10" will be printed */
d = c;
/* Only copies the address of the string -
there is still only one string stored in memory */
c[1] = 'x';
/* Modifies the original string - d[1] = 'x' will do exactly the same thing */
printf("%s %s\n", c, d); /* "axc axc" will be printed */
return 0;
}
उपरोक्त उदाहरण संकलित किया गया है क्योंकि हमने char d[3]
बजाय char *d
उपयोग किया है। उत्तरार्द्ध का उपयोग करना एक संकलक त्रुटि का कारण होगा। आप सी में सरणियों को निर्दिष्ट नहीं कर सकते।
#include <stdio.h>
int main(void) {
char a[] = "abc";
char b[8];
b = a; /* compile error */
printf("%s\n", b);
return 0;
}
मानक कार्यों का उपयोग करके तार की नकल करना
strcpy()
वास्तव में स्ट्रिंग की प्रतिलिपि बनाने के लिए, strcpy()
फ़ंक्शन string.h
में उपलब्ध है। नकल करने से पहले गंतव्य के लिए पर्याप्त स्थान आवंटित किया जाना चाहिए।
#include <stdio.h>
#include <string.h>
int main(void) {
char a[] = "abc";
char b[8];
strcpy(b, a); /* think "b special equals a" */
printf("%s\n", b); /* "abc" will be printed */
return 0;
}
snprintf()
बफर ओवररन से बचने के लिए, snprintf()
का उपयोग किया जा सकता है। यह सबसे अच्छा समाधान प्रदर्शन-वार नहीं है क्योंकि इसे टेम्पलेट स्ट्रिंग को पार्स करना है, लेकिन मानक लाइब्रेरी में आसानी से उपलब्ध स्ट्रिंग की प्रतिलिपि बनाने के लिए यह केवल बफर सीमा-सुरक्षित फ़ंक्शन है, जिसे बिना किसी अतिरिक्त चरणों के उपयोग किया जा सकता है।
#include <stdio.h>
#include <string.h>
int main(void) {
char a[] = "012345678901234567890";
char b[8];
#if 0
strcpy(b, a); /* causes buffer overrun (undefined behavior), so do not execute this here! */
#endif
snprintf(b, sizeof(b), "%s", a); /* does not cause buffer overrun */
printf("%s\n", b); /* "0123456" will be printed */
return 0;
}
strncat()
एक दूसरा विकल्प, बेहतर प्रदर्शन के साथ, strncat()
(एक बफर अतिप्रवाह जाँच strcat()
का संस्करण) का उपयोग करना है - यह एक तीसरा तर्क लेता है जो इसे कॉपी करने के लिए बाइट्स की अधिकतम संख्या बताता है:
char dest[32];
dest[0] = '\0';
strncat(dest, source, sizeof(dest) - 1);
/* copies up to the first (sizeof(dest) - 1) elements of source into dest,
then puts a \0 on the end of dest */
ध्यान दें कि यह सूत्रीकरण sizeof(dest) - 1
उपयोग करता है sizeof(dest) - 1
; यह महत्वपूर्ण है क्योंकि strncat()
हमेशा एक अशक्त बाइट (अच्छा) जोड़ता है, लेकिन यह गणना नहीं करता है कि स्ट्रिंग के आकार में (भ्रम का कारण और बफर अधिलेखित)।
यह भी ध्यान दें कि विकल्प - एक गैर-खाली स्ट्रिंग के बाद समतल करना - और भी अधिक भयावह है। विचार करें:
char dst[24] = "Clownfish: ";
char src[] = "Marvin and Nemo";
size_t len = strlen(dst);
strncat(dst, src, sizeof(dst) - len - 1);
printf("%zu: [%s]\n", strlen(dst), dst);
आउटपुट है:
23: [Clownfish: Marvin and N]
ध्यान दें, हालांकि, लंबाई के रूप में निर्दिष्ट आकार गंतव्य सरणी का आकार नहीं था, लेकिन टर्मिनल नल बाइट की गिनती नहीं करते हुए, इसमें जितनी जगह बची है, उतनी नहीं है। इससे बड़ी ओवरराइटिंग की समस्या हो सकती है। यह थोड़ा व्यर्थ भी है; लंबाई तर्क को सही ढंग से निर्दिष्ट करने के लिए, आप गंतव्य में डेटा की लंबाई जानते हैं, इसलिए आप मौजूदा सामग्री के अंत में नल बाइट के पते को निर्दिष्ट कर सकते हैं, जिससे strncat()
को फिर से खोलने से बचाया जा सकता है:
strcpy(dst, "Clownfish: ");
assert(len < sizeof(dst) - 1);
strncat(dst + len, src, sizeof(dst) - len - 1);
printf("%zu: [%s]\n", strlen(dst), dst);
यह पहले जैसा ही आउटपुट तैयार करता है, लेकिन strncat()
को कॉपी करने से पहले dst
की मौजूदा सामग्री पर स्कैन नहीं करना पड़ता है।
strncpy()
अंतिम विकल्प strncpy()
फ़ंक्शन है। यद्यपि आप सोच सकते हैं कि यह पहले आना चाहिए, यह एक बल्कि भ्रामक कार्य है जिसमें दो मुख्य समूह हैं:
- यदि
strncpy()
माध्यम से कॉपी करनाstrncpy()
बफर सीमा को हिट करता है, तो एक समाप्ति नल-वर्ण नहीं लिखा जाएगा। -
strncpy()
हमेशा पूरी तरह से गंतव्य को भर देता है, यदि आवश्यक हो तो शून्य बाइट्स के साथ।
(इस तरह का विलक्षण कार्यान्वयन ऐतिहासिक है और शुरू में UNIX फ़ाइल नामों को संभालने के लिए बनाया गया था )
इसका उपयोग करने का एकमात्र सही तरीका यह है कि मैन्युअल रूप से शून्य-समाप्ति सुनिश्चित करें:
strncpy(b, a, sizeof(b)); /* the third parameter is destination buffer size */
b[sizeof(b)/sizeof(*b) - 1] = '\0'; /* terminate the string */
printf("%s\n", b); /* "0123456" will be printed */
फिर भी, यदि आपके पास एक बड़ा बफर है, तो अतिरिक्त अशक्त गद्दी के कारण strncpy()
का उपयोग करना बहुत अक्षम हो जाता है।
स्ट्रिंग्स को संख्या में बदलें: atoi (), atof () (खतरनाक, उनका उपयोग न करें)
चेतावनी: कार्यों atoi
, atol
, atoll
और atof
: स्वाभाविक रूप से असुरक्षित है क्योंकि कर रहे हैं, परिणाम का मूल्य नहीं दर्शाया जा सकता है, तो व्यवहार अपरिभाषित है। (7.20.1p1)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
int val;
if (argc < 2)
{
printf("Usage: %s <integer>\n", argv[0]);
return 0;
}
val = atoi(argv[1]);
printf("String value = %s, Int value = %d\n", argv[1], val);
return 0;
}
जब परिवर्तित की जाने वाली स्ट्रिंग एक मान्य दशमलव पूर्णांक है जो सीमा में है, तो फ़ंक्शन काम करता है:
$ ./atoi 100
String value = 100, Int value = 100
$ ./atoi 200
String value = 200, Int value = 200
किसी संख्या के साथ शुरू होने वाले तार के लिए, उसके बाद कुछ और, केवल प्रारंभिक संख्या को पार्स किया जाता है:
$ ./atoi 0x200
0
$ ./atoi 0123x300
123
अन्य सभी मामलों में, व्यवहार अपरिभाषित है:
$ ./atoi hello
Formatting the hard disk...
उपरोक्त अस्पष्टताओं और इस अपरिभाषित व्यवहार के कारण, कार्यों के atoi
परिवार का उपयोग कभी नहीं किया जाना चाहिए।
- कन्वर्ट करने के लिए
long int
, उपयोगstrtol()
के बजायatol()
। -
double
बदलने के लिए,strtod()
बजायatof()
।
-
long long int
बदलने के लिए,atoll()
बजायstrtoll()
उपयोग करें।
स्ट्रिंग स्वरूपित डेटा पढ़ने / लिखने
स्ट्रिंग के लिए स्वरूपित डेटा लिखें
int sprintf ( char * str, const char * format, ... );
स्ट्रिंग के लिए फ्लोट डेटा लिखने के लिए sprintf
फ़ंक्शन का उपयोग करें।
#include <stdio.h>
int main ()
{
char buffer [50];
double PI = 3.1415926;
sprintf (buffer, "PI = %.7f", PI);
printf ("%s\n",buffer);
return 0;
}
स्ट्रिंग से स्वरूपित डेटा पढ़ें
int sscanf ( const char * s, const char * format, ...);
डेटा स्वरूपित करने के लिए sscanf
फ़ंक्शन का उपयोग करें।
#include <stdio.h>
int main ()
{
char sentence []="date : 06-06-2012";
char str [50];
int year;
int month;
int day;
sscanf (sentence,"%s : %2d-%2d-%4d", str, &day, &month, &year);
printf ("%s -> %02d-%02d-%4d\n",str, day, month, year);
return 0;
}
स्ट्रिंग्स को संख्या में परिवर्तित करें: स्ट्रेटोक्स फ़ंक्शंस
C99 के बाद से C लाइब्रेरी में सुरक्षित रूपांतरण फ़ंक्शन का एक सेट है जो एक स्ट्रिंग को संख्या के रूप में व्याख्या करता है। उनके नाम strtoX
के रूप में हैं, जहाँ X
, l
, ul
, d
आदि में से एक है, जो लक्ष्य प्रकार का रूपांतरण निर्धारित करता है
double strtod(char const* p, char** endptr);
long double strtold(char const* p, char** endptr);
वे जाँचते हैं कि रूपांतरण में अधिक या कम प्रवाह था:
double ret = strtod(argv[1], 0); /* attempt conversion */
/* check the conversion result. */
if ((ret == HUGE_VAL || ret == -HUGE_VAL) && errno == ERANGE)
return; /* numeric overflow in in string */
else if (ret == HUGE_VAL && errno == ERANGE)
return; /* numeric underflow in in string */
/* At this point we know that everything went fine so ret may be used */
यदि वास्तव में स्ट्रिंग में कोई संख्या नहीं है, तो strtod
का यह उपयोग 0.0
।
यदि यह संतोषजनक नहीं है, तो अतिरिक्त पैरामीटर endptr
का उपयोग किया जा सकता है। यह एक पॉइंटर को पॉइंटर है जो स्ट्रिंग में पाए गए नंबर के अंत में बताया जाएगा। यदि इसे 0
सेट किया गया है, जैसा कि ऊपर, या NULL
, तो इसे केवल अनदेखा कर दिया गया है।
यह endptr
पैरामीटर संकेत देता है कि क्या कोई सफल रूपांतरण हुआ है और यदि ऐसा है, जहां संख्या समाप्त हो गई है:
char *check = 0;
double ret = strtod(argv[1], &check); /* attempt conversion */
/* check the conversion result. */
if (argv[1] == check)
return; /* No number was detected in string */
else if ((ret == HUGE_VAL || ret == -HUGE_VAL) && errno == ERANGE)
return; /* numeric overflow in in string */
else if (ret == HUGE_VAL && errno == ERANGE)
return; /* numeric underflow in in string */
/* At this point we know that everything went fine so ret may be used */
व्यापक पूर्णांक प्रकारों में परिवर्तित करने के लिए समान कार्य हैं:
long strtol(char const* p, char** endptr, int nbase);
long long strtoll(char const* p, char** endptr, int nbase);
unsigned long strtoul(char const* p, char** endptr, int nbase);
unsigned long long strtoull(char const* p, char** endptr, int nbase);
इन फ़ंक्शंस में एक तीसरा पैरामीटर nbase
होता है जो नंबर बेस रखता है जिसमें नंबर लिखा होता है।
long a = strtol("101", 0, 2 ); /* a = 5L */
long b = strtol("101", 0, 8 ); /* b = 65L */
long c = strtol("101", 0, 10); /* c = 101L */
long d = strtol("101", 0, 16); /* d = 257L */
long e = strtol("101", 0, 0 ); /* e = 101L */
long f = strtol("0101", 0, 0 ); /* f = 65L */
long g = strtol("0x101", 0, 0 ); /* g = 257L */
nbase
लिए विशेष मान 0
अर्थ है स्ट्रिंग को उसी तरह से व्याख्या किया गया है जैसे कि सी प्रोग्राम में नंबर शाब्दिक व्याख्या की गई है: 0x
का एक उपसर्ग हेक्साडेसिमल प्रतिनिधित्व से मेल खाता है, अन्यथा एक अग्रणी 0
अष्टक है और सभी संख्याओं को दशमलव के रूप में देखा जाता है।
इस प्रकार कमांड-लाइन तर्क को एक संख्या के रूप में व्याख्या करने का सबसे व्यावहारिक तरीका होगा
int main(int argc, char* argv[] {
if (argc < 1)
return EXIT_FAILURE; /* No number given. */
/* use strtoull because size_t may be wide */
size_t mySize = strtoull(argv[1], 0, 0);
/* then check conversion results. */
...
return EXIT_SUCCESS;
}
इसका मतलब है कि कार्यक्रम को ऑक्टल, दशमलव या हेक्साडेसिमल में एक पैरामीटर के साथ कहा जा सकता है।