C++: سلاسل C
آخر تحديث: 2026-08-26
C++ لديها نوعان من السلاسل النصية:
- سلاسل C (مصفوفات محارف)
- سلسلة C++ (ستُغطى لاحقًا)
هذا الدرس يغطي سلاسل C أولًا — أنها إرث من C تحافظ عليه C++ للتوافق. فهمها يساعدك على إدراك المبادئ الأساسية للسلاسل النصية.
1. ما هي سلسلة C؟
(1) 1.1 الجوهر: مصفوفة محارف + منتهية بقيمة فارغة
سلسلة C هي ببساطة مصفوفة محارف، مع قاعدة خاصة:
- المحرف الأخير يجب أن يكون
\0(المحرف الفارغ، كود ASCII 0) \0يحدد نهاية السلسلة
"Hello" in memory:
+---+---+---+---+---+----+
| H | e | l | l | o | \0 |
+---+---+---+---+---+----+
0 1 2 3 4 5 ← indices
💡 نقطة مهمة: طول سلسلة C هو 5 (Hello)، لكن حجم المصفوفة يجب أن يكون 6 على الأقل (لتخزين \0).
2. التعريف والتهيئة
(1) 2.1 تعريف سلسلة C
الصياغة:
char stringName[Size];
مثال:
▶ مثال 2: تطبيق برمجي أساسي (صعوبة ⭐)
#include <iostream>
int main() {
char name[20]; // Can store 19 chars + 1 \0
name[0] = 'H';
name[1] = 'e';
name[2] = 'l';
name[3] = 'l';
name[4] = 'o';
name[5] = '\0'; // Don't forget the null terminator!
std::cout << "Name: " << name << std::endl; // Hello
return 0;
}
الخرج:
Name: Hello
💡 نصيحة: إضافة \0 يدويًا مملة — ستتعلم طرقًا أبسط لاحقًا.
(2) 2.2 تهيئة سلسلة C
الطريقة 1: التهيئة بثابت سلسلة نصية
#include <iostream>
int main() {
char name = "Hello"; // ✅ Compiler auto-adds \0, array size is 6
std::cout << "Name: " << name << std::endl;
return 0;
}
💡 نقطة مهمة: عند التهيئة بثابت سلسلة نصية، لا تحتاج لتحديد حجم المصفوفة — المترجم يحسبه تلقائيًا (بما في ذلك \0).
3. دوال السلاسل النصية الشائعة
دوال سلاسل C موجودة في ملف الرأس cstring.
(1) 3.1 strlen: حساب طول السلسلة
#include <iostream>
#include <cstring> // Must include this header
int main() {
char name = "Hello";
std::cout << "String: " << name << std::endl;
std::cout << "Length: " << std::strlen(name) << std::endl; // 5(excluding \0)
return 0;
}
💡 نصيحة: std::strlen تُرجع عدد المحارف الفعّالة (بدون \0)، بينما sizeof تُرجع حجم المصفوفة (بما في ذلك \0).
char name = "Hello";
std::cout << sizeof(name) << std::endl; // 6(Array size)
std::cout << std::strlen(name) << std::endl; // 5(effective character count)
(2) 3.2 strcpy: نسخ سلسلة
#include <iostream>
#include <cstring>
int main() {
char src = "Hello";
char dest[20];
std::strcpy(dest, src); // Copy src to dest
std::cout << "src:" << src << std::endl;
std::cout << "dest:" << dest << std::endl;
return 0;
}
⚠️ تحذير: std::strcpy لا تتحقق من حجم المصفوفة الهدف — إذا كان dest صغيرًا جدًا، ستسبب فيضان المخزن المؤقت!
دالة أكثر أمانًا (بعد C++11):
std::strncpy(dest, src, sizeof(dest) - 1); // Copy at most sizeof(dest)-1 characters
dest[sizeof(dest) - 1] = '\0'; // Manually add null terminator
(3) 3.3 strcat: ربط السلاسل
#include <iostream>
#include <cstring>
int main() {
char greeting[50] = "Hello, ";
char name = "World";
std::strcat(greeting, name); // Append name to greeting
std::cout << greeting << std::endl; // Hello, World
return 0;
}
(4) 3.4 strcmp: مقارنة السلاسل
#include <iostream>
#include <cstring>
int main() {
char str1 = "Hello";
char str2 = "Hello";
char str3 = "World";
std::cout << "strcmp(str1, str2) = " << std::strcmp(str1, str2) << std::endl;
std::cout << "strcmp(str1, str3) = " << std::strcmp(str1, str3) << std::endl;
return 0;
}
قيم الإرجاع:
0: السلسلتان متساويتان< 0: السلسلة الأولى أصغر من الثانية> 0: السلسلة الأولى أكبر من الثانية
💡 نصيحة: لا تستخدم == لمقارنة سلاسل C! == تُقارن العناوين، وليس المحتوى.
char str1 = "Hello";
char str2 = "Hello";
if (str1 == str2) { // ❌ Error: Comparing addresses, not content
// ...
}
if (std::strcmp(str1, str2) == 0) { // ✅ Correct:Use strcmp to compare content
// ...
}
4. التعامل مع سلاسل C باستخدام cin و cout
(1) 4.1 قراءة السلاسل
#include <iostream>
int main() {
char name[20];
std::cout << "Please enter your name: ";
std::cin >> name; // ✅ Can read strings (but no spaces)
std::cout << "Hello," << name << "!" << std::endl;
return 0;
}
💡 مشكلة: cin >> يتوقف عند المسافات! إذا أدخلت "John Smith"، سيقرأ فقط "John".
الحل: استخدم std::cin.getline
#include <iostream>
int main() {
char name[50];
std::cout << "Please enter your full name: ";
std::cin.getline(name, 50); // ✅ Read entire line (including spaces)
std::cout << "Hello," << name << "!" << std::endl;
return 0;
}
5. تطبيق: معالجة بسيطة للسلاسل
▶ مثال 1: عد حروف العلة في سلسلة (صعوبة ⭐⭐)
#include <iostream>
#include <cstring>
int main() {
char str[100];
std::cout << "Please enter a string: ";
std::cin.getline(str, 100);
int vowels = 0;
for (int i = 0; i < std::strlen(str); i++) {
char c = str[i];
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ||
c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U') {
vowels++;
}
}
std::cout << "Vowel count: " << vowels << std::endl;
return 0;
}
الخرج:
Please enter a string:
Vowel count:
نتيجة التشغيل:
Please enter a string: Hello World
Vowel count: 3
6. الأخطاء الشائعة
(1) 6.1 نسيان ترك مساحة لـ \0
مثال خطأ:
#include <iostream>
int main() {
char name[5] = "Hello"; // ❌ Error: "Hello" Need 6 chars (including \0), but array size is only 5
std::cout << name << std::endl;
return 0;
}
الإصلاح:
char name[6] = "Hello"; // ✅ Correct:Array size must be at least 6
(2) 6.2 استخدام = لإسناد سلسلة
مثال خطأ:
#include <iostream>
int main() {
char str1[20];
char str2 = "Hello";
str1 = str2; // ❌ Error: Cannot assign to array
str1 = "World"; // ❌ Error: Cannot assign to array
return 0;
}
الإصلاح: استخدم strcpy
#include <iostream>
#include <cstring>
int main() {
char str1[20];
char str2 = "Hello";
std::strcpy(str1, str2); // ✅ Correct:Use strcpy to copy
std::cout << str1 << std::endl;
return 0;
}
❓ أسئلة شائعة
س: متى أستخدم سلاسل C، ومتى أستخدم سلاسل C++؟ ج: فضّل سلاسل C++ (ستُغطى لاحقًا)، إلا إذا: > 1. كنت تُصيح كودًا قديمًا (كود C) > 2. كنت تقوم بتحسين منخفض المستوى جدًا (سلاسل C أكثر كفاءة)
سلاسل C++ أكثر أمانًا وسهولة في الاستخدام؛ موصى بها للمبتدئين.
س: لماذا
char name = "Hello"يعمل، لكنint arr = {1, 2, 3}لا يعمل؟ ج: فقط ثوابت السلاسل النصية يمكنها تهيئة مصفوفات المحارف مباشرة.CPPchar name = "Hello"; // OK int arr = {1, 2, 3}; // OK(this is an initializer list, not a string literal)
س: كيف أحول سلسلة C إلى سلسلة C++؟
ج: يمكنك الإسناد مباشرة (منشئ سلسلة C++ يتعامل مع التحويل تلقائيًا).
CPP`#include <iostream>` `#include <string>` `int main() {` `char cstr[] = "Hello";` `std::string cppStr = cstr; // Automatic conversion` `std::cout << cppStr << std::endl;` `return 0;` `}`
▶ مثال 3: طول السلسلة والنسخ (صعوبة ⭐)
#include <iostream>
#include <cstring>
int main() {
char src[] = "Hello";
char dest[20];
std::cout << "src length: " << strlen(src) << std::endl;
strcpy(dest, src);
std::cout << "After copy: " << dest << std::endl;
return 0;
}
الخرج:
src length: 5
After copy: Hello
strlen() للحصول على الطول و strcpy() للنسخ. تأكد أن المصفوفة الهدف كبيرة بما يكفي!
📖 ملخص
- سلاسل C هي مصفوفات محارف تنتهي بـ
\0 - الدوال الشائعة:
strlen(الطول)،strcpy(النسخ)،strcat(الربط)،strcmp(المقارنة) - لا تستخدم
==لمقارنة سلاسل C — استخدمstrcmp - لا تستخدم
=لإسناد سلاسل C — استخدمstrcpy - سلاسل C غير آمنة (عرضة لفيضان المخزن المؤقت)؛ فضّل سلاسل C++
📝 تمارين
-
أساسي (صعوبة ⭐): عرّف سلسلة C
char str = "Hello, World!"، ثم أخرج طولها وكل محرف فيها. -
متوسط (صعوبة ⭐⭐): اكتب برنامجًا يتيح للمستخدم إدخال سلسلتين ومقارنة ما إذا كانتا متساويتين (باستخدام
strcmp). -
تحدي (صعوبة ⭐⭐⭐): اكتب برنامجًا ينفذ "عكس السلسلة":
-
دع المستخدم يدخل سلسلة نصية
-
اعكسها (مثلاً،
"Hello"تصبح"olleH") -
نفّذها باستخدام سلاسل C (لا يُسمح بسلسلة C++)
- سلاسل C: مصفوفات محارف تنتهي بـ \0
- الدوال الشائعة: strlen/strcpy/strcat/strcmp
- سلاسل C تُهيَّأ بعلامات اقتباس مزدوجة؛ مصفوفات char يجب أن تحجز مساحة لـ \0
- العيوب: غير آمنة (فيضان المخزن المؤقت)، مرهقة في التعامل
- C++ الحديثة توصي باستخدام std::string بدلًا من سلاسل C
7. 🚀 الخطوة التالية
الآن بعد أن تعلمت سلاسل C، لنتابع إلى سلسلة C++ (الدرس 19) — صنف سلاسل نصية أكثر أمانًا وسهولة في الاستخدام!