كيف يمكنني printf في ج

كيف يمكنني إجراء هذه الطباعة بشكل صحيح دون استخدام مكالمتين printf؟

char* second = "Second%d";
printf("First%d"second,1,2);
0
شكر. مفيد جدا
وأضاف المؤلف David hehe, مصدر
لا يوجد (IIRC) طريقة مدمجة للقيام بذلك لأنه يمكن أن يكون مشكلة أمان رئيسية. راجع en.wikipedia.org/wiki/Uncontrolled_format_string للحصول على تفاصيل حول كيفية استغلال البرنامج إذا استطعت القيام بذلك.
وأضاف المؤلف templatetypedef, مصدر

5 إجابة

char *second = "Second %d";
char *first = "First %d";
char largebuffer[256];

strcpy (largebuffer, first);
strcat (largebuffer, second);
printf (largebuffer, 1, 2);

تكمن المشكلة في استخدام التنسيقات التي تم إنشاؤها مثل الطريقة المذكورة أعلاه في أن الدالة printf() ، حيث إنها قائمة وسيطة متغيرة الطول ، ليس لديها أي طريقة لمعرفة عدد الوسيطات المقدمة. ما يفعله هو استخدام سلسلة التنسيق المتوفرة واستخدام الأنواع كما هو موضح في سلسلة التنسيق ، ثم اختيار ذلك العدد وأنواع الوسيطات من قائمة الوسائط.

إذا قمت بتوفير العدد الصحيح من الوسيطات كما في المثال أعلاه حيث يوجد تنسيقان٪ d وهناك نوعان من الأعداد الصحيحة التي تم طباعتها في تلك الأماكن ، فكل شيء على ما يرام. ومع ذلك ، ماذا لو فعلت شيئًا كالتالي:

char *second = "Second %s";
char *first = "First %d";
char largebuffer[256];

strcpy (largebuffer, first);
strcat (largebuffer, second);
printf (largebuffer, 1);

في هذا المثال تتوقع الدالة printf() سلسلة التنسيق بالإضافة إلى عدد متغير من الوسائط. سلسلة التنسيق تقول أنه سيكون هناك وسيطان إضافيان ، عدد صحيح وسلسلة أحرف منتهية صفرية. ومع ذلك يتم توفير وسيطة إضافية واحدة فقط لذلك سوف تستخدم الدالة printf() ما هو التالي على المكدس كمؤشر إلى سلسلة أحرف تم إنهاؤها.

إذا كنت محظوظاً ، فإن البيانات التي تفسر الدالة printf() كمؤشر سيكون عنوان ذاكرة صالح للتطبيق الخاص بك وسوف تكون مساحة الذاكرة المشار إليها عبارة عن زوجين تم إنهاؤها بواسطة صفر. إذا كنت محظوظًا ، سيكون المؤشر صفرًا أو قمامة وستحصل على انتهاك وصول في الوقت المناسب وسيكون من السهل العثور على سبب تعطل التطبيق. إذا لم يكن لديك حظًا على الإطلاق ، فسيكون المؤشر جيدًا بما فيه الكفاية بحيث يشير إلى عنوان صالح يبلغ حوالي 2 كيلو بايت من الأحرف والنتيجة هي أن printf() ستفشل مجموعتك تمامًا وتذهب إلى الحشائش وما ينتج عنها البيانات تحطم ستكون عديمة الفائدة إلى حد كبير.

0
وأضاف
char *second = "Second%d";
char tmp[256];
memset(tmp, 0, 256);
sprintf(tmp, second, 2);
printf("First%d%s", 1,tmp);

أو شيء من هذا القبيل

0
وأضاف
تقصد ربما printf ("First٪ d٪ s"، 1، tmp)؛ ؟
وأضاف المؤلف Shahbaz, مصدر
أعني ، ما كتبته لن ينجح. لا يمكنك concat سلسلة حرفية و char * / char array في C بوضعها بجانب بعضها البعض.
وأضاف المؤلف Shahbaz, مصدر
بالتأكيد. هذا أفضل
وأضاف المؤلف Matthieu, مصدر
نعم ، أفهم أن ... سيصحح الإجابة
وأضاف المؤلف Matthieu, مصدر

الشفرة التي عرضتها لنا غير صحيحة من الناحية التركيبية ، لكنني أفترض أنك تريد إجراء شيء له نفس التأثير مثل:

printf("First%dSecond%d", 1, 2);

