تمرير مجموعة من السلاسل كمعلمة إلى دالة في لغة C
-
20-08-2019 - |
سؤال
أريد وظيفة بسيطة تستقبل سلسلة وترجع مجموعة من السلاسل بعد بعض التحليل.إذن، هذا هو توقيع وظيفتي:
int parse(const char *foo, char **sep_foo, int *sep_foo_qty) {
int i;
char *token;
...
strcpy(sep_foo[i], token); /* sf here */
...
}
ثم أسميها هكذا:
char sep_foo[MAX_QTY][MAX_STRING_LENGTH];
char foo[MAX_STRING_LENGTH];
int sep_foo_qty, error;
...
error = parse(foo, sep_foo, &sep_foo_qyt);
...
بهذه الطريقة أحصل على تحذير أثناء التجميع:
warning: passing argument 2 of 'parse' from incompatible pointer type
ثم حدث خطأ تجزئة أثناء التنفيذ في السطر المميز بـ /* sf هنا */
ما هو الخطأ في رمز C الخاص بي؟
شكرا لك مقدما
المحلول
التحذير صحيح تماما.وظيفتك تريد مجموعة من المؤشرات.أنت تعطيه مجموعة من المصفوفات.
مُتوقع:
sep_foo: +------+ +-----+ |char**|--> 0: |char*|-->"string1" +------+ +-----+ 1: |char*|-->"string2" +-----+ *sep_foo_qty-1: |... | +-----+
ما قدمته:
sep_foo: +--------------------------------+ 0: | char[MAX_STRING_LENGTH] | +--------------------------------+ 1: | char[MAX_STRING_LENGTH] | +--------------------------------+ MAX_QTY-1: | ... | +--------------------------------+
مصفوفة تحتوي على عناصر من النوع X
يمكن أن "تتحلل" إلى مؤشر إلى-X
, ، أو X*
.ولكن قيمة X
لا يسمح بالتغيير في هذا التحويل.فقط واحد يسمح بعملية الاضمحلال.كنت في حاجة إلى أن يحدث مرتين.في حالتك، X
هو مجموعة من-MAX_STRING_LENGTH
-الحرف.الوظيفة تريد X
ليكون المؤشر إلى شار.وبما أن هذه ليست هي نفسها، فإن المترجم يحذرك.أنا مندهش بعض الشيء لأنه كان مجرد تحذير لأنه لا يمكن أن يأتي أي شيء جيد مما سمح المترجم بحدوثه.
في وظيفتك، يمكنك كتابة هذا الكود:
char* y = NULL;
*sep_foo = y;
هذا هو القانون القانوني منذ ذلك الحين sep_foo
هو char**
, ، لذا *sep_foo
هو char*
, ، وذلك هو y
;يمكنك تعيينهم.ولكن مع ما حاولت القيام به، *sep_foo
لن حقًا يكون أ char*
;سيكون يشير إلى مجموعة من char.في الواقع، سيحاول الكود الخاص بك القيام بذلك:
char destination[MAX_STRING_LENGTH];
char* y = NULL;
destination = y;
لا يمكنك تعيين مؤشر إلى مصفوفة، ولذلك يحذر المترجم من أن الاستدعاء ليس جيدًا.
هناك طريقتان لحل هذا:
غيّر طريقة إعلانك وتخصيصك
sep_foo
على جانب الاتصال بحيث يتطابق مع ما تتوقع الوظيفة تلقيه:char** sep_foo = calloc(MAX_QTY, sizeof(char*)); for (int i = 0; i < MAX_QTY; ++i) sep_foo[i] = malloc(MAX_STRING_LENGTH);
أو مكافئ
char* sep_foo[MAX_QTY]; for (int i = 0; i < MAX_QTY; ++i) sep_foo[i] = malloc(MAX_STRING_LENGTH);
قم بتغيير النموذج الأولي للوظيفة لقبول ما تقدمه لها بالفعل:
int parse(const char *foo, char sep_foo[MAX_QTY][MAX_STRING_LENGTH], int *sep_foo_qty);
نصائح أخرى
ويجب أن تكون المعلمة 2
char sep_foo[][MAX_STRING_LENGTH]
لتوضيح، يتم تمرير مؤشر إلى تحليل () والتعامل معها على أنها مؤشر إلى مؤشر. وهناك مجموعة متعددة الأبعاد في C ليست مجموعة من المؤشرات. بل هو كتلة واحدة من الذاكرة المشار إليه بواسطة متغير صفيف. لا يمكنك dereference مرتين.
ويعرف sep_foo
بوصفها مجموعة من المصفوفات. وبعبارة أخرى، عند استخدام sep_foo
، فإنه يشير إلى بداية الذاكرة متسلسلة. وفيما يلي نموذج:
(assume MAX_STRING_LENGTH = 16, MAX_QTY = 2)
sep_foo = &&0000
sep_foo[0] = &0000
sep_foo[0][0] = *&0000 = 12
sep_foo[0][8] = *&0008 = 74
sep_foo[1] = &0010
sep_foo[1][0] = *&0010 = 12
0000 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
0010 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
ولكن، وظيفة الخاص بك وتتوقع مجموعة من المؤشرات (في الواقع، مؤشر إلى مؤشر). وعلى غرار هذا على هذا النحو:
sep_foo_arg = &&0000
sep_foo_arg[0] = *&&0000 = &0010
sep_foo_arg[0][0] = *&*&0000 = 12
sep_foo_arg[0][8] = *(&*&0000 + 8) = 74
sep_foo_arg[1] = *&&0002 = &0020
sep_foo_arg[1][0] = *&*&0000 = 12
0000 0010 0020 xxxx xxxx xxxx xxxx xxxx xxxx
0010 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
0020 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
نعم ... بناء الجملة قد يكون مربكا بعض الشيء عن تفسيرات بلدي ...
وعلى أي حال، يمكنك حل هذه المشكلة عن طريق إخبار الدالة كيفية التعامل أشار المؤشر إلى. على وجه الخصوص، هل تريد التعامل معها على أنها مجموعة (سلسلة من الذاكرة):
int parse(const char *foo, char (*sep_foo)[MAX_STRING_LENGTH], int *sep_foo_qty);
وإذا كان هذا هو رمز بك على وجه الدقة، ثم أنا التخمين segfault لأن من حقيقة أنك لم يخصص الذاكرة إلى char* token
داخل وظيفة تحليل الخاص بك، ومن ثم استخدام ذلك في strcpy الخاص بك.