স্ট্রিং আক্ষরিক দিয়ে শুরু করে "চর * গুলি" লিখতে গিয়ে কেন আমি বিভাগের ত্রুটি পাই, তবে "চর এস []" নয়?


287

নিম্নলিখিত কোডটি লাইন 2 তে সেগ ফল্ট গ্রহণ করে:

char *str = "string";
str[0] = 'z';  // could be also written as *str = 'z'
printf("%s\n", str);

যদিও এটি পুরোপুরি ভালভাবে কাজ করে:

char str[] = "string";
str[0] = 'z';
printf("%s\n", str);

এমএসভিসি এবং জিসিসির সাথে পরীক্ষিত।


1
এটি মজার - তবে ভিজ্যুয়াল স্টুডিও বিকাশকারী কমান্ড প্রম্পটে উইন্ডোজ সংকলক (সিএল) ব্যবহার করার সময় এটি আসলে সংকলন করে এবং পুরোপুরি চলে। আমাকে কয়েক মুহুর্তের জন্য বিভ্রান্ত করে ফেলেছে ...
ডেভিড রেফেলি

উত্তর:


241

সি এফএকিউ দেখুন, প্রশ্ন 1.32

প্রশ্ন : এই আরম্ভের মধ্যে পার্থক্য কী?
char a[] = "string literal";
char *p = "string literal";
যদি আমি কোনও নতুন মান নির্ধারণের চেষ্টা করি তবে আমার প্রোগ্রামটি ক্র্যাশ হয়ে গেছে p[i]

উত্তর : একটি স্ট্রিং আক্ষরিক (সি উত্সে ডাবল-কোটড স্ট্রিংয়ের আনুষ্ঠানিক শব্দ) দুটি কিছুটা ভিন্ন উপায়ে ব্যবহার করা যেতে পারে:

  1. চরের অ্যারের প্রাথমিক হিসাবে, যেমনটি ঘোষণাপত্রে char a[], এটি সেই অ্যারের অক্ষরের প্রাথমিক মানগুলি নির্দিষ্ট করে (এবং, প্রয়োজনে এর আকার)।
  2. অন্য কোথাও, এটি একটি নামবিহীন, অক্ষরগুলির স্ট্যাটিক অ্যারেতে পরিণত হয় এবং এই নামবিহীন অ্যারেটি কেবল পঠনযোগ্য মেমরিতে সংরক্ষণ করা যেতে পারে এবং যার ফলে অগত্যা সংশোধন করা যায় না। একটি অভিব্যক্তির প্রসঙ্গে অ্যারেটি যথারীতি একবারে পয়েন্টারে রূপান্তরিত হয় (বিভাগটি দেখুন 6), সুতরাং দ্বিতীয় ঘোষণার নামটি অজ্ঞাতনামা অ্যারের প্রথম উপাদানটির দিকে নির্দেশ করতে পি আরম্ভ করে।

কিছু সংকলকের স্ট্রিং লিটারালগুলি লেখার যোগ্য কিনা (পুরানো কোডটি সংকলনের জন্য) নিয়ন্ত্রণ করে এবং কারও কারও কাছে স্ট্রিং লিটারালগুলি আনুষ্ঠানিকভাবে কনস্ট চরের অ্যারে হিসাবে গণ্য করার কারণ হতে পারে (আরও ভাল ত্রুটি ধরা পড়ার জন্য)।


7
অন্যান্য পয়েন্টগুলির যুগল: (1) সেগফল্ট বর্ণিত হিসাবে ঘটে তবে এর উপস্থিতি রান পরিবেশের একটি ক্রিয়াকলাপ; যদি একই কোডটি এম্বেড করা সিস্টেমে থাকে তবে লেখার কোনও প্রভাব থাকতে পারে, বা এটি আসলে গুলিটিকে একটি জেডে রূপান্তর করতে পারে। (২) স্ট্রিং লিটারেলগুলি অ-লিখনযোগ্য হওয়ায়, সংকলক একই জায়গায় "স্ট্রিং" এর দুটি উদাহরণ স্থাপন করে স্থান বাঁচাতে পারে; বা, কোডটিতে অন্য কোথাও যদি আপনার "অন্য স্ট্রিং" থাকে, তবে মেমরির একটি অংশ উভয় অক্ষরকে সমর্থন করতে পারে। স্পষ্টতই, যদি কোডটি সেই বাইটগুলি পরিবর্তন করার অনুমতি দেওয়া হয়, তবে অদ্ভুত এবং কঠিন বাগগুলি ঘটতে পারে।
গ্রেগগো

