اذهب إلى المحتوى

أدوات مكتبة stdlib في لغة سي C


Naser Dakhel

نستعرض هنا الأدوات الموجودة في ملف الترويسة <stdlib.h> الذي يصرح عن عدد من الأنواع والماكرو وعدة دوال للاستخدام العام، تتضمن الأنواع والماكرو التالي:

  • النوع size_t: تكلمنا عنه سابقًا.
  • النوع div_t: نوع من الهياكل التي تعيدها الدالة div.
  • النوع ldiv_t: نوع من الهياكل التي تعيدها الدالة ldiv.
  • النوع NULL: تكلمنا عنه سابقًا.
  • القيمة EXIT_FAILURE و EXIT_SUCCESS: يمكن استخدامهما مثل وسيط للدالة exit.
  • القيمة MB_CUR_MAX: العدد الأعظمي للبايتات في محرف متعدد البايتات multibyte character من مجموعة المحارف الإضافية والمحددة حسب إعدادت اللغة المحلية locale.
  • القيمة RAND_MAX: القيمة العظمى المُعادة من استدعاء دالة rand.

دوال تحويل السلسلة النصية

هناك ثلاث دوال تقبل سلسلة نصية وسيطًا لها وتحوّلها إلى عدد من نوع معين كما هو موضح هنا:

#include <stdlib.h>

double atof(const char *nptr);
long atol(const char *nptr);
int atoi(const char *nptr);

نحصل على عدد مُحوّل مُعاد لكل من الدوال الثلاث السابقة، ولا تضمن لك أيٌ من الدوال أن تضبط القيمة errno (إلا أن الأمر محقّق في بعض التنفيذات)، وتكون النتائج التي نحصل عليها من تحويلات تتسبب بحدوث طفحان overflow ولا يمكننا تمثيلها غير معرّفة.

هناك بعض الدوال أكثر تعقيدًا:

#include <stdlib.h>

double strtod(const char *nptr, char **endptr);
long strtol(const char *nptr, char **endptr, int base);
unsigned long strtoul(const char *nptr,char **endptr, int base);

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

  • في الدالة strtod: إشارة "+" أو "-" اختيارية في البداية متبوعة بسلسلة أرقام تحتوي على محرف الفاصلة العشرية الاختياري وأس exponent اختياري أيضًا. لا يُعترف على أي لاحقة عائمة (ما بعد الفاصلة العشرية)، وتُعدّ الفاصلة العشرية تابعةً لسلسلة الأرقام إذا وُجدت.
  • في الدالة strtol: إشارة "+" أو "-" اختيارية في البداية متبوعة بسلسلة أرقام، وتُؤخذ هذه الأرقام من الخانات العشرية أو من أحرف صغيرة lower case أو كبيرة upper case ضمن النطاق a إلى z في الأبجدية الإنجليزية ويُعطى لكل من هذه الأحرف القيم ضمن النطاق 10 إلى 35 بالترتيب. يحدِّد الوسيط base القيم المسموحة ويمكن أن تكون قيمة الوسيط صفر أو ضمن النطاق 2 إلى 36. يجري التعرُّف على الخانات التي تبلغ قيمتها أقل من الوسيط base، إذ تسمح القيمة 16 للوسيط base على سبيل المثال للمحارف 0x أو 0X أن تتبع الإشارة الاختيارية، بينما يسمح base بقيمة صفر أن تكون المحارف المدخلة على هيئة أعداد صحيحة ثابتة في سي، ولا يُعترف على أي لاحقة عدد صحيح.
  • في الدالة strtoul: مطابقة للدالة strtol إلا أنها لا تسمح بوجود إشارة.

يُخزّن عنوان أول محرف غير مُعترف عليه في الكائن الذي يشير إليه endptr في حال لم يكُن فارغًا، وتكون هذه قيمة nptr إذا كانت السلسلة فارغة أو ذات تنسيق خاطئ.

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

  • في الدالة strtod: تُعيد عند الطفحان القيمة HUGE_VAL± وتعتمد الإشارة على إشارة النتيجة، وتُعيد القيمة صفر عند طفحان الحد الأدنى underflow ويُضبط errno في الحالتين إلى القيمة ERANGE.
  • في الدالة strtol: تُعيد القيمة LONG_MAX أو LONG_MIN عند الطفحان بحسب إشارة النتيحة، ويُضبط errno في كلا الحالتين إلى القيمة ERANGE.
  • في الدالة strtoul: تُعيد القيمة ULONG_MAX عند الطفحان، ويُضبط errno إلى القيمة ERANGE.

قد يكون هناك سلاسل أخرى من الممكن التعرُّف عليها في بعض التنفيذات إذا لم تكن الإعدادات المحلية هي إعدادات سي التقليدية.

توليد الأرقام العشوائية

