رفتن به مطلب
جامعه‌ی برنامه‌نویسان مُدرن ایران
  • 0
قاسم رمضانی منش

اضافه کردن یک کاراکتر به انتهای رشته


سوال

درود بر دوستان عزیز؛

برای اضافه کردن یک کاراکتر به انتهای رشته شاید افراد به این‌صورت عمل کنند :

string[ strlen(string) ] = char;

امّا من خواستم بدون وابسته بودن این قسمت به libc؛ این عمل انجام شود به این‌صورت عمل کردم :

int main (void){
    /* Define variable */
    char c = 'm';
    char* string = NULL;

    /* Allocating memory */
    string = malloc(7);

    /* Copy char into `string` */
    strcpy(string, (char*)"ghase");

    /* Append `c` to end of `string` */
    *((char*)(&string + 1) - 2) = c;
    *((char*)(&string + 1) - 1) = '\0';

    /* Result */
    printf("%s\n", string);

    return EXIT_SUCCESS;
}

امّا با سیگنال SIGSEGV در تابع __strlen_sse2() هنگام فراخوانی printf() مواجه می‌شوم، کلاً حافظهٔ دریافتی از طریق Derefrence کردن string مقادیرش قابل دسترسی نیست (پیغامی که GDB نشان می‌دهد). ولی همچنان می‌توانم به‌اینصورت به مقداردهی که کرده‌ام دسترسی داشته‌باشم :

printf("%c\n", *((char*)(&string + 1) - 2));

الآن چه اتفاقی برای حافظهٔ متغیر string می‌افتد ؟

ویرایش شده در توسط قاسم رمضانی منش
تصحیح حالت رنگ‌آمیزی کدها.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

3 پاسخ به این سوال تا کنون داده شده است

پست های پیشنهاد شده

  • 0

متشکرم از توضیحتان رفتار کامپایلر را برای تولید آن کد اسمبلی را زیاد متوجه نشدم، کاری که کردم :

  1.  اضافه کردن به آدرسی که به کل آرایه اشاره می‌کنه، که باعث میشه آدرس بعد از آرایه را به ما بده.
  2.  سپس type اون آدرس را به تبدیل به نوع *char می‌کنم.
  3.  و یک واحد (char) از آن آدرس کم می‌کنم که میشه خونهٔ آخر آرایه ما.

امّا ظاهراً اون اتفاقی که می‌خواستم صورت نگرفته.

درمورد روش‌هایی که پیشنهاد دادید :

در 11 ساعت قبل، فرهاد شیری گفته است :

*(((char*)&string[4])+4) = c;

 

در 11 ساعت قبل، فرهاد شیری گفته است :

(((char*)&string[4])[4]) = c;

اینجا متوجه آن ۴ واحد اضافه کردن آخری نشدم، شما آدرس خانهٔ چهارم آرایه را تبدیل به *char کردید و سپس چهار واحد اضافه کردید (چرا ؟) و بعد به مقدارَش اشاره کردید.

 

ویرایش شده در توسط قاسم رمضانی منش
تصحیح نگارش.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 1 ساعت قبل، فرهاد شیری گفته است :

در حقیقت اشاره به چهارمین عضو آرایه temp هست!

میشه کاری کرد که اصلاً دست به اشاره‌گر string نزنه ؟ یعنی همان کد بالا ولی هیچ تغییری در محتوای اشاره‌گر string ایجاد نکنه که باعث بشه به ناکجاآباد اشاره‌کنه ؟

در 1 ساعت قبل، فرهاد شیری گفته است :

بلکه ایندکس شماره 0 آدرس کلی آرایه را میده!...

بله درست متوجه شدید، و بعد چون اون اشاره‌گر از نوع کل‌آرایه هست من تبدیلش کردم به نوع *char که بتونم خونه‌های ۱ بایتی را ازش کم کنم؛ که میشه خونهٔ آخر آرایه.

یه کم کامل‌تر بگم :

  • وقتی ما می‌نویسیم arr* یعنی مقدار خانه‌ای که arr به آن اشاره می‌کند را درخواست می‌کنیم (فرض می‌گیریم arr یک []char است).
  • حالا وقتی می‌گوییم arr& یعنی آدرس خانه‌ای که arr به آن اشاره می‌کند را می‌گیریم، با تفاوتش با arr + 2& این است که arr& آدرس کل خانه‌های arr را به ما می‌دهد  به جای آدرس یک خانه.
  • پس وقتی که arr + 1& می‌گوییم درواقع یک همچین چیزی است :
/*
        =================
        | x | x | x | x |
        =================
            \---+---/
                |
   char arr[]: -+
   
        =================
        | x | x | x | x |
        ======|==========
              |
              |
   arr + 1 : -+
  
         =================
         | x | x | x | x |
         =================
               ^
               |
   &arr + 1 : -+
  
     /  =================
     +> | x | x | x | x |
     \  =================
     +--------+
              |
   &arr : ----+
  
  
        ================= -------------...
        | x | x | x | x | |  |  |  |  |...
        ================= -------------...  
                            ^
                 +----------+
                 |
   &arr + 1: ----+
*/

و در انتها وقتی که ما نوع اشاره‌گر را به *char تغییر می‌دهیم و یک واحد کم می‌کنیم، درواقع یک واحد از نوع *char کم‌ می‌شود به جای یک واحد از نوع arr&. و اینطوری می‌توانیم به خانهٔ آخر آرایه به راحتی دسترسی داشته باشیم چرا که آن خانه در دسترس است. امّا اینکه چرا نمی‌توانم مقداری درآن خانه قرار بدم و آن رفتار کامپایلر اتفاق می‌اٌفتد عجیبه.

در 1 ساعت قبل، فرهاد شیری گفته است :

چه کاری این که رفتار تعریف نشده میشه!

من فقط آدرس را می‌گیرم، اصلاً هیچ دسترسی به آن خانه ندارم که بخواد مشکلی ایجاد کنه؛ فقط آدرس را می‌گیرم و واحدهایی (به اندازهٔ مقدارحافظه‌ای که char می‌گیرد) ازش کم‌ می‌کنم که بتونم به خانهٔ آخر آرایه دسترسی داشته‌باشم، نمونه :

#define END_OF_ARRAY(type, arr, index) \
    (*((type*) (&arr + 1) - index))

int main (void){
    char string[] = "ghasem is here";
    printf("%c\n", END_OF_ARRAY(char, string, 2));
    printf("%s\n", string);
    return 0;
}

 

ویرایش شده در توسط قاسم رمضانی منش
حذف ستاره‌های اضافه | اصلاح نگارش.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0

😅تشکر بابت توضیحاتتون ممنون؛  اصرارم این بود که فکر می‌کردم اینکار ساده‌ای هست و نیازی نیست که بی‌مورد توابع libc را فراخوانی کنیم. البته به گمانم بشه کارهایی کرد ولی بهتر است که کمی اسمبلی را مطالعه کنم.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

مهمان
پاسخ به این سوال ...

×   شما در حال چسباندن محتوایی با قالب بندی هستید.   حذف قالب بندی

  تنها استفاده از ۷۵ اموجی مجاز می باشد.

×   لینک شما به صورت اتوماتیک جای گذاری شد.   نمایش به عنوان یک لینک به جای

×   محتوای قبلی شما بازگردانی شد.   پاک کردن محتوای ویرایشگر

×   شما مستقیما نمی توانید تصویر خود را قرار دهید. یا آن را اینجا بارگذاری کنید یا از یک URL قرار دهید.


  • کاربران آنلاین در این صفحه   0 کاربر

    هیچ کاربر عضوی،در حال مشاهده این صفحه نیست.

×
×
  • جدید...