العبارات النصية في ++C
العبارات النصية
تعامل العبارات النصية strings في لغة السي كمصفوفات عناصرها من النوع المحرفي char وكأي من أنواع البيانات , قد تكون هذه العبارات ثابتة أو متغيرة
متغيرات العبارات النصية
إليك برنامج يسأل المستخدم إدخال عبارة نصية , ثم يظهرها له علي الشاشة :
stringin.cpp
// stringin.cpp
// simple string variable
#include <iostream.h>
#include <conio.h>
const int MAX = 80; // max characters in string
void main()
{
char str[MAX]; // string variable str
cout << "\nEnter a string: ";
cin >> str; // put string in str
cout << "You entered: " << str; // display string from str
getche();
}
في هذا البرنامج كان تعريف متغير العبارة النصية كتعريف أي مصفوفة عادية , نوع عناصرها محرفي , وحجمها 80 . وقد استخدمنا المؤثر >> لكي ندخل الحروف من لوحة المفاتيح إلي المصفوفة , ويبين المصفوفة , ويبين الشكل العبارة النصية في الذاكرة .
شكل عبارة نصية مخزنة
يحتل كل محرف بايتا واحدة كما سبق قوله , ولكن هناك خصيصة هامة في لغة السي , وهي أن العبارة النصية تنتهي دائما ببايت تحتوي علي الصفر , ليدل علي نهايتها , ويمثل عادة بالحرف '\0' , ويسمي المحرف الصفري null character . وحينما يظهر المؤثر << العبارة , فإنه يظل مستمرا في إظهار الحروف إلي أن يلتقي بالمحرف الصفري .
تلاقي تجاور حجم المصفوفة
سبق أن تحدثنا عن خطورة تجاوز حجم المصفوفة , ويمكن تلاقي ذلك عن طريق استخدام الدالة set() بعد أن تغذي بالحجم الأقصي للمصفوفة . والبرنامج التالي يستخدم هذه الفكرة .
safetyin.cpp
// safetyin.cpp
// avoids buffer overflow with cin.width
#include <iostream.h>
#include <iomanip.h> // for setw
#include <conio.h>
const int MAX = 20; // max characters in string
void main()
{
char str[MAX]; // string variable str
cout << "\nEnter a string: ";
cin >> setw(MAX) >> str; // put string in str,
// no more than MAX chars
cout << "You entered: " << str; // display string from str
getche();
}
ولن تدخل الدالة setw(MAX) في المصفوفة حروفا أكثر من المحدد بها . بل الحقيقة أنها تحدد عدد الحروف المخلة بأقل ممن العدد المبين في معاملها بواحد , حيث يكون البايت الأخيرة مشغولة بالمحرف الصفري .
ثوابت العبارة النصية
يمكنك استهلال العبارة النصية بعبارة ثابتة , كما نبين في البرنامج التالي :
strinit.cpp
// strinit.cpp
// initialized string
#include <iostream.h>
#include <conio.h>
void main()
{
char str[] = "Farewell! thou art too dear for my possessing";
cout << str;
getche();
}
وتلاحظ أن الاستهلال قد تم بعلامتي التنصيص المعتادين بينما استهلال المصفوفات يكون بضم عناصرها بين قوسين حلزونين , فكان المفروض أن يكون الاستهلال علي الصورة :
Char str[] = { 'F', 'a', 'r', 'e', …….};
هذه الميزة وضعها مصممو لغة السي تسهيلا لعملية إدخال الثوابت النصية . ولا تنس أن الحرف الأخير سيكون الصفر.
العبارة متعددة الكلمات
لو حاولت في البرنامج stringin.cpp إدخال عبارة مكونة من عدة كلمات , فسوف تخرج لك الكلمة الأولي قط . والسبب أن مؤثر الإدخال يعتبر المسافة إنهاء للإدخال . ولإدخال عبارة نصية متعددة الكلمات , تستخدم دالة أخري هي get() , وهي دالة منتمية , اسم المصفوفة وحجمها , علي النحو التالي :
Cin.get(str,MAX);
والبرنامج التالي يستخدم هذه الخاصية :
blanksin.cpp
// blanksin.cpp
// reads string with embedded blanks
#include <iostream.h>
#include <conio.h>
const int MAX = 80; // max characters in string
void main()
{
char str[MAX]; // string variable str
cout << "\nEnter a string: ";
cin.get(str, MAX); // put string in str
cout << "You entered: " << str; // display string from str
getche();
}
وتلاحظ أن الخلط بين الإدخال باستخدام الدالة cin.get() والطريقة المعتادة >> cin يسبب مشاكل جسيمة سوف , نتعرض لها في الفصل الحادي عشر , حيث أن معالجتها الأكبر هو البرامج الرسومية .
العبارة متعددة الأسطر
إذا كانت العبارة تحتوي علي أكثر من سطر , هنا تدخل الدالة cin::get() لإنقاذ الموقف أيضا , فهي يمكنها تتقبل معاملا ثالثا , يمثل نهاية الإدخال , والوضع المبدئي لهذا المعامل هو السطر الجديد (\n) , فإذا لم يدخل معامل ثالث تنهي الدالة الإدخال بمجرد الضرب علي مفتاح الإدخال سوف يقوم بعمله الطبيعي في النقل لسطر جديد , ولن ينتهي الإدخال إلا بالضرب علي الحرف المحدد للمعمل الثالث , ثم الضرب علي مفتاح الإدخال , وإليك تطبيق لذلك :
linesin.cpp
// linesin.cpp
// reads multiple lines, terminates on '$' character
#include <iostream.h>
#include <conio.h>
const int MAX = 2000; // max characters in string
char str[MAX]; // string variable str
void main()
{
cout << "\nEnter a string:\n";
cin.get(str, MAX, '$'); // terminate with $
cout << "You entered:\n" << str; // display string from str
getche();
}
وفي هذا البرنامج يتسبب الضرب علي مفتاح الإدخال الانتقال إلي سطر جديد , ولإنهاء البرنامج يضرب علي حرف $ ثم مفتاح الإدخال .
نسخ العبارات النصية – الطريقة الصعبة
أفضل طريقة لفهم الطبيعة الحقيقة للعبارات النصية هي التعامل معها محرفا بعد الأخر . وهاك برنامج يفعل ذلك :
strcopy1.cpp
// strcopy1.cpp
// copies a string using a for loop
#include <iostream.h>
#include <string.h> // for strlen()
#include <conio.h>
const int MAX = 80; // size of str2 buffer
void main()
{ // initialized string
char str1[] = "Oh, Captain, my Captain! "
"our fearful trip is done";
char str2[MAX]; // empty string
for(int j=0; j<strlen(str1); j++) // copy strlen characters
str2[j] = str1[j]; // from str1 to str2
str2[j] = '\0'; // insert null character
cout << endl;
cout << str2; // display str2
getche();
}
في هذا البرنامج نسخت محتويات المصفوفة str1[] في المصفوفة str2 باستخدام الدوارة المبنية , وفيها الأمر :
Str2[j] = str1[j];
وتلاحظ من خرج البرنامج أن محول الصياغة هنا قد وصل العبارتين النصيتين في عبارة واحدة .
ولما كانت لغة السي لا تتضمن العبارات النصية كأحد أنواع البيانات ] كما في لغات أخري [ , وبالتالي لا توجد مؤثرات تتعامل معها , فإنه توجد دوال مكتبية تقوم بهذا الغرض , وهي موجودة في ملف string.h ويقدم البرنامج أحد هذه الدوال ؛ strlen() , ] إختصار لـــ [ string length , وهي تعيد طول العبارة النصية , قد وضعت في الدوارة لتحدد لها وقت انتهائها . وتطلب استخدام هذه الدالة تضمين البرنامج الملف المكتبي المشار إليه .
ويجب أن تنهي النسخة من العبارة في المصفوفة الثانية بالمحرف الصفري تحديدا لنهايتها , وقد تم هذا بالأمر :
Str2[j] = '\0';
وفي حالة عدم تنفيذ ذلك , فإن المؤثر << سوف يظل يقرأ بقية أماكن الذاكرة المخصصة للعبارة النصية ] المحددة بالعدد المخصص للثابت MAX [ طالما لم يصادف المحرف الذي يدل علي إنتهاء العبارة , ويظهر ما بهذه الأماكن من أحرف عشوائية .
نسخ العبارات النصية – الطريقة السهلة
شكرا للدوال المكتبية في ملف string.h , فهي تضم دالة تغنينا عن هذا العناء , وهي الدالة strcpy() ] لعلك فهمت أن اسمها اختصار لـــ string copy [ , ومهمتها نسخ العبارات النصية , وسوف نعدل البرنامج السابق للإستفادة بهذه الإمكانية .
strcopy2.cpp
// strcopy2.cpp
// copies a string using strcpy() function
#include <iostream.h>
#include <string.h> // for strcpy()
#include <conio.h>
const int MAX = 80; // size of str2 buffer
void main()
{
char str1[] = "Tiger, tiger, burning bright\n"
"In the forests of the night";
char str2[MAX]; // empty string
strcpy(str2, str1); // copy str1 to str2
cout << endl;
cout << str2; // display str2
getche();
}
وكما تري تأخذ الدالة معاملين هما اسم المصفوفة النسخ فيها , واسم المصفوفة المطلوب النسخ منها وأنها تقوم بإضافة المحرف الصفري تلقائيا .
مصفوفات العبارات النصية
طالما يوجد مصفوفة لمصفوفة , فيوجد إذن مصفوفة للعبارات النصية , ولعلك توقعت أن تكون مصفوفة ثنائية الأبعاد . وسوف نقدم برنامجا يظهر أيام الأسبوع , كتطبيق علي هذه الإمكانية المفيدة .
straray.cpp
// straray.cpp
// array of strings
#include <iostream.h>
#include <conio.h>
const int DAYS = 7; // number of strings in array
const int MAX = 10; // maximum size of each string
void main()
{ // array of strings
char star[DAYS][MAX] = { "Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday",
"Friday", "Saturday" };
for(int j=0; j<DAYS; j++) // display every string
cout << star[j] << endl;
getche();
}
ولعلك لاحظت شيئا غير طبيعي في عبارة الوصول لعناصر المصفوفة :
Star[j];
حيث استخدم دليل واحد , رغم أن المصفوفة ذات بعدين , فكيف يستدل علي موضع العنصر دون الدليل الثاني ؟ الرد هو أن الدليل الأول يشير للمصفوفة الخارجية , وهذا كاف لمعرفة محتواها فهو مثبت بداية في عملية الاستهلال .
تعليقات
إرسال تعليق