تقدِّم الدوال التالية طريقةً لتوليد الأرقام العشوائية الزائفة pseudo-random:

#include <stdlib.h>

int rand(void);
void srand(unsigned int seed);

تُعيد الدالة rand رقمًا عشوائيًا زائفًا ضمن النطاق من "0" إلى "RAND_MAX"، وهو ثابت قيمته على الأقل "32767".

تسمح الدالة srand بتحديد نقطة بداية للنطاق المُختار طبقًا لقيمة الوسيط seed، وهي ذات قيمة "1" افتراضيًا إذا لم تُستدعى srand قبل rand، ونحصل على سلسلة قيم مطابقة من الدالة rand إذا استخدمنا قيمة seed ذاتها.

يصف المعيار الخوارزمية المستخدمة في دالتي rand و srand، وتستخدم معظم التنفيذات هذه الخوارزمية عادةً.

حجز المساحة

تُستخدم هذه الدوال لحجز وتحرير المساحة، إذ يُضمن للمساحة التي حصلنا عليها أن تكون كبيرةً كفاية لتخزين كائن من نوع معين ومُحاذاة ضمن الذاكرة بحيث لا تتسبب بتفعيل استثناءات العنوان addressing exceptions، ولا يجب افتراض أي شيء آخر بخصوص عملها.

#include <stdlib.h>

void *malloc(size_t size);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);

void *free(void *ptr);

تُعيد جميع دوال حجز المساحة مؤشرًا يشير إلى المساحة المحجوزة التي يبلغ حجمها size بايت، وإذا لم يكن هناك أي مساحة فارغة فهي تعيد مؤشرًا فارغًا، إلا أن الفرق بين الدوال هو أن دالة calloc تأخذ وسيطًا يدعى nmemb الذي يحدد عدد العناصر في مصفوفة، وكل عنصر في هذه المصفوفة يبلغ حجمه size بايت، ولذا فهي تحجز مساحةً أكبر من التخزين عادةً من المساحة التي تحجزها malloc، كما أن المساحة المحجوز بواسطة malloc غير مُهيّئة بينما تُهيّأ جميع بتات مساحة التخزين المحجوزة بواسطة calloc إلى الصفر، إلا أن هذا الصفر ليس تمثيلًا مكافئًا للصفر ضمن الفاصلة العائمة floating-point أو مؤشرًا فارغًا null بالضرورة.

تُستخدم الدالة realloc لتغيير حجم الشيء المُشار إليه بواسطة المؤشر ptr مما يتطلب بعض النسخ لإنجاز هذا الأمر ومن ثمّ تُحرّر مساحة التخزين القديمة. لا تُغيّر محتويات الكائن المُشار إليه بواسطة ptr بالنسبة للحجمين القديم والجديد، وتتصرف الدالة تصرفًا مماثلًا لتصرف malloc إذا كان المؤشر ptr مؤشرًا فارغًا وذلك للحجم المخصّص.

تُستخدم الدالة free لتحرير المساحة المحجوزة مسبقًا من إحدى دوال حجز المساحة، ومن المسموح تمرير مؤشر فارغ إلى الدالة free وسيطًا لها، إلا أن الدالة في هذه الحالة لا تنفّذ أي شيء.

إذا حاولت تحرير مساحة لم تُحجز مسبقًا تحصل على سلوك غير محدّد، ويتسبب هذا الأمر في العديد من التنفيذات باستثناء عنوان addressing exception مما يوقف البرنامج، إلا أن هذه ليست بدلالة يمكن الاعتماد عليها.

التواصل مع البيئة

سنستعرض مجموعةً من الدوال المتنوعة:

#include <stdlib.h>