1
@ গ্রেগগো: ভালো কথা। mprotectকেবলমাত্র পঠনযোগ্য সুরক্ষা তরঙ্গ ব্যবহার করে এমএমইউ সহ সিস্টেমে এটি করার একটি উপায়ও রয়েছে ( এখানে দেখুন )।

সুতরাং চর * পি = "ব্লাহ" আসলে একটি অস্থায়ী অ্যারে তৈরি করে?
রাহুল তায়াগি

1
এবং সি ++ এ 2 বছর লেখার পরে ...
TIL

@ আরহ্যাক্ট্যাগি মানে কি?
সুরজ জৈন

105

সাধারণত প্রোগ্রামটি চলাকালীন স্ট্রিং লিটারালগুলি কেবল পঠনযোগ্য মেমরিতে সংরক্ষণ করা হয়। এটি আপনাকে দুর্ঘটনাক্রমে কোনও স্ট্রিং ধ্রুবক পরিবর্তন করা থেকে বিরত রাখতে। আপনার প্রথম উদাহরণে, "string"কেবল পঠনযোগ্য মেমরির মধ্যে সঞ্চয় করা *strহয় এবং প্রথম অক্ষরকে নির্দেশ করে। আপনি যখন প্রথম চরিত্রটিতে পরিবর্তন করার চেষ্টা করবেন তখন সেগফল্টটি ঘটে 'z'

দ্বিতীয় উদাহরণে, স্ট্রিং "string"হয় কপি তার শুধুমাত্র পাঠযোগ্য বাসা থেকে কম্পাইলার দ্বারা str[]অ্যারে। তারপরে প্রথম চরিত্রটি পরিবর্তন করার অনুমতি রয়েছে। আপনি প্রত্যেকের ঠিকানা মুদ্রণ করে এটি পরীক্ষা করতে পারেন:

printf("%p", str);

এছাড়াও, strদ্বিতীয় উদাহরণের আকার মুদ্রণ আপনাকে দেখায় যে সংকলকটির জন্য এটি 7 বাইট বরাদ্দ করেছে:

printf("%d", sizeof(str));

13
প্রিন্টফের উপর যখনই "% p" ব্যবহার করা হচ্ছে, আপনার মুদ্রকটি প্রিন্টফের মতো অকার্যকর * করতে হবে ("% পি", (শূন্য *) টিআর); প্রিন্টফের সাথে একটি সাইজ_টি মুদ্রণের সময়, সর্বশেষ সি স্ট্যান্ডার্ড (সি 99) ব্যবহার করা আপনার "% zu" ব্যবহার করা উচিত।
ক্রিস ইয়ং

4
এছাড়াও, আকারের প্রথম বন্ধনীগুলি কেবলমাত্র কোনও ধরণের আকার নেওয়ার সময় প্রয়োজন হয় (যুক্তিটি তখন castালার মতো লাগে)। মনে রাখবেন যে আকারটি একটি অপারেটর, কোনও ফাংশন নয়।
বিনোদন


34

এই উত্তরগুলির বেশিরভাগই সঠিক, তবে আরও কিছুটা স্পষ্ট করার জন্য ...

লোকেরা "কেবল পঠনযোগ্য স্মৃতি" উল্লেখ করছে এটি হ'ল এএসএম পদগুলির পাঠ্য বিভাগ। এটি মেমরির একই স্থান যেখানে নির্দেশাবলী লোড করা হয়। এটি সুরক্ষার মতো সুস্পষ্ট কারণে কেবল পঠনযোগ্য। আপনি যখন একটি স্ট্রিংকে আরম্ভ করা চর * তৈরি করেন, তখন স্ট্রিং ডেটা পাঠ্য বিভাগে সংকলিত হয় এবং প্রোগ্রামটি পাঠ্য বিভাগে নির্দেশ করতে পয়েন্টারকে আরম্ভ করে। সুতরাং আপনি যদি এটি পরিবর্তন করার চেষ্টা করেন, কবুম। Segfault।

