C তে চর অ্যারে এবং চর পয়েন্টারের মধ্যে পার্থক্য কী?


216

আমি সি-তে পয়েন্টারগুলি বোঝার চেষ্টা করছি তবে আমি বর্তমানে নিম্নলিখিতগুলির সাথে বিভ্রান্ত রয়েছি:

  • char *p = "hello"

    এটি অক্ষরের অ্যারেতে নির্দেশক একটি চর পয়েন্টার, এইচ থেকে শুরু হবে ।

  • char p[] = "hello"

    এটি হ্যালো সঞ্চয় করে এমন একটি অ্যারে ।

আমি যখন এই ফাংশনটিতে এই দুটি ভেরিয়েবলগুলি পাস করি তখন কী পার্থক্য হয়?

void printSomething(char *p)
{
    printf("p: %s",p);
}

5
এটি বৈধ হবে না: char p[3] = "hello";আপনি যে অ্যারে ঘোষণা করেন তার আকারের জন্য আরম্ভকারী স্ট্রিং খুব দীর্ঘ। ভুল টাইপ করেছেন?
কোডি গ্রে

16
বা শুধু char p[]="hello";যথেষ্ট হবে!
ডিপডাইভ


1
চার্জের [] এবং সিআর চর * এর মধ্যে পার্থক্য কী এর সম্ভাব্য নকল ? সত্য, এটি ফাংশন প্যারামিটার সম্পর্কেও বিশেষভাবে জিজ্ঞাসা করে, তবে এটি charনির্দিষ্ট নয় ।
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

1
আপনার বুঝতে হবে যে তারা মূলত আলাদা। এর মধ্যে একমাত্র সাধারণতা হ'ল অ্যারি পি এর ভিত্তি [[] একটি কনস্ট পয়েন্টার যা একটি পয়েন্টারের মাধ্যমে অ্যারে পি []] অ্যাক্সেস করতে সক্ষম করে। পি [] নিজেই একটি স্ট্রিংয়ের জন্য মেমরি ধারণ করে, যেখানে * পি কেবলমাত্র একটি চিয়ারের প্রথম উপাদানটির ঠিকানা দেখায় (অর্থাত্ ইতিমধ্যে বরাদ্দ স্ট্রিংয়ের গোড়ায় নির্দেশ করে)। এটির আরও ভালভাবে বর্ণনা করার জন্য নীচে বিবেচনা করুন: চর * সিপিটি = {'এইচ', 'ই', 'এল', 'এল', 'ও', '\ 0'}; ==> এটি একটি ত্রুটি, কারণ সিপিটিআর কেবল একটি চরিত্রের সিবিফের পয়েন্টার []] = {'এইচ', 'ই', 'এল', 'ল', 'ও', '\ 0'}; ==> এটি ঠিক আছে, bcos cBuff নিজেই একটি চর অ্যারে
Ilavarasan

উত্তর:


222

char*এবং char[] বিভিন্ন ধরণের , তবে এটি সমস্ত ক্ষেত্রে অবিলম্বে স্পষ্ট হয় না। এটি কারণ পয়েন্টারগুলিতে অ্যারে ক্ষয় হয় , এর অর্থ char[]হ'ল যদি ধরণের কোনও অভিব্যক্তি সরবরাহ করা হয় যেখানে এক ধরণের char*প্রত্যাশা থাকে, সংকলক স্বয়ংক্রিয়ভাবে অ্যারেটিকে তার প্রথম উপাদানটিতে পয়েন্টারে রূপান্তরিত করে।

আপনার উদাহরণ ফাংশনটি printSomethingএকটি পয়েন্টারের প্রত্যাশা করে, সুতরাং আপনি যদি এটির মতো কোনও অ্যারে পাস করার চেষ্টা করেন:

char s[10] = "hello";
printSomething(s);

সংকলক ভান করে যে আপনি এটি লিখেছেন:

char s[10] = "hello";
printSomething(&s[0]);

2012 থেকে এখন পর্যন্ত কি কিছু পরিবর্তন হয়েছে। একটি চরিত্রের অ্যারে "s" এর জন্য পুরো অ্যারে মুদ্রণ করে .. যেমন, "হ্যালো"
ভানু তেজ

@ ভানুটিজ না, কীভাবে তথ্য সংরক্ষণ করা হয় এবং ডেটা দিয়ে কী করা হয় তা পৃথক উদ্বেগ। এই উদাহরণটি পুরো স্ট্রিংটি প্রিন্ট করে কারণ ফর্ম্যাট স্ট্রিংটি এভাবে printfপরিচালনা করে %s: প্রদত্ত ঠিকানায় শুরু করুন এবং নাল টার্মিনেটরের মুখ না হওয়া পর্যন্ত চালিয়ে যান continue আপনি যদি কেবল একটি অক্ষর মুদ্রণ করতে চান তবে আপনি %cফর্ম্যাট স্ট্রিংটি ব্যবহার করতে পারেন ।
আইএক্স 3

কেবল জিজ্ঞাসা করতে চেয়েছিলেন যে চরের [] অ্যারের ক্ষেত্রে যেমন char *p = "abc";নল চরিত্রটি \0স্বয়ংক্রিয়ভাবে যুক্ত হয়?
কেপিএমজি

কেন আমি সেট char *name; name="123";করতে পারি কিন্তু intটাইপ দিয়ে একই করতে পারি ? আর ব্যবহার করে পরে %cপ্রিন্ট করতে name, আউটপুট অপাঠ্য স্ট্রিং: ?
টমসওয়ায়ার

83

দেখা যাক:

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

int main()
{
    char *p = "hello";
    char q[] = "hello"; // no need to count this

    printf("%zu\n", sizeof(p)); // => size of pointer to char -- 4 on x86, 8 on x86-64
    printf("%zu\n", sizeof(q)); // => size of char array in memory -- 6 on both

    // size_t strlen(const char *s) and we don't get any warnings here:
    printf("%zu\n", strlen(p)); // => 5
    printf("%zu\n", strlen(q)); // => 5

    return 0;
}

foo * এবং foo [] বিভিন্ন ধরণের এবং সেগুলি সংকলক দ্বারা পৃথকভাবে পরিচালিত হয় (পয়েন্টার = ঠিকানা + পয়েন্টারের ধরণের উপস্থাপনা, অ্যারে = পয়েন্টার + অ্যারের lengthচ্ছিক দৈর্ঘ্য, যদি জানা থাকে, উদাহরণস্বরূপ, অ্যারে স্থিতিপূর্বক বরাদ্দ করা হয় তবে ), বিশদটি স্ট্যান্ডার্ডে পাওয়া যাবে। এবং রানটাইমের স্তরে তাদের মধ্যে কোনও পার্থক্য নেই (এসেম্বলারে, ভাল, প্রায়, নীচে দেখুন)।

এছাড়াও, সি এফকিউতে একটি সম্পর্কিত প্রশ্ন রয়েছে :

প্রশ্ন : এই আরম্ভের মধ্যে পার্থক্য কী?

char a[] = "string literal";   
char *p  = "string literal";   

আমি পি [i] কে নতুন মান নির্ধারণ করার চেষ্টা করলে আমার প্রোগ্রামটি ক্র্যাশ হয়ে গেছে।

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

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

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

1.31, 6.1, 6.2, 6.8 এবং 11.8 বি প্রশ্নগুলিও দেখুন।

তথ্যসূত্র: কে ও আর 2 সেকেন্ড 5.5 পি। 104

আইএসও সেকেন্ড 6.1.4, সেকেন্ড 6.5.7

রেশনেল সেক। 3.1.4

এইচএন্ডএস সেকেন্ড 2.7.4 পৃষ্ঠা 31-2


আকারে (কিউ), কেন পয়েন্টার হিসাবে q ক্ষয় হয় না, কারণ @ জন তার উত্তরে উল্লেখ করেছে?
গ্যারিপ

@ গ্যারিপ কিউ পয়েন্টারে ক্ষয় হয় না কারণ সাইজফ একটি অপারেটর, কোনও ফাংশন নয় (সাইজফোফ একটি ফাংশন হলেও, ক্রু ক্ষয় হবে কেবলমাত্র যদি ফাংশনটি চার পয়েন্টার আশা করছিল)।
গিরিবি

ধন্যবাদ, তবে প্রিন্টফ ("% u \ n" প্রিন্টফের পরিবর্তে ("% zu \ n", আমি মনে করি আপনার জেড অপসারণ করা উচিত।
জাকারিয়া

33

C তে চর অ্যারে বনাম চর পয়েন্টারের মধ্যে পার্থক্য কী?

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

2
@ leszek.hanusz অনির্ধারিত আচরণ stackoverflow.com/questions/2766731/... গুগল "সি ল্যাঙ্গুয়েজ UB" ;-)
সিরো Santilli郝海东冠状病六四事件法轮功

9

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


6

এই জাতীয় ক্ষেত্রেগুলির জন্য প্রভাবটি একই: আপনি প্রথম অক্ষরের ঠিকানাটি অক্ষরের একটি স্ট্রিংয়ে শেষ করেন।

ঘোষণাগুলি যদিও স্পষ্টতই এক নয়।

নিম্নলিখিতটি স্ট্রিংয়ের জন্য এবং একটি অক্ষর পয়েন্টারের জন্য মেমরি আলাদা করে দেয় এবং তারপরে স্ট্রিংয়ের প্রথম অক্ষরের দিকে নির্দেশ করতে পয়েন্টারটি আরম্ভ করে।

char *p = "hello";

যখন নিম্নলিখিতটি কেবল স্ট্রিংয়ের জন্য মেমরি আলাদা করে দেয়। সুতরাং এটি আসলে কম স্মৃতি ব্যবহার করতে পারে।

char p[10] = "hello";

codeplusplus.blogspot.com/2007/09/… "তবে, পরিবর্তনশীল আরম্ভ করতে অ্যারের জন্য বিশাল কর্মক্ষমতা এবং স্পেস পেনাল্টি লাগে"
লিফ

@ লেফ: আমি মনে করি এটি নির্ভর করে যেখানে চলকটি কোথায় অবস্থিত। যদি এটি স্ট্যাটিক মেমোরিতে থাকে তবে আমি মনে করি অ্যারে এবং ডেটা EXE চিত্রে সংরক্ষণ করা সম্ভব এবং কোনও প্রারম্ভিককরণের প্রয়োজন নেই। অন্যথায়, হ্যাঁ, যদি ডেটা বরাদ্দ করতে হয় এবং স্থির ডেটা অনুলিপি করতে হয় তবে তা অবশ্যই ধীর হতে পারে
জোনাথন উড

3

যতদূর আমি মনে করতে পারি, একটি অ্যারে আসলে পয়েন্টারগুলির একটি গ্রুপ। উদাহরণ স্বরূপ

p[1]== *(&p+1)

একটি সত্য বিবৃতি


2
আমি একটি অ্যারে মেমরির ব্লকের ঠিকানার পয়েন্টার হিসাবে বর্ণনা করব। সুতরাং কেন *(arr + 1)আপনাকে দ্বিতীয় সদস্যের কাছে নিয়ে আসে arr। যদি *(arr)একটি 32 বিট মেমরি অ্যাড্রেস, যেমন পয়েন্ট bfbcdf5e, তারপর *(arr + 1)স্থানটিকে bfbcdf60(দ্বিতীয় বাইট)। সুতরাং কোনও অ্যারের ক্ষেত্রের বাইরে যাওয়ার ফলে ওএস সেগফল্ট না করলে অদ্ভুত ফলাফলের দিকে নিয়ে যায়। যদি int a = 24;ঠিকানা হয় bfbcdf62, তবে অ্যাক্সেসটি arr[2]ফিরে আসতে পারে 24, ধরে নিয়েই কোনও সেগফাল্ট প্রথমে ঘটে না।
ব্র্যাডেন সেরা

3

থেকে APUE , বিভাগ 5.14:

char    good_template[] = "/tmp/dirXXXXXX"; /* right way */
char    *bad_template = "/tmp/dirXXXXXX";   /* wrong way*/

... প্রথম টেমপ্লেটের জন্য, নামটি স্ট্যাকের উপর বরাদ্দ করা হয়েছে, কারণ আমরা একটি অ্যারে ভেরিয়েবল ব্যবহার করি। দ্বিতীয় নামের জন্য, তবে আমরা একটি পয়েন্টার ব্যবহার করি। এই ক্ষেত্রে, কেবল পয়েন্টারটির জন্য মেমরি নিজেই স্ট্যাকের উপরে থাকে; সংকলক এক্সিকিউটেবলের কেবল পঠনযোগ্য বিভাগে স্ট্রিংটি সংরক্ষণের ব্যবস্থা করে। যখন mkstempফাংশনটি স্ট্রিংটি সংশোধন করার চেষ্টা করে, তখন একটি সেগমেন্টেশন ত্রুটি ঘটে।

উদ্ধৃত পাঠ্য @ সিরো সান্তিলির ব্যাখ্যার সাথে মেলে।


1

char p[3] = "hello"? char p[6] = "hello"মনে রাখা উচিত যে সিতে একটি "স্ট্রিং" এর শেষে একটি '\ 0' চর আছে

যাইহোক, সি এ অ্যারে মেমোরিতে অ্যাডজাস্ট অবজেক্টের প্রথম অবজেক্টের কেবলমাত্র পয়েন্টার। কেবল ভিন্ন ভিন্ন শব্দার্থবিজ্ঞানের মধ্যে রয়েছে। আপনি যখন পয়েন্টারের মান পরিবর্তন করতে পারেন মেমরির একটি আলাদা অবস্থানের দিকে নির্দেশ করার জন্য একটি অ্যারে তৈরি হওয়ার পরে, সর্বদা একই অবস্থানের দিকে নির্দেশ করবে।
এছাড়াও অ্যারে ব্যবহার করার সময় "নতুন" এবং "মুছুন" স্বয়ংক্রিয়ভাবে আপনার জন্য হয়ে যায়।

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