التعامل مع المحارف والسلاسل النصية في لغة سي C
تُعتبر لغة البرمجة سي C من اللغات الأساسية التي تشكل حجر الزاوية في تعلم علوم الحاسوب والبرمجة، حيث تُستخدم في تطوير الأنظمة، البرمجيات، وحتى في برمجة الأجهزة المدمجة. ومن أهم الجوانب التي يتعامل معها المبرمجون في هذه اللغة هي المحارف (Characters) والسلاسل النصية (Strings)، حيث تلعب دوراً جوهرياً في عمليات الإدخال، الإخراج، معالجة النصوص، وبناء التطبيقات التي تتطلب التعامل مع البيانات النصية. لهذا، يكتسب فهم كيفية التعامل مع المحارف والسلاسل النصية في لغة سي أهمية كبيرة للغاية.
1. مفهوم المحارف (Characters) في لغة C
في لغة C، المحرف هو نوع بيانات أساسي يُخزن رمزًا واحدًا، ويُعرّف باستخدام النوع char. يمثل هذا النوع رموزًا فردية مثل الحروف، الأرقام، وعلامات الترقيم. من المهم ملاحظة أن المحارف في C تُخزن عادة في 1 بايت (8 بت) من الذاكرة، ما يسمح بتخزين 256 قيمة مختلفة (من 0 إلى 255 في حال كانت unsigned).
يتم تمثيل المحارف باستخدام علامات اقتباس مفردة 'A' أو '9'، وتتم معالجتها كقيم عددية (عادة قيم ASCII أو الترميز المستخدم). مثلاً، الحرف 'A' يُخزن كقيمة رقمية 65 في الترميز ASCII.
مثال تعريفي لمتغير محرف:
cchar letter = 'A';
القيم الرقمية للمحارف
يمكن استخدام القيم الرقمية بدلاً من المحارف مباشرة. فعلى سبيل المثال:
cchar ch = 65; // يعادل 'A' في ASCII
2. السلاسل النصية (Strings) في لغة C
السلسلة النصية هي مجموعة من المحارف المتتالية التي تمثل نصًا أو مجموعة حروف. في C، لا توجد نوع بيانات خاص للسلاسل النصية كما هو الحال في بعض اللغات الأخرى، بل تُعبّر السلاسل النصية بواسطة مصفوفة من المحارف char ينتهي بواحد خاص يسمى المحرف الصفري (null character) والذي يُمثّل بالرمز '\0'.
هذا المحرف هو مؤشر نهاية السلسلة، ومن دونه لا يستطيع المترجم معرفة نهاية النص.
تعريف سلسلة نصية
يمكن تعريف سلسلة نصية في C بطرق متعددة، منها:
cchar name[] = "Mohamed"; // مصفوفة من المحارف تحتوي على النص "Mohamed" تليها '\0'
أو بتعريفها كمصفوفة محارف وتعبئتها يدوياً:
cchar greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
3. كيفية تخزين السلاسل النصية في الذاكرة
السلاسل النصية في C تخزن كمصفوفة متجاورة من المحارف، وتنتهي بمحرف صفري '\0'، وهذا يعني أن أي عملية على سلسلة نصية يجب أن تراعي وجود هذا المحرف لضمان سلامة العمليات.
عند تعريف سلسلة نصية باستخدام الصيغة "text", المترجم يخصص مساحة في الذاكرة تضم الحروف متبوعة بـ '\0'.
مثلاً سلسلة "Hello" تُخزن في 6 خانات من الذاكرة:
| ‘H’ | ‘e’ | ‘l’ | ‘l’ | ‘o’ | ‘\0’ |
4. التعامل مع السلاسل النصية: القراءة والكتابة
طباعة السلاسل النصية
يستخدم دالة printf لطباعة النصوص، مع تحديد %s كمحدد لطباعة سلسلة نصية:
cchar message[] = "Hello, World!";
printf("%s\n", message);
قراءة السلاسل النصية
للقراءة من المستخدم يمكن استخدام دالة scanf مع محدد %s، لكنها تقرأ حتى أول مسافة أو نهاية السطر:
cchar name[50];
scanf("%s", name);
لكن هذه الطريقة قد تكون غير كافية عند الحاجة لقراءة نص يحتوي على مسافات. بدلاً منها يمكن استخدام:
-
gets(غير آمنة ولا يُنصح بها بسبب خطر تجاوز الحدود). -
fgetsوالتي تسمح بقراءة سطر كامل بأمان مع تحديد حد حجم المصفوفة.
مثال باستخدام fgets:
cchar line[100];
fgets(line, sizeof(line), stdin);
5. مكتبة التعامل مع السلاسل النصية
لغة C توفر مكتبة قياسية مخصصة لمعالجة السلاسل النصية وهي مكتبة . تحتوي هذه المكتبة على دوال متعددة تساعد في:
-
حساب طول السلسلة النصية.
-
نسخ النصوص.
-
مقارنة النصوص.
-
دمج النصوص.
-
البحث داخل النصوص.
أهم دوال مكتبة :
| الدالة | الوظيفة |
|---|---|
strlen(const char *s) |
تحسب طول السلسلة النصية بدون احتساب المحرف الصفري. |
strcpy(char *dest, const char *src) |
تنسخ نص من مصدر إلى هدف. |
strncpy(char *dest, const char *src, size_t n) |
تنسخ عدد محدود من المحارف. |
strcmp(const char *s1, const char *s2) |
تقارن بين سلسلتين نصيتين وتُرجع قيمة دلالة على التساوي. |
strcat(char *dest, const char *src) |
تدمج نص المصدر إلى نهاية نص الهدف. |
strstr(const char *haystack, const char *needle) |
تبحث عن نص معين داخل نص آخر وترجع مؤشر لأول ظهور. |
memset(void *s, int c, size_t n) |
تملأ منطقة في الذاكرة بقيمة معينة، مفيد لمصفوفات النصوص. |
أمثلة على استخدام بعض هذه الدوال:
حساب طول نص:
cchar str[] = "OpenAI";
size_t length = strlen(str); // length = 6
نسخ نص:
cchar source[] = "Hello";
char destination[10];
strcpy(destination, source); // destination يحتوي على "Hello"
مقارنة نصوص:
cchar a[] = "test";
char b[] = "test";
if (strcmp(a, b) == 0) {
// النصان متطابقان
}
6. مشكلات شائعة في التعامل مع المحارف والسلاسل النصية
6.1 عدم وجود محرف نهاية السلسلة
في حال عدم وجود '\0' في نهاية السلسلة، تتصرف دوال المكتبة بشكل غير متوقع، مما قد يؤدي إلى تجاوز حدود المصفوفة، وتحصل أخطاء في الذاكرة أو برامج متوقفة عن العمل.
6.2 تجاوز حدود المصفوفة (Buffer Overflow)
عدم مراعاة حجم المصفوفة عند إدخال أو نسخ النصوص قد يؤدي إلى الكتابة خارج حدود الذاكرة المخصصة، وهو من أكبر الأخطاء في البرمجة بلغة C ويؤدي إلى مشاكل أمنية حرجة.
6.3 عدم التعامل مع النصوص التي تحتوي على مسافات
استخدام scanf("%s", str) يقرأ فقط حتى أول فراغ، لذا يُفضل استخدام fgets أو طرق أخرى عند الحاجة لقراءة نص كامل.
7. كيفية إنشاء وتعديل السلاسل النصية
7.1 تعريف السلاسل النصية
cchar str1[] = "Hello"; // سلسلة نصية قابلة للتعديل
char *str2 = "World"; // سلسلة نصية ثابتة، غير قابلة للتعديل في بعض الأنظمة
7.2 تعديل محارف داخل السلسلة
يمكن تعديل المحارف داخل مصفوفة نصية معرفه، مثل:
cchar text[] = "Hello";
text[0] = 'J'; // يصبح "Jello"
لكن تعديل نص معرف كمؤشر على ثابت نصي يؤدي إلى سلوك غير معرف.
8. تمثيل المحارف الخاصة
بعض المحارف لا يمكن تمثيلها مباشرة، مثل محارف الأسطر الجديدة، الجدولة، أو علامات الاقتباس. في لغة C يمكن تمثيلها باستخدام الرموز الهاربة (escape sequences):
| الرمز الهارب | الوصف |
|---|---|
\n |
سطر جديد (newline) |
\t |
مسافة جدولة (tab) |
\\ |
شرطة مائلة للخلف |
\' |
علامة اقتباس مفردة |
\" |
علامة اقتباس مزدوجة |
مثال:
cprintf("Hello\tWorld\n");
9. التعامل مع المحارف الرقمية والرموز
في بعض التطبيقات، يحتاج المبرمج التعامل مع رموز غير نصية مثل الأرقام الثنائية أو تمثيل الرموز من جداول أخرى غير ASCII (مثل UTF-8). لغة C الأصلية لا تدعم بشكل مباشر النصوص متعددة البايت (multi-byte characters) أو الترميزات المعقدة، لكن يمكن استخدام مكتبات خارجية للتعامل مع الترميزات مثل:
-
مكتبة
iconvلتحويل الترميزات. -
مكتبة
wchar.hللتعامل مع محارف عريضة (wide characters) التي تسمح بدعم UTF-16 أو UTF-32.
10. دعم المحارف العريضة والسلاسل النصية متعددة البايت
تم تقديم أنواع بيانات مثل wchar_t التي تمثل المحارف العريضة (wide characters) بهدف دعم لغات متعددة تحتوي على أحرف أكبر من 1 بايت، مثل الحروف العربية، الصينية، اليابانية.
مثال:
c#include
wchar_t wideChar = L'ع';
wchar_t wideStr[] = L"مرحبا";
wprintf(L"%ls\n", wideStr);
11. أمثلة متقدمة في التعامل مع السلاسل النصية
11.1 دمج سلسلتين نصيتين
cchar str1[20] = "Hello, ";
char str2[] = "World!";
strcat(str1, str2);
// str1 تصبح "Hello, World!"
11.2 نسخ عدد معين من المحارف
cchar src[] = "Programming";
char dest[6];
strncpy(dest, src, 5);
dest[5] = '\0'; // تأكد من وجود محرف نهاية السلسلة
// dest تحتوي على "Progr"
12. جدول يلخص أنواع الدوال الرئيسية في مكتبة ووظائفها
| الدالة | الوظيفة | الملاحظات |
|---|---|---|
strlen() |
حساب طول السلسلة بدون \0 |
نوع الإرجاع: size_t |
strcpy() |
نسخ سلسلة نصية إلى أخرى | يجب التأكد من حجم الهدف |
strncpy() |
نسخ عدد معين من المحارف | لا تضمن وجود \0 تلقائياً |
strcmp() |
مقارنة سلسلتين نصيتين | إرجاع 0 للتساوي، قيمة أخرى لعدم التساوي |
strcat() |
دمج سلسلتين نصيتين | يجب أن يحتوي الهدف على مساحة كافية |
strchr() |
البحث عن محرف في سلسلة نصية | إرجاع مؤشر أول ظهور |
strstr() |
البحث عن سلسلة نصية داخل أخرى | إرجاع مؤشر أول ظهور أو NULL |
memset() |
ملأ منطقة من الذاكرة بقيمة معينة | مفيد لتهيئة المصفوفات |
13. خاتمة
يعتبر التعامل مع المحارف والسلاسل النصية في لغة C من المواضيع الحيوية والأساسية في البرمجة، حيث تتطلب مهارات دقيقة في التحكم بالذاكرة، فهم كيفية التخزين، وكيفية استخدام الدوال المتاحة لضمان كتابة برامج آمنة وفعالة. يعتمد نجاح المبرمج على إتقانه للتعامل مع هذه المفاهيم الأساسية، لا سيما في بيئات التطوير التي تتطلب سرعة الأداء والكفاءة العالية، كأنظمة التشغيل، البرامج المدمجة، وتطبيقات الحوسبة منخفضة المستوى.
بالرغم من أن لغة C لا توفر أنواع بيانات متقدمة للسلاسل النصية كما في اللغات الحديثة، إلا أن المرونة التي توفرها هذه اللغة مع المكتبات المتوفرة، بالإضافة إلى أدوات التوسع، تجعلها من أقوى اللغات في مجال التحكم المباشر بالبيانات النصية وذاكرة الحاسوب.
المصادر
-
كتاب: The C Programming Language – Brian W. Kernighan & Dennis M. Ritchie