যখন অ্যারে হিসাবে লেখা হয়, সংকলক পরিবর্তে ডেটা বিভাগে সূচনাযুক্ত স্ট্রিং ডেটা রাখে, এটি একই স্থান যা আপনার বৈশ্বিক চলক এবং যেমন লাইভ। ডেটা বিভাগে কোনও নির্দেশনা নেই বলে এই মেমরিটি পরিবর্তনযোগ্য। এবার যখন সংকলক অক্ষর অ্যারের সূচনা করে (এটি এখনও কেবল একটি চর *) এটি পাঠ্য বিভাগের চেয়ে ডেটা বিভাগে নির্দেশ করছে, যা আপনি রান-টাইমে নিরাপদে পরিবর্তন করতে পারবেন।


তবে এটি কি সত্য নয় যে এমন বাস্তবায়ন হতে পারে যা "কেবলমাত্র পঠনযোগ্য মেমরি" সংশোধন করতে পারে?
পেসারিয়ার

অ্যারে হিসাবে লেখা হয়ে গেলে, সংকলকটি স্ট্যাটিক বা গ্লোবাল হলে ডেটা বিভাগে প্রারম্ভিক স্ট্রিং ডেটা রাখে। অন্যথায় (যেমন একটি সাধারণ স্বয়ংক্রিয় অ্যারের জন্য) এটি ফাংশন প্রধানের স্ট্যাক ফ্রেমে স্ট্যাকের উপরে রাখে। সঠিক?
এসই

26

স্ট্রিংয়ে লেখার সময় কেন আমি সেগমেন্টেশন ত্রুটি পেতে পারি?

C99 N1256 খসড়া

অক্ষর স্ট্রিং আক্ষরিক দুটি ভিন্ন ব্যবহার আছে:

  1. আরম্ভ করুন char[]:

    char c[] = "abc";      

    এটি "আরও যাদু" এবং 6..7.৮ / ১৪ "ইনিশিয়ালাইজেশন" এ বর্ণিত:

    অক্ষরের ধরণের একটি অ্যারে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে অক্ষরে সংযুক্ত করা যেতে পারে। অক্ষরের স্ট্রিং আক্ষরিকের ধারাবাহিক অক্ষর (ঘর থাকলে অবিরাম আকারে টার্মিনেটিং নাল চরিত্র সহ) অ্যারের উপাদানগুলির সূচনা করে।

    সুতরাং এটি কেবল একটি শর্টকাট:

    char c[] = {'a', 'b', 'c', '\0'};

    অন্য কোনও নিয়মিত অ্যারের মতো, cপরিবর্তন করা যেতে পারে।

  2. অন্য যে কোনও জায়গায়: এটি একটি উত্পন্ন করে:

    সুতরাং আপনি যখন লিখুন:

    char *c = "abc";

    এটি এর অনুরূপ:

    /* __unnamed is magic because modifying it gives UB. */
    static char __unnamed[] = "abc";
    char *c = __unnamed;

    নোট থেকে অন্তর্নিহিত ঢালাই char[]করার char *, যা সবসময় বৈধ।

    তারপরে আপনি যদি সংশোধন করেন c[0], __unnamedআপনিও সংশোধন করুন , যা ইউবি।

    এটি 6.4.5 "স্ট্রিং লিটারালস" এ নথিভুক্ত করা হয়েছে:

    5 অনুবাদ পর্বে 7-এ, বাইট বা মান শূন্যের কোডটি প্রতিটি মাল্টবাইট চরিত্রের অনুক্রমের সাথে যুক্ত হয় যা স্ট্রিং আক্ষরিক বা আক্ষরিক থেকে ফলাফল results মাল্টিবাইট চরিত্রের সিক্যুয়েন্সটি তখন স্ট্যাটিক স্টোরেজ সময়কাল এবং সিক্যুয়েন্সটি পর্যাপ্ত রাখার জন্য যথেষ্ট দৈর্ঘ্যের একটি অ্যারে শুরু করার জন্য ব্যবহৃত হয়। চরিত্রের স্ট্রিং লিটারালগুলির জন্য, অ্যারের উপাদানগুলিতে টাইপ চর থাকে এবং মাল্টিবাইট অক্ষর ক্রমের পৃথক বাইটগুলির সাথে আরম্ভ করা হয় [...]

    These এই অ্যারেগুলি পৃথক পৃথক কিনা এগুলি নির্ধারিত নয় যদি তাদের উপাদানগুলির উপযুক্ত মান থাকে। প্রোগ্রামটি যদি এমন অ্যারে সংশোধন করার চেষ্টা করে তবে আচরণটি সংজ্ঞায়িত।