كما تعلم ، فإن الوسيطة الأولى إلى printf هي سلسلة التنسيق. لا يجب أن تكون حرفية. يمكنك بناء ذلك بالطريقة التي تريدها.

إليك مثال على ذلك:

#include 
#include 
int main(void)
{
    char *second = "Second%d";
    char format[100];
    strcpy(format, "First%d");
    strcat(format, second);

    printf(format, 1, 2);

    putchar('\n');
    return 0;
}

بعض الملاحظات:

لقد قمت بإضافة سطر جديد بعد الإخراج. يجب إنهاء النص الناتج (تقريبًا) دائمًا بواسطة سطر جديد.

لقد قمت بتعيين حجم تعسفي من 100 بايت لسلسلة التنسيق. بشكل عام ، يمكنك أن تعلن

char *format;

وتهيئته بمكالمة malloc() ، مع تخصيص الحجم الذي تحتاجه بالفعل (والتحقق من أن malloc() لا يشير إلى الفشل عن طريق إرجاع مؤشر فارغ (null pointer) ؛ إذا كنت تريد الاتصال مجانًا (تنسيق) ؛ بعد الانتهاء من ذلك.

كما يقول templatetypedef في تعليق ، هذا النوع من الأشياء يمكن أن يكون خطيرًا إذا جاءت سلسلة التنسيق من مصدر غير متحكم فيه.

(أو يمكنك فقط الاتصال printf مرتين ، وهي ليست أكثر تكلفة من الاتصال مرة واحدة.)

0
وأضاف
اختبرت هذا الحل وهي تكلفة مماثلة لاستخدام printf اثنين. أعتقد أنه ليس لدي خيارات أخرى. شكر!
وأضاف المؤلف David hehe, مصدر

استخدم المعالج الأولي لسَلسَلة السلكين.

#define second "Second%d"
printf("First%d"second,1,2);

لا تفعل ذلك في برنامج حقيقي .

0
وأضاف
بناء جملة غير صحيح. راجع stringfication أو تحويل .
وأضاف المؤلف Richard Chambers, مصدر
اعتذاري ، أنت على صواب. غلطتي.
وأضاف المؤلف Richard Chambers, مصدر
RichardChambers أين قلت هذا كان التحزيم؟ هذا يستخدم preprocessor لسَلسَط سلسلتين. يرجى إزالة downvote. ideone.com/eUGVI
وأضاف المؤلف Marlon, مصدر
يجب أن يكون هذا هو الحل لأن هذه هي الطريقة الأسرع (كما يبدو أن البروتوكول الاختياري يريد). ومع ذلك ، من الواضح أن الثانية يجب أن تكون معروفة في وقت الترجمة. +1
وأضاف المؤلف jn1kk, مصدر

أفترض أنك تريد الإخراج:

First 1 Second 2

للقيام بذلك ، نحتاج إلى فهم وظيفة printf أفضل قليلاً. إن السبب الحقيقي الذي يجعل printf مفيدًا جدًا لدرجة أنه لا يطبع السلاسل فحسب ، بل ينسق المتغيرات أيضًا. استنادًا إلى الطريقة التي تريد بها تنسيق المتغير ، يلزمك استخدام أحرف تنسيق مختلفة. ٪ d tells printf لتنسيق المتغير كعدد صحيح موقّع ، والذي تعرفه بالفعل. ومع ذلك ، هناك تنسيقات أخرى ، مثل ٪ f للعوامات والمضاعفات ، ٪ l٪ للأعداد الصحيحة الطويلة ، و ٪ s للسلاسل ، أو char * .

باستخدام رمز تنسيق ٪ s لطباعة char * المتغير ، الثاني ، تبدو الشفرة كما يلي:

char* second = "Second";
printf ( " First %d %s %d ", 1, second, 2 );

هذا يخبر printf أنك تريد المتغير الأول المنسق كعنصر ، والثاني كسلسلة ، والثالث كعدد صحيح آخر.

0
وأضاف
-1 لـ non-const char * .
وأضاف المؤلف Puppy, مصدر
أﻋﺗﻘد أن OP ﺗﺳﺄل ﻓﻌﻼً ﮐﯾف ﯾﻣﮐﻧﻧﺎ إﺟراء ﺗﻘﯾﯾم ﻣزدوج ﺑدون اﺳﺗﺧدام اﻟﻣﻌﺎﻟﺞ اﻟﻣﺳﺑق.
وأضاف المؤلف Dave Newton, مصدر