سؤال

هذا يبدو وكأنه مسألة سخيفة, ولكن أنا لا تزال التعلم ج ، لذا يرجى تتحمل معي.:)

أنا أعمل على الفصل 6 من K&R (البنيات), و حتى الآن خلال هذا الكتاب قد شهدت نجاحا كبيرا.قررت العمل مع البنيات بشكل كبير جدا ، وبالتالي فعلت الكثير من العمل في وقت مبكر في الفصل مع نقطة المستطيل الأمثلة.واحدة من الأشياء التي كنت أرغب في محاولة تغيير canonrect وظيفة (2nd Edition, p 131) العمل من خلال المؤشرات ، ومن ثم العودة void.

لدي هذا العامل ، لكنها واجهت زوبعة كنت آمل يا رفاق يمكن أن تساعدني.أردت canonRect لإنشاء المؤقتة المستطيل كائن إجراء التغييرات ، ثم إعادة تعيين مؤشر انها مرت المؤقتة مستطيل ، وبالتالي تبسيط التعليمات البرمجية.

ومع ذلك, إذا فعلت ذلك, rect لا تغيير.بدلا من ذلك, أجد نفسي يدويا إعادة إسكانها في مجالات rect أنا مرت في التي لا تعمل.

رمز يلي:

#include <stdio.h>

#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))

struct point {
    int x;
    int y;
};

struct rect {
    struct point lowerLeft;
    struct point upperRight;
};

// canonicalize coordinates of rectangle
void canonRect(struct rect *r);

int main(void) {
    struct point p1, p2;
    struct rect r;

    p1.x = 10;
    p1.y = 10;
    p2.x = 20;
    p2.y = 40;
    r.lowerLeft = p2; // note that I'm inverting my points intentionally
    r.upperRight = p1;

    printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n", 
        r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);

    // can't pass a pointer, only a reference. 
    // (Passing pointers results in illegal indirection compile time errors)
    canonRect(&r); 
    printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n", 
        r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);    
}

void canonRect(struct rect *r) {
    struct rect temp;
    temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
    temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
    temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
    temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);

    r = &temp; // doesn't work; my passed-in rect remains the same

    // I wind up doing the following instead, to reassign all 
    // the members of my passed-in rect
    //r->lowerLeft = temp.lowerLeft;
    //r->upperRight = temp.upperRight;
}

حتى هنا هي الأسئلة:

  1. لماذا r = &temp; لا تعمل ؟ (أنا أعتقد هذا هو لأنني تمر في إشارة بدلا من المؤشر.أنا على حق في التفكير في أن المراجع لا للتعديل ولكن المؤشرات؟)
  2. لماذا قد أحصل على غير قانونية المراوغة وقت التحويل البرمجي خطأ إذا حاولت تمرير مؤشر إلى canonRect?(أي إذا كان canonRect(*r); في main().)

وأظن أنا بالفعل أعرف الجواب #1, ولكن #2 يحيرني ... ظننت أنه القانونية لتمرير مؤشرات حول.

على أي حال ...يرجى أن يغفر C newb.

هل كانت مفيدة؟

المحلول

أعتقد أن ما تريد القيام به هو هذا:

void canonRect(struct rect *r) {
    struct rect temp;
    temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
    temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
    temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
    temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);

    *r = temp; 
}

في التعليمات البرمجية أعلاه أنت الإعداد *r الذي هو من نوع المستطيل إلى درجة الحرارة التي هي من نوع rect.

Re 1:إذا كنت ترغب في تغيير ما r يشير إلى أنك تحتاج إلى استخدام مؤشر إلى مؤشر.إذا كان هذا هو حقا ما تريد (انظر أعلاه ليس حقا ما تريد) ثم سيكون لديك للتأكد من أن نشير إلى شيء على كومة.إذا أشرت إلى شيء لم يخلق مع "الجديد" أو malloc ثم أنها سوف تقع خارج نطاق وسوف يكون لافتا إلى الذاكرة التي لم تعد تستخدم هذا المتغير.

لماذا لا رمز العمل مع r = &temp ؟

لأنه r هو المستطيل* نوع.وهذا يعني أنه r هو المتغير الذي يحمل عنوان الذاكرة من الذاكرة يحتوي على المستطيل.إذا قمت بتغيير r ما يشير إلى هذا جيد ولكن هذا لا يغير مرت في متغير.

إعادة 2:* عندما لا تستخدم في نوع الإعلان هو إلغاء مرجعية الأحادية المشغل.هذا يعني أنه سيتم بحث ما هو داخل في عنوان المؤشر.وذلك عن طريق تمرير *r أنت لا يمر المؤشر على الإطلاق.في الوجه منذ r ليس المؤشر ، هذا بناء جملة غير صالح.

نصائح أخرى

أيضا الجدير بالذكر المتغير الخاص بك 'البنية rec temp' هو الذهاب الى الخروج من نطاق بمجرد أن طريقة canonRect ينتهي وسوف يكون لافتا إلى ذاكرة غير صالحة.

يبدو أنك خلطت بين 'إلغاء مرجعية' المشغل (*) مع 'عنوان' المشغل (&).

عندما تكتب &r, أن يحصل على عنوان في r و عودة المؤشر الى r (مؤشر هو مجرد عنوان الذاكرة متغير).لذلك كنت حقا تمرير المؤشر إلى وظيفة.

عندما تكتب *r, أنت تحاول إلغاء مرجعية r.إذا كان r هو مؤشر ، التي ستعود على قيمة r يشير إلى.ولكن r ليس مؤشر انه rect, لذلك عليك الحصول على خطأ.

لجعل الأمور أكثر مربكة ، * حرف يستخدم أيضا عندما يعلن مؤشر المتغيرات.في هذه الوظيفة الإعلان:

void canonRect(struct rect *r) {

r وأعلن أن مؤشر إلى struct rect.هذا يختلف تماما عن استخدام * مثل هذا:

canonRect(*r); 

في كلتا الحالتين ، * حرف يعني شيئا مختلفا تماما.

أولا K&R c لا يكون مفهوم "المراجع", مؤشرات فقط.على & المشغل يعني "خذ عنوان".


ثانيا ، r في cannonRect() هو متغير محلي ، لا على r في main().تغيير المكان المحلي r نقاط لا تأثير r في الدعوة الروتينية.


أخيرا, كما لوحظ بالفعل المحلية struct rect يتم تخصيص كومة ، و يخرج من نطاق في ختام هدفين ،

قد ترغب في الاطلاع على طرق مختلفة المعلمات يمكن (نظريا) أن تنتقل إلى وظائف.ج الاتصال عن طريق القيمة, لذا عند تمرير المؤشر على المستطيل في الدالة يتم تمرير نسخة من المؤشر.أي تغييرات وظيفة يجعل قيمة r مباشرة (غير مباشرة) سوف لا تكون مرئية إلى المتصل.

إذا كنت تريد وظيفة لتوفير المتصل مع البنية الجديدة ثم هناك طريقتان للقيام بذلك:1.يمكنك العودة rect:2.يمكنك تمرير مؤشر إلى مؤشر إلى المستطيل في:

الطريقة الأولى سيكون أكثر طبيعية:

struct rect* canonRect(struct rect* r)
{
  struct rect* cr = (struct rect*) malloc(sizeof(struct rect));
  ...
  return cr;
}

الطريقة الثانية ليكون:

void canonRect(struct rect** r)
{
  *r = (struct rect*) malloc(sizeof(struct rect));
}

و المتصل ثم استخدام:

   canonRect(&r);

ولكن الطالب يفقد الأصلي المؤشر كان, و عليك أن تكون حريصا على عدم تسرب البنيات.

أيهما كنت تستخدم تقنية, وظيفة سوف تحتاج إلى تخصيص الذاكرة البنية الجديدة على كومة استخدام malloc.لا يمكنك تخصيص مساحة على كومة من مجرد إعلان البنية بسبب أن الذاكرة يصبح غير صالح عندما ترجع الدالة.

2.لماذا قد أحصل على غير قانونية المراوغة وقت التحويل البرمجي خطأ إذا حاولت تمرير مؤشر إلى canonRect?(أي إذا كان canonRect(*r) ؛ في main().)

لأنه ليس الغرض من مؤشر.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top