Initial.7.৮ / ৩২ "ইনিশিয়ালাইজেশন" এর প্রত্যক্ষ উদাহরণ দেয়:

উদাহরণ 8: ঘোষণা

char s[] = "abc", t[3] = "abc";

"প্লেইন" চর অ্যারে অবজেক্টগুলি সংজ্ঞায়িত করে sএবং tযার উপাদানগুলি অক্ষর স্ট্রিং ল্যাটারাল দিয়ে শুরু করা হয়।

এই ঘোষণাটি সমান

char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };

অ্যারের সামগ্রীগুলি পরিবর্তনযোগ্য if অন্যদিকে, ঘোষণা

char *p = "abc";

p"পয়েন্টার টু চর" টাইপ দিয়ে সংজ্ঞায়িত করে এবং এটি দৈর্ঘ্য 4 দিয়ে "চরের অ্যারে" টাইপযুক্ত কোনও অবজেক্টের দিকে নির্দেশ করতে ইনিশিয়াল করে যার উপাদানগুলি একটি অক্ষরের স্ট্রিং আক্ষরিক দিয়ে প্রাথমিক হয়। pঅ্যারের বিষয়বস্তুগুলি সংশোধন করার জন্য যদি চেষ্টা করা হয় , তবে আচরণটি সংজ্ঞায়িত।

জিসিসি 4.8 x86-64 ইএলএফ বাস্তবায়ন

কার্যক্রম:

#include <stdio.h>

int main(void) {
    char *s = "abc";
    printf("%s\n", s);
    return 0;
}

সংকলন এবং পচনশীল:

gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o

আউটপুট রয়েছে:

 char *s = "abc";
8:  48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
f:  00 
        c: R_X86_64_32S .rodata

উপসংহার: জিসিসি char*এটিকে .rodataবিভাগে রাখে, না .text

আমরা যদি এর জন্য একই করি char[]:

 char s[] = "abc";

আমরা প্রাপ্ত:

17:   c7 45 f0 61 62 63 00    movl   $0x636261,-0x10(%rbp)

সুতরাং এটি স্ট্যাকের মধ্যে (আপেক্ষিক %rbp) সঞ্চিত হয় ।

তবে খেয়াল করুন যে ডিফল্ট লিঙ্কার স্ক্রিপ্টটি একই বিভাগে রাখে .rodataএবং এতে .textলেখার অনুমতি নেই। এটি দিয়ে পর্যবেক্ষণ করা যেতে পারে:

readelf -l a.out

যেটা বহন করে:

 Section to Segment mapping:
  Segment Sections...
   02     .text .rodata

17

প্রথম কোডে, "স্ট্রিং" একটি স্ট্রিং ধ্রুবক এবং স্ট্রিং ধ্রুবকগুলি কখনই সংশোধন করা উচিত নয় কারণ এগুলি প্রায়শই কেবল পঠনযোগ্য মেমরির মধ্যে স্থাপন করা হয়। "str" ​​হল একটি পয়েন্টার যা ধ্রুবকটি পরিবর্তন করতে ব্যবহৃত হয়।

দ্বিতীয় কোডে, "স্ট্রিং" হল একটি অ্যারে ইনিশিয়ালাইজার, এর জন্য সংক্ষিপ্ত হাতের সাজান

char str[7] =  { 's', 't', 'r', 'i', 'n', 'g', '\0' };

"স্ট্রিং" স্ট্যাকের জন্য বরাদ্দ করা একটি অ্যারে এবং অবাধে পরিবর্তন করা যেতে পারে।


1
স্ট্যাকে বা ডেটা বিভাগে যদি strবিশ্বব্যাপী বা হয় static
গৌথির

12

কারণ "whatever"1 ম উদাহরণের প্রসঙ্গে প্রকারের ধরনটি const char *(এমনকি আপনি এটি একটি অ-কন্সট চরকে * অর্পণ করলেও), যার অর্থ আপনার চেষ্টা করা এবং এটি লেখার চেষ্টা করা উচিত নয়।

সংকলক মেমরির কেবল পঠনযোগ্য অংশে স্ট্রিংটি রেখে এটি প্রয়োগ করেছে, সুতরাং এটিতে লিখে একটি সেগফল্ট তৈরি করে।


8

এই ত্রুটি বা সমস্যাটি বোঝার জন্য আপনাকে প্রথমে পার্থক্য b / w এর পয়েন্টার এবং অ্যারে সম্পর্কে জানতে হবে সুতরাং প্রথমে আমি আপনাকে বি পার্থক্য বি / ডব্লিউটি ব্যাখ্যা করব

স্ট্রিং অ্যারে

 char strarray[] = "hello";

মেমরিতে অ্যারে অবিচ্ছিন্ন মেমরি কোষে সংরক্ষণ করা [h][e][l][l][o][\0] =>[]হয়, 1 চর বাইট আকারের মেমরি কোষ হিসাবে সঞ্চিত থাকে এবং এই ধারাবাহিক মেমরি কোষগুলি স্ট্র্রে নামে নামেই অ্যাক্সেস করতে পারে so সুতরাং এখানে স্ট্রিংয়ের strarrayসমস্ত অক্ষর যুক্ত স্ট্রিং অ্যারে নিজেই এটি.আই.টি. এখানে কেস করুন "hello" যাতে আমরা প্রতিটি অক্ষরকে তার সূচক মানের দ্বারা অ্যাক্সেস করে সহজেই এর স্মৃতি সামগ্রী পরিবর্তন করতে পারি

`strarray[0]='m'` it access character at index 0 which is 'h'in strarray

এবং এর মান পরিবর্তিত হয়ে 'm'স্ট্রেয়ের মানতে পরিবর্তিত হয়েছে "mello";

এখানে একটি বিষয় লক্ষণীয় যে আমরা অক্ষরে অক্ষরে অক্ষরে অক্ষরে স্ট্রিং অ্যারের সামগ্রী পরিবর্তন করতে পারি তবে অন্য স্ট্রিংটিকে সরাসরি এটির মতো আরম্ভ করতে পারি না এটি strarray="new string"অবৈধ is

ইশারা

যেহেতু আমরা সকলেই মেমরির মেমরির অবস্থানের জন্য পয়েন্টার পয়েন্টগুলি জানি, অবিচ্ছিন্ন পয়েন্টারটি এলোমেলোভাবে স্মৃতি অবস্থানের দিকে এবং সূচনাকরণের পরে নির্দিষ্ট মেমরির স্থানে নির্দেশ করে

char *ptr = "hello";

এখানে পয়েন্টার পিটিআরটি স্ট্রিংয়ে শুরু করা হয়েছে "hello"যা ধ্রুব স্ট্রিং কেবল পঠনযোগ্য মেমরি (রম) এ "hello"সংরক্ষণ করা হয় তাই এটি আরওএম-তে সংরক্ষিত থাকায় পরিবর্তন করা যায় না

এবং পিটিআর স্ট্যাক বিভাগে সঞ্চয় করা হয় এবং ধ্রুব স্ট্রিংয়ের দিকে নির্দেশ করে "hello"

সুতরাং ptr [0] = 'এম' অবৈধ কারণ আপনি কেবল পঠন মেমরিটিতে অ্যাক্সেস করতে পারবেন না

তবে পিটিআরটি অন্য স্ট্রিং মান থেকে সরাসরি সূচনা করা যেতে পারে কারণ এটি কেবলমাত্র পয়েন্টার তাই এটি তার ডেটা টাইপের ভেরিয়েবলের কোনও মেমরি ঠিকানার দিকে নির্দেশ করতে পারে

ptr="new string"; is valid

7
char *str = "string";  

উপরের সেটগুলি strআক্ষরিক মানের দিকে ইঙ্গিত করার জন্য "string"যা প্রোগ্রামের বাইনারি চিত্রটিতে হার্ড-কোডড হয়, যা সম্ভবত মেমরির মধ্যে কেবল পঠনযোগ্য হিসাবে চিহ্নিত করা হয়।

তাই str[0]=অ্যাপ্লিকেশনটির পঠনযোগ্য কোডটিতে লেখার চেষ্টা করা হচ্ছে। আমি মনে করি এটি সম্ভবত সংকলক নির্ভরশীল যদিও।


6
char *str = "string";

একটি স্ট্রিং আক্ষরিকের জন্য একটি পয়েন্টার বরাদ্দ করে, যা সংকলকটি আপনার এক্সিকিউটেবলের একটি অ-পরিবর্তনীয় অংশে রাখে;

char str[] = "string";

একটি স্থানীয় অ্যারে বরাদ্দ এবং প্রারম্ভিক যা পরিবর্তনযোগ্য


আমরা int *b = {1,2,3) যেমন লিখি তেমন লিখতে char *s = "HelloWorld"পারি?
সুরজ জৈন

6

সি এফএকিউ যা @ মাতলী এটির সাথে উল্লেখ করেছে, তবে এখানে অন্য কারও কাছে এখনও স্পষ্টতা নেই: একটি স্ট্রিং লিটারাল (যদি আপনার উত্সে ডাবল-কোট করা স্ট্রিং) একটি অক্ষর অ্যারে আরম্ভ করার জন্য অন্য কোথাও ব্যবহার করা হয় (যেমন: @ মার্কের দ্বিতীয় উদাহরণ, যা সঠিকভাবে কাজ করে), সেই স্ট্রিংটি কম্পাইলার দ্বারা একটি বিশেষ স্ট্যাটিক স্ট্রিং টেবিলের মধ্যে সংরক্ষণ করা হয় , যা গ্লোবাল স্ট্যাটিক ভেরিয়েবল তৈরি করার অনুরূপ (কেবল পঠনযোগ্য, অবশ্যই) বেনামে থাকে (কোনও পরিবর্তনশীল "নাম নেই" ")। শুধুমাত্র পাঠযোগ্য অংশ গুরুত্বপূর্ণ অংশ এবং কেন @ মার্ক প্রথম কোড উদাহরণস্বরূপ segfaults হয়।


আমরা int *b = {1,2,3) যেমন লিখি তেমন লিখতে char *s = "HelloWorld"পারি?
সুরজ জৈন

4

দ্য

 char *str = "string";

লাইন একটি পয়েন্টার সংজ্ঞায়িত করে এবং এটি আক্ষরিক স্ট্রিংয়ের দিকে নির্দেশ করে। আক্ষরিক স্ট্রিং লিখিত হয় না তাই আপনি যখন করবেন:

  str[0] = 'z';

আপনি একটি সেগ ত্রুটি পেতে। কিছু প্ল্যাটফর্মে, আক্ষরিক লিখনযোগ্য মেমরিতে থাকতে পারে তাই আপনি কোনও সেগফল্ট দেখতে পাবেন না, তবে এটি অবৈধ কোড (অনির্ধারিত আচরণের ফলে) নির্বিশেষে।

লাইন:

char str[] = "string";

অক্ষরের একটি অ্যারে বরাদ্দ করে এবং সেই অ্যারেতে আক্ষরিক স্ট্রিং অনুলিপি করে, যা সম্পূর্ণ লিখনযোগ্য, সুতরাং পরবর্তী আপডেটে কোনও সমস্যা নেই।


আমরা int *b = {1,2,3) যেমন লিখি তেমন লিখতে char *s = "HelloWorld"পারি?
সুরজ জৈন

3

"স্ট্রিং" এর মতো স্ট্রিং লিটারেলগুলি সম্ভবত কেবলমাত্র পঠনযোগ্য ডেটা হিসাবে আপনার এক্সিকিউটেবলের ঠিকানা স্পেসে বরাদ্দ করা হয় (আপনার সংকলক দিন বা নিন)। আপনি যখন এটি স্পর্শ করতে যান, এটি শিথিল করে যে আপনি তার স্নানের স্যুট অঞ্চলে রয়েছেন এবং আপনাকে সেগ দোষের সাথে জানাতে দেয়।

আপনার প্রথম উদাহরণে, আপনি এই কনস্ট ডেটাতে একটি পয়েন্টার পাচ্ছেন। আপনার দ্বিতীয় উদাহরণে, আপনি কনস্টের ডেটা অনুলিপি করে 7 টি অক্ষরের অ্যারে শুরু করছেন।


2
// create a string constant like this - will be read only
char *str_p;
str_p = "String constant";

// create an array of characters like this 
char *arr_p;
char arr[] = "String in an array";
arr_p = &arr[0];

// now we try to change a character in the array first, this will work
*arr_p = 'E';

// lets try to change the first character of the string contant
*str_p = 'G'; // this will result in a segmentation fault. Comment it out to work.


/*-----------------------------------------------------------------------------
 *  String constants can't be modified. A segmentation fault is the result,
 *  because most operating systems will not allow a write
 *  operation on read only memory.
 *-----------------------------------------------------------------------------*/

//print both strings to see if they have changed
printf("%s\n", str_p); //print the string without a variable
printf("%s\n", arr_p); //print the string, which is in an array. 

1

প্রথম স্থানে, strএকটি পয়েন্টার যা নির্দেশ করে "string"। সংকলকটিকে মেমরিতে এমন জায়গায় স্ট্রিং লিটারেল রাখার অনুমতি দেওয়া হয়েছে যা আপনি লিখতে পারবেন না তবে কেবল পড়তে পারবেন। (এই সত্যিই একটি সতর্কবার্তা আলোড়ন সৃষ্টি উচিত ছিল, যেহেতু আপনি একটি বরাদ্দ করছি const char *একটি থেকে char *। আপনি কি সতর্কবার্তা নিষ্ক্রিয় করে দিয়েছি, অথবা আপনি শুধু তাদের উপেক্ষা হয়নি?)

দ্বিতীয় স্থানে, আপনি একটি অ্যারে তৈরি করছেন যা মেমরি যা আপনার সম্পূর্ণ অ্যাক্সেস পেয়েছিল এবং এটি দিয়ে আরম্ভ করা হচ্ছে "string"। আপনি একটি char[7](অক্ষরের ছয়টি, '\ 0' অবসানের জন্য একটি ) তৈরি করছেন এবং আপনি এটির সাথে যা খুশি তা করতে পারেন।


@ ফের্রুসিও,? হ্যাঁconst উপসর্গটি কেবলমাত্র পঠনযোগ্য-কেবল
পঠনযোগ্য করে তোলে

সি স্ট্রিংয়ে আক্ষরিক টাইপ আছে char [N], নেই const char [N]তাই কোনও সতর্কতা নেই। (আপনি কমপক্ষে পাস করে -Wwrite-strings
জিসিসিতে

0

ধরুন স্ট্রিংগুলি হ'ল,

char a[] = "string literal copied to stack";
char *p  = "string literal referenced by p";

প্রথম ক্ষেত্রে, আক্ষরিকটি অনুলিপি করতে হয় যখন 'এ' সুযোগে আসে। এখানে 'ক' স্ট্যাকের উপর সংজ্ঞায়িত একটি অ্যারে। এর অর্থ স্ট্যাকের উপর স্ট্রিং তৈরি হবে এবং এর ডেটা কোড (পাঠ্য) মেমরি থেকে অনুলিপি করা হয়েছে যা সাধারণত পঠনযোগ্য (এটি বাস্তবায়নের নির্দিষ্টকরণ, একটি সংকলক এই পঠনযোগ্য প্রোগ্রামের ডেটা কেবল পঠনযোগ্য মেমরিতেও রাখতে পারে )।

দ্বিতীয় ক্ষেত্রে, পি একটি পয়েন্টার যা স্ট্যাকের (স্থানীয় স্কোপ) উপর সংজ্ঞায়িত করা হয় এবং স্ট্রিং আক্ষরিক (প্রোগ্রাম ডেটা বা পাঠ্য) উল্লেখ করা হয় যেখানে অন্য কোনও স্থানে রয়েছে। সাধারণত এ জাতীয় স্মৃতি পরিবর্তন করা ভাল অনুশীলন বা উত্সাহিত হয় না।


-1

প্রথমটি হ'ল একটি ধ্রুব স্ট্রিং যা পরিবর্তিত হতে পারে না। দ্বিতীয়টি প্রাথমিক মান সহ একটি অ্যারে, তাই এটি সংশোধন করা যায়।


-2

আপনি অ্যাক্সেসযোগ্য যা মেমরি অ্যাক্সেস করার চেষ্টা করার সময় বিভাজন ত্রুটি ঘটে।

char *str একটি স্ট্রিংয়ের পয়েন্টার যা অবিচ্ছেদ্য (সেগফল্ট পাওয়ার কারণ)।

যদিও char str[]এটি একটি অ্যারে এবং পরিবর্তনযোগ্য হতে পারে ..

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.