void abort(void);
int atexit(void (*func)(void));
void exit(int status);
char *getenv(const char *name);
int system(const char *string);
  • دالة abort: تتسبب بإيقاف غير اعتيادي للبرنامج وذلك باستخدام الإشارة SIGABRT، ويمكن منع الإيقاف غير الاعتيادي فقط إذا حصلنا على الإشارة ولم يُعد معالج الإشارة signal handler أي قيمة، وإلا ستُحذف ملفات الخرج وقد يمكن أيضًا إزالة الملفات المؤقتة بحسب تعريف التنفيذ، وتُعاد حالة "إنهاء برنامج غير ناجح unsuccessful termination" إلى البيئة المُستضافة، كما أن هذه الدالة لا يمكن أن تُعيد أي قيمة.
  • دالة atexit: يصبح وسيط الدالة func دالةً يمكن استدعاؤها دون استخدام أي وسطاء عندما يُغلق البرنامج، ويمكن استخدام ما لا يقل عن 32 دالة مشابهة لهذه الدالة وأن تُستدعى عند إغلاق البرنامج بصورةٍ مُعاكسة لتسجيل كلٍّ منها، ونحصل على القيمة المُعادة صفر للدلالة على النجاح وإلا فقيمة غير صفرية للدلالة على الفشل.
  • دالة exit: تُستدعى هذه الدالة عادةً لإنهاء البرنامج على نحوٍ اعتيادي، وتُستدعى عند تنفيذ الدالة جميع الدوال المُسجّلة باستخدام دالة atexit، لكن انتبه، إذ ستُعد الدالة main بحلول هذه النقطة قد أعادت قيمتها ولا يمكن استخدام أي كائنات ذات مدة تخزين تلقائي automatic storage duration على نحوٍ آمن، من ثمّ تُحذف محتويات جميع مجاري الخرج output streams وتُغلق وتُزال جميع الملفات التلقائية المُنشأة بواسطة tmpfile، وأخيرًا يُعيد البرنامج التحكم إلى البيئة المستضافة بإعادة حالة نجاح أو فشل محدّدة بحسب التنفيذ، وتعتمد الحالة على إذا ما كان وسيط الدالة exit مساوٍ للقيمة EXITSUCCESS (وهذه حالة النجاح) أو EXITFAILURE (حالة الفشل). للتوافق مع لغة سي القديمة، تُستخدم القيمة صفر بدلًا من EXITFAILURE، بينما يكون لباقي القيم تأثيرات معرّفة بحسب التنفيذ. لا يمكن أن تُعاد حالة الخروج.
  • دالة getenv: يجري البحث في لائحة البيئة environment list المعرفة بحسب التنفيذ بهدف العثور على عنصر يوافق السلسلة النصية المُشار إليها بواسطة وسيط الاسم name، إذ تُعيد الدالة مؤشرًا إلى العنصر يشير إلى مصفوفة لا يمكن تعديلها من قبل البرنامج ويمكن تعديلها باستدعاء لاحق للدالة getenv، ونحصل على مؤشر فارغ إذا لم يُعثر على عنصر موافق. يعتمد الهدف من لائحة البيئة وتنفيذها على البيئة المُستضافة.
  • دالة system: تُمرّر سلسلة نصية إلى أمر معالج مُعرف حسب التنفيذ، ويتسبب مؤشر فارغ بإعادة القيمة صفر، وقيمة غير صفرية إذا لم يكن الأمر موجودًا، بينما يتسبب مؤشر غير فارغ بمعالجة الأمر. نتيجة الأمر والقيمة المُعادة معرف حسب التنفيذ.

البحث والترتيب

هناك دالتان ضمن هذا التصنيف، أولهما دالة للبحث ضمن لائحة مُرتّبة والأخرى لترتيب لائحة غير مرتبة، واستخدام الدالتان عام، إذ يمكن استخدامهما في مصفوفات من أي سعة وعناصرها من أي حجم.

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

#include <stdlib.h>

void *bsearch(const void *key, const void *base,
        size_t nmemb, size_t size,
        int (*compar)(const void *, const void *));

void *qsort(const void *base, size_t nmemb,
        size_t size,
        int (*compar)(const void *, const void *));

يمثّل الوسيط nmemb في كلٍّ من الدالتين السابقتين عدد العناصر في المصفوفة، ويمثل الوسيط size حجم عنصر المصفوفة الواحد بالبايت و compar هي الدالة التي تُستدعى للمقارنة بين العنصرين، بينما يشير المؤشر base إلى أساس المصفوفة أي بدايتها.

ترتّب الدالة qsort المصفوفة ترتيبًا تصاعديًا.

تفترض الدالة bsearch أن المصفوفة مرتّبة مسبقًا وتُعيد مؤشرًا إلى أي عنصر يتساوى مع العنصر المُشار إليه بالمؤشر key، وتُعيد الدالة مؤشرًا فارغًا إذا لم تجد أي عناصر متساوية.

دوال العمليات الحسابية الصحيحة

تقدّم هذه الدوال طريقةً لإيجاد القيمة المطلقة لوسيط يمثل عدد صحيح، إضافةً لحاصل القسمة والباقي من العملية لكلٍّ من النوعين int و long.

#include <stdlib.h>

int abs(int j);
long labs(long j);

div_t div(int numerator, int denominator);
ldiv_t ldiv(long numerator, long denominator);
  • الدالتان abs و labs: تُعيدان القيمة المطلقة لوسيطهما ويجب اختيار الدالة المناسبة بحسب احتياجاتك. نحصل على سلوك غير معرّف إذا لم تكن القيمة ممكنة التمثيل وقد يحدث ذلك في الأنظمة التي تعمل بنظام المتمم الثنائي two's complement systems، إذ لا يوجد لأكثر رقم سلبيّة أي مكافئ إيجابي.
  • الدالتان div وldiv: تُقسّمان الوسيط numerator على الوسيط denominator وتُعيدان هيكلًا structure للنوع المحدد، وفي أي حالة، سيحتوي الهيكل على عضو يدعى quot يحتوي على حاصل القسمة الصحيحة وعضوًا آخر يدعى rem يحتوي على باقي القسمة، ونوع العضوين هو int في الدالة div و long في الدالة ldiv، ويمكن تمثيل نتيجة العملية على النحو التالي:
quot*denominator+rem == numerator

الدوال التي تستخدم المحارف متعددة البايت

يؤثر تصنيف LC_CTYPE ضمن الإعدادات المحلية الحالية على سلوك هذه الدوال، إذ تُضبط كل دالة إلى حالة ابتدائية باستدعاء يكون وسيطها s الذي يمثل مؤشر المحرف فارغًا null، وذلك في حالة الترميز المُعتمد على الحالة state-dependent endcoding، وتُغيَّر حالة الدالة الداخلية وفق الضرورة عن طريق استدعاءات لاحقة عندما لا يكون s مؤشرًا فارغًا. تُعيد الدالة قيمةً غير صفرية إذا كان الترميز معتمدًا على الحالة، وإلا فتعيد القيمة صفر إذا كان المؤشر s فارغًا. تصبح حالة الإزاحة shift state الخاصة بالدوال غير محددة indeterminate إذا حدث تغيير للتصنيف LC_TYPE.

الدوال هي:

#include <stdlib.h>

int mblen(const char *s, size_t n);
int mbtowc(wchar_t *pwc, const char *s, size_t n);
int wctomb(char *s, wchar_t wchar);
size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n);
size_t wcstombs(char *s, const wchar_t *pwcs, size_t n);
  • الدالة mblen: تُعيد عدد البايتات المُحتواة بداخل محرف متعدد البايتات multibyte character المُشار إليه بواسطة المؤشر s أو تُعيد القيمة ‎-1 إذا كان أول n بايت لا يشكّل محرف متعدد البايتات صالحًا، أو تُعيد القيمة صفر إذا كان المؤشر يشير إلى محرف فارغ.
  • الدالة mbtowc: تُحوِّل محرف متعدد البايتات يُشير إليه المؤشر s إلى الرمز الموافق له من النوع wchar_t وتُخزّن النتيجة في الكائن المُشار إليه بالمؤشر pwc، إلا إن كان pwc مؤشرًا فارغًا، وتُعيد الدالة عدد البايتات المُحوّلة بنجاح، أو ‎-1 إذا لم تشكّل أول n بايت محرفًا متعدد البايت صالحًا، ولا يُفحص أكثر من n بايت يُشير إليه المؤشر s، ولن تتعدى القيمة المُعادة قيمة n أو MB_CUR_MAX.
  • دالة wctmob: تُحوِّل رمز القيمة wchar إلى سلسلة من البايتات تمثل محرف متعدد البايتات وتخزن النتيجة في مصفوفة يشير إليها المؤشر s وذلك إن لم يكن s مؤشرًا فارغًا، وتُعيد الدالة عدد البايتات المحتواة داخل محرف متعدد البايتات، أو ‎-1 إذا كانت القيمة المخزنة في wchar لا تمثل محرف متعدد البايات، ومن غير الممكن معالجة عدد بايتات يتجاوز MB_CUR_MAX.
  • دالة mbstowcs: تحوّل سلسلة محارف متعددة البايتات بدءًا من الحالة الأولية للإزاحة initial shift state وذلك ضمن المصفوفة التي يشير إليها المؤشر s إلى سلسلة من الرموز الموافقة ومن ثم تخزّنها في مصفوفة يشير إليها المؤشر pwcs، لا يُخزّن ما يزيد عن n قيمة في pwcs، وتُعيد الدالة 1- إذا صادفت محرفًا متعدد البايت غير صالح، وإلا فإنها تعيد عدد عناصر المصفوفة المُعدّلة باستثناء رمز إنهاء المصفوفة.

نحصل على سلوك غير معرّف إذا وجد كائنين متقاطعين.

  • الدالة wcstombs: تُحوِّل سلسلة من الرموز المُشار إليها بالمؤشر pwcs إلى سلسلة من المحارف متعددة البايتات بدءًا من الحالة الأولية للإزاحة وتُخزّن فيما بعد في مصفوفة مُشار إليها بالمؤشر s. تتوقف عملية التحويل عند مصادفة رمز فارغ، أو عند كتابة n بايت إلى s، وتُعيد الدالة ‎-1 إذا كان الرمز المُصادف لا يمثل محرفًا متعدد البايتات صالحًا، وإلا فيُعاد عدد البايتات التي كُتبت باستثناء رمز الإنهاء الفارغ.

نحصل على سلوك غير محدد إذا وجد كائنين متقاطعين.

ترجمة -وبتصرف- لقسم من الفصل Libraries من كتاب The C Book.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...