C أنواع غير متوافقة في المهمة ، مشكلة مع المؤشرات؟
سؤال
مرحبًا ، أنا أعمل مع C ولدي سؤال حول تعيين مؤشرات.
struct foo
{
int _bar;
char * _car[SOME_NUMBER]; // this is meant to be an array of char * so that it can hold pointers to names of cars
}
int foofunc (void * arg)
{
int bar;
char * car[SOME_NUMBER];
struct foo * thing = (struct foo *) arg;
bar = thing->_bar; // this works fine
car = thing->_car; // this gives compiler errors of incompatible types in assignment
}
Car و _car لديهما نفس الإعلان ، فلماذا أحصل على خطأ بشأن الأنواع غير المتوافقة؟ أظن أنه له علاقة مع كونهم مؤشرات (لأنهم مؤشرات على صفائف Char *، أليس كذلك؟) لكنني لا أرى لماذا هذه مشكلة.
عندما أعلنت char * car;
بدلاً من char * car[MAXINT];
يجمع بشكل جيد. لكنني لا أرى كيف سيكون ذلك مفيدًا بالنسبة لي لاحقًا عندما أحتاج إلى الوصول إلى معلومات معينة باستخدام الفهرس ، سيكون من المزعج للغاية الوصول إلى هذه المعلومات لاحقًا. في الواقع ، لست متأكدًا مما إذا كنت سأذهب بالطريقة الصحيحة ، فربما يكون هناك طريقة أفضل لتخزين مجموعة من الأوتار بدلاً من استخدام مجموعة من char *؟
تحرير: لم أقصد استخدام int_max (القيمة القصوى لـ int) ، إنها مجرد int أخرى ، والتي تبلغ حوالي 20.
المحلول
أنت تقوم بإنشاء مجموعة جديدة من maxint الحجم. أعتقد أنك تريد إنشاء مؤشر لمجموعة من MaxInt الحجم.
إنشاء مؤشر لمجموعة من char*s:
فيما يلي مجموعة من الحجم الأقصى لعناصر char*:
char * car[MAXINT];
ما يلي هو مؤشر ل: مجموعة من الحجم maxint إلى char* عناصر:
char* (*car)[MAXINT];
فيما يلي كيف تقوم بتعيين مؤشر على: مجموعة من Maxint Size to Char* العناصر:
char* (*car)[MAXINT];
car = &arg->_car;
أخطاء بناء الجملة الأخرى في السؤال:
- يجب أن يكون لديك فاصلة فاصلة بعد تعريف الهيكل الخاص بك.
- يجب أن تستخدم
foo*
ليسfoo
. لذلك ينبغي أن يكون:
struct foo* thing = (struct foo *) arg;
- يجب أن تستخدم
thing
ليسarg
:
bar = thing->_bar;
car = thing->_car;
نصائح أخرى
car
و _car
كلا المصفوفتين ، ولا يمكنك تعيين المصفوفات في C (باستثناء عندما يتم تضمين الصفيف في هيكل (أو اتحاد) وأنت تقوم بتعيين هيكل).
كما أنها صفائف من المؤشرات إلى Char ، بدلاً من مؤشرات إلى صفائف Char. ما كتبته في الرمز هو ما تريده على الأرجح - يمكنك تخزين المؤشرات إلى أسماء Maxint في الصفيف. ومع ذلك ، يجب أن تصف النوع بشكل صحيح - كمجموعة من المؤشرات إلى مؤشرات char أو char.
سيبدو مؤشر لمجموعة من الشخصيات:
char (*car)[MAXINT];
ونقطة إلى مجموعة من مؤشرات الشخصية (شكرًا ، براين) ستبدو:
char *(*car)[MAXINT];
كن حذرا من maxint. يمكن أن يكون هذا صفيفًا كبيرًا جدًا (على Linux ، <values.h>
تعريف MAXINT
مثل INT_MAX
, ، وهو على الأقل 231-1).
الرمز يشبه:
struct foo
{
int _bar;
char * _car[MAXINT];
}
int foofunc (void * arg)
{
int bar;
char * car[MAXINT];
struct foo thing = (struct foo *) arg;
bar = arg->_bar; // this works fine
car = arg->_car; // this gives compiler errors of incompatible types in assignment
}
لا ينبغي تجميع المهمة إلى شريط ولا سيارة على الإطلاق - arg
هو void *
. من المفترض أن تهدف إلى استخدام thing
في شكل أو شكل. كما لاحظ براين ، هناك مشاكل هناك أيضًا:
إما تريد:
int foofunc(void *arg)
{
int bar;
char *car[MAXINT];
struct foo thing = *(struct foo *)arg;
bar = thing._bar; // this works fine
car = thing._car; // this is still an array assignment
...other code using bar and car...
}
أو تريد:
int foofunc(void *arg)
{
int bar;
char *car[MAXINT];
struct foo *thing = (struct foo *) arg;
bar = thing->_bar; // this works fine
car = thing->_car; // this is still an array assignment
...other code using bar and car...
}
أو في الواقع:
int foofunc(void *arg)
{
struct foo *thing = (struct foo *) arg;
int bar = thing->_bar; // this works fine
char *car[MAXINT] = thing->_car; // this is still an array assignment
...other code using bar and car...
}
أخيرًا ، التعامل مع مهمة الصفيف ، في C يمكنك استخدامه بشكل معقول memmove()
لفعل هذا:
int foofunc(void *arg)
{
struct foo *thing = (struct foo *) arg;
int bar = thing->_bar; // this works fine
char *car[MAXINT];
memmove(car, thing->_car, sizeof(car));
...other code using bar and car...
}
وظيفة مماثلة memcpy()
ليس لديها دلالات موثوقة إذا كانت المناطق التي يجب نسخها تتداخل ، في حين memmove()
يفعل؛ من الأسهل استخدام دائمًا memmove()
لأنه يعمل دائما بشكل صحيح. في C ++ ، يجب أن تكون حذرًا بشأن استخدامه memmove()
(أو memcpy()
). في هذا الرمز ، سيكون من الآمن بما فيه الكفاية ، ولكن فهم سبب عدم التافهة.
يجب أن تكون على دراية بأنك تقوم فقط بنسخ مؤشرات هنا - أنت لا تقوم بنسخ الأوتار التي تشير إليها المؤشرات. إذا قام شيء آخر بتغيير تلك الأوتار ، فإنه يؤثر على كل من القيم التي شوهدت عبر car
والمتغير في رمز الاتصال.
نقطة أخيرة - في الوقت الحالي: هل أنت متأكد من أنك بحاجة إلى الوسيطة إلى الوظيفة كملف void *
؟ يفتح الرمز على جميع أنواع سوء المعاملة التي يمكن منعها إذا تم إعلان الوظيفة لأخذ ''struct foo *
"بدلاً من ذلك (أو حتى أ"const struct foo *
').
لا يمكنك التعيين إلى صفيف بالطريقة التي تفعله. يمكنك عمل نسخة من العناصر.
for(int i = 0; i < MAXINT; i++)
{
car[i] = (arg->_car)[i]
}
لاحظ أنه إذا لم تكن الأوتار ثابتة ، فقد تحتاج إلى استخدام strcpy
.
تدوين الصفيف في C أمر مربك بشكل شرعي ؛ الكود الخاص بك لا يعني ما تعتقد أنه يعني.
arg->_car
يعني "عنوان الصفيف _car
". بصورة مماثلة، car
يعني "عنوان الصفيف car
". إذا كنت تحاول نسخ محتويات _car للسيارة ، فإن هذا سيفعل ذلك:
memcpy(car, _car, MAXINT);
لكن سؤالك الحقيقي ، على ما أعتقد ، هو "ما هي أفضل طريقة لتخزين قائمة الأوتار؟" هذه الإجابة هي: قائمة ديناميكية (تنمو تلقائيًا أثناء إضافة عناصر).
كنت تعلن ذلك مثل هذا:
#define CARSIZE 65
int numCars = 0;
char **car; /* a list of addresses, each one will point to a string */
لإضافة سيارة:
char *newCar = malloc(CARSIZE); /* make room */
strncpy(newCar, "Mercedes", CARSIZE); /* newCar has the address of the string */
car[numCars++] = newCar; /* store it */
لسرد السيارات:
int n;
for (n = 0; n < numCars; ++n)
printf("%s\n", car[n]);
لإزالة السيارة في الموضع n:
free(car[n]); /* release the memory */
/* condense the list of pointers */
for ( ; n < numCars - 1; ++n)
car[n] = car[n+1];
هذا روتيني تماما في C. ملاحظة: ما سبق خارج الجزء العلوي من رأسي ولم يتم نسخه من برنامج عمل ، لذلك لا يمكنني أن أعد كل ما في المكان المناسب. أظن أن هذه مهمة منزلية ، لذلك لا أريد أن أعطيك كل شىء...