|
| قسم لغات البرمجة php java c++ جافا Visual Basic فيجوال بيسك c# Delphi دلفي API PERL HTML و TML JavaScript ASP XML Oracle اوركال MySql sql server Access |
|
|
| F.Abdelaziz |
| مشاهدة ملفه الشخصي |
| زيارة موقع F.Abdelaziz المفضل |
| البحث عن كافة المشاركات المكتوبة بواسطة F.Abdelaziz |
| اعلانات |
|
||||||
|
السلاسل في C++ Strings in C++ نحن نعلم أن السلسلة string عبارة عن مصفوفة array من الأحرف characters . لنلقي نظرة على السلسلة ونعرف المزيد عنها. هناك نوعان مختلفان من السلاسل في C++ . • سلسلة على غرار (نمط) C C-style string (موروثة من لغة C ) • سلسلة الفئة std::string (جزء من مكتبة C++ القياسية ، تجعل العمل مع السلاسل فى C++ سهل ) في هذه الفقرة ، سوف نركز على سلسلة النمط C . سلسلة النمط C C-style String • إعلان السلسلة : يمكننا التفكير في السلسلة باعتبارها مصفوفة من الأحرف ، مثل "Sam" عبارة عن سلسلة وهي عبارة عن مصفوفة من الأحرف عناصرها 'S' و 'a' و 'm' و '\0' . كود:
element 'S' 'a' 'm' '\0' index 0 1 2 3 انظر إلى الحرف في الفهرس index 3 . إنه يمثل حرف null character . قيمة ASCII للحرف '\0' هي 0 وقيمة الحرف ‘0’ هي 48. وهو يمثل حرف إنهاء السلسلة. لذلك ، إذا أعلنا: - كود:
char name[ ]= "Sam"; فهذا يعنى : كود:
['S','a','m','\0'] ملاحظة : دائما نضع السلسلة بين أقواس اقتباس مزدوجة “ “ يمكننا أيضا أن نعلن متغير السلسلة باستخدام الحروف على النحو التالي : كود:
char name[ ]= { 'S', 'a', 'm', '\0'};
• طباعة (إخراج) السلسلة دعونا نرى مثالين لطباعة سلسلة ، أحدهما بدون والآخر بحلقة for . كود:
#include <iostream>
using namespace std;
int main()
{
char str[ ] = "Hello"; // Declaration
cout << str << endl;//Print , Output
return 0;
}
الخرج : كود:
Hello في المثال أعلاه ، قمنا بطباعة السلسلة بالكامل مرة واحدة. الآن ، دعونا نرى نفس المثال لطباعة الأحرف الفردية من السلسلة باستخدام حلقة for . كود:
#include <iostream>
using namespace std;
int main()
{
char str[ ] = "Hello";
int i;
for( i=0; i<6; i++)
{
cout << str[i];
}
return 0;
}
الخرج : كود:
Hello في المثال الأول ، قمنا بطباعة السلسلة بالكامل مرة واحدة. بينما في المثال الثاني ، قمنا بطباعة حرف في كل مرة. • إدخال السلسلة String Input الآن دعونا نرى كيفية إدخال سلسلة من المستخدم بمثال. كود:
#include <iostream>
using namespace std;
int main()
{
char name[20]; //declaring string 'name'
cin >> name; //taking string input
cout << name << endl; //printing string
return 0;
}
الخرج : كود:
Peter Peter العبارة : كود:
char name[20]; من خلال كتابة هذه العبارة ، فإننا نعلن عن مصفوفة من الأحرف المسماة 'name' ومنحناها حجم مصفوفة من 20 عنصر لأننا لا نعرف بالضبط طول السلسلة. وبالتالي ، احتلت مساحة في الذاكرة ذات حجم مطلوب من 20 حرفًا. لذلك ، لا يمكن للمصفوفة 'name' تخزين أكثر من 20 حرفًا. العبارة : كود:
cin >> name; تستخدم هذه العبارة ببساطة لإدخال سلسلة من المستخدم كما نفعل مع أنواع البيانات الأخرى وليس هناك شيء جديد في هذا. ملاحظة : يأخذ الكود أعلاه كلمة واحدة فقط من المستخدم إلى متغير السلسلة. وينتهي مع أي مسافة بيضاء. حاول أن تكتب شيئًا ما بعد الفراغ وسيأخذ الكلمة الأولى فقط. على سبيل المثال ، إذا قمنا في المثال أعلاه بإدخال Sam Brad كإسم ، فسيكون الإخراج هو Sam فقط لأن الكود يأخذ في الاعتبار كلمة واحدة فقط وينتهي بعد الكلمة الأولى (بعد مسافة بيضاء). • إدخال سلسلة من كلمات متعددة يمكننا أخذ مدخلات لسلسلة تتكون من أكثر من كلمة واحدة باستخدام الدالة cin.getline. لنرى مثالا: كود:
#include <iostream>
using namespace std;
int main()
{
char name[20]; //declaring string 'name'
cin.getline(name, sizeof(name)); //taking string input
cout << name << endl; //printing string
return 0;
}
الخرج : كود:
Sam Bard Sam Bard فى العبارة : كود:
cin.getline(name, sizeof(name)); تأخذ الدالة cin.getline وسيطين ، متغير السلسلة name وحجم هذا المتغير sizeof(name) . لقد استخدمنا الدالة sizeof للحصول على حجم متغير السلسلة 'name' . • تمرير السلاسل إلى الدوال هذا هو نفس ما نفعل مع المصفوفات الأخرى. الفرق الوحيد أن هنا مصفوفة من الأحرف . لنرى مثال . كود:
#include <iostream>
using namespace std;
void display( char ch[] )
{
cout << ch;
}
int main(){
char arr[30];
cout << "Enter a word" << endl;
cin >> arr;
display(arr);
return 0;
}
الخرج : كود:
Enter a word cpp cpp دوال السلسلة المعرفة مسبقا Predefined string functions يمكننا تنفيذ أنواع مختلفة من دوال السلسلة مثل ربط joining سلسلتين أو مقارنة comparing سلسلة بأخرى أو إيجاد طول السلسلة. دعونا نلقي نظرة على قائمة هذه الدوال . ![]() هذه الدوال المحددة مسبقًا جزء من مكتبة cstring. لذلك ، نحتاج إلى تضمين هذه المكتبة في الكود الخاص بنا عن طريق كتابة : كود:
#include <cstring> سنرى بعض أمثلة على الدوال strlen و strcpy و strcat و strcmp لأن هذه هي الأكثر شيوعًا. • الدالة strlen(s1) : لحساب طول السلسلة s1 . يتم حساب المسافة البيضاء فى طول السلسلة . كود:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char name[ ]= "Hello";
int len1, len2;
len1 = strlen(name);
len2 = strlen("Hello World");
cout << "Length of " << name << " = " << len1 << endl;
cout << "Length of " << "Hello World" << " = " << len2 << endl;
return 0;
}
الخرج : كود:
Length of Hello = 5 Length of Hello World = 11 ملاحظة : الدالة strlen لا تحسب حرف الإنتهاء ‘\0’ عند حساب طول السلسلة . • الدالة strcpy(s1, s2) تنسخ السلسلة الثانية s2 إلى السلسلة الأولى s1 . كود:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s2[ ]= "Hello";
char s1[10];
strcpy(s1, s2);
cout << "Source string " << s2 << endl;
cout << "Target string " << s1 << endl;
return 0;
}
الخرج : كود:
Source string Hello Target string Hello • الدالة strcat(s1, s2) تسلسل (تربط ) concatenates(joins) السلسلة الثانية s2 إلى السلسلة الأولى s1 كود:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s2[ ]= "World";
char s1[20]= "Hello";
strcat(s1, s2);
cout << "Source string " << s2 << endl;
cout << "Target string " << s1 << endl;
return 0;
}
الخرج : كود:
Source string World Target string HelloWorld لاحظ أنه في المثال أعلاه ،أعطينا حجم المصفوفة إلى السلسلة s1 لأننا نقوم بإضافة أحرف سلسلة أخرى إليها. يجب أن يكون حجم المصفوفة المعطى أكبر من أو يساوي حجم مصفوفة السلسلة بعد التسلسل (الربط) . • الدالة strcmp(s1, s2) تقارن سلسلتين وإيجاد ما إذا كانت متشابهة أم مختلفة. فهى تقارن أحرف السلسلتين حرف بحرف حتى يكون هناك عدم تطابق. إذا كانت السلسلتان متطابقتان identical ، فسوف تُرجع 0. وإذا لم تكن كذلك ، فتُرجع الفرق بين قيم ASCII للأزواج الأولى غير المطابقة من الأحرف. كود:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s1[ ]= "Hello";
char s2[ ]= "World";
int i, j;
i = strcmp(s1, "Hello");
j = strcmp(s1, s2);
cout << i << endl;
cout << j << endl;
return 0;
}
الخرج : كود:
0 -15 مصفوفة الأحرف ثتائية الأبعاد : كما هو الحال مع المصفوفة ثنائية الأبعاد من الأعداد الصحيحة وأنواع البيانات الأخرى ، لدينا مصفوفة ثنائية الأبعاد من الأحرف أيضًا. على سبيل المثال ، يمكننا كتابة كود:
char names[4][10] =
{
"Andrew",
"Kary",
"Brown",
"Lawren"
};
نظرًا لاستخدام السلسلة على نطاق واسع ، توفر C++ نوع بيانات سلسلة مضمّن سنتعلمه في الفقرة التالية . لا تستخدم سلاسل النمط C Don’t use C-style strings من المهم معرفة السلاسل ذات النمط C لأنها تستخدم في الكثير من الأكواد . ومع ذلك ، والآن بعد أن أوضحنا كيفية عملها ، سنوصي بتجنبها تمامًا كلما كان ذلك ممكنًا! ما لم يكن لديك سبب محدد وجذاب لاستخدام سلاسل النمط C ، استخدم الفئة std :: string (المعرفة في الرأس <string>) بدلاً من ذلك. الفئة std::string أسهل وأكثر أمانا وأكثر مرونة. |
| F.Abdelaziz |
| مشاهدة ملفه الشخصي |
| زيارة موقع F.Abdelaziz المفضل |
| البحث عن كافة المشاركات المكتوبة بواسطة F.Abdelaziz |
| اعلانات اضافية ( قم بتسجيل الدخول لاخفائها ) | |
|
|
|
||||||
|
السلسلة فى C++ باستخدام الفئة (النوع) std::string نظرًا لاستخدام السلسلة بشكل مكثف ، يوفر C++ نوع بيانات سلسلة مضمنة built-in . تمامًا مثل أنواع البيانات int أو float أو أنواع البيانات الأخرى ، يمكننا استخدام نوع بيانات السلسلة أيضًا. إنه ببساطة يجعل استخدام السلاسل أسهل. • مثل cin و cout ، يتم تعريف السلسلة أيضًا في مساحة الاسم std namespace . لاستخدام السلاسل بهذه الطريقة ، نحتاج إلى تضمين ملف الرأس حيث يتم الإعلان عنه في رأس البرنامج . يتم ضمه عن طريق كتابة : كود:
#include <string> • يتم إعلان declare المتغيرات من النوع std::string كما يلى : كود:
std::string name; فى حالة استخدام : كود:
using namespace std; كود:
string name; إى النوع ثم الاسم . هنا name متغير سلسلة تمامًا مثلما لدينا متغيرات int أو متغيرات float أو متغيرات أنواع بيانات أخرى. • نقوم بتعيين assign قيمة لمتغير السلسلة تمامًا كما نقوم بتعيين قيمة لمتغير من أي نوع بيانات آخر كما يلي : كود:
name = "Hall"; • يمكننا أيضًا تعيين قيمة لمتغير السلسلة في وقت الإعلان عنها كما يلى : كود:
std::string name("Hall");
متغير السلسلة مثله مثل أي متغير آخر. الآن دعونا نرى مثالا لطباعة سلسلة. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
name = "Hall";
cout << name << endl;
return 0;
}
الخرج : كود:
Hall • إدخال سلسلة Input a string تعرفنا بالفعل على كيفية إدخال سلسلة باستخدام مصفوفة أحرف. الآن ، دعونا ندخل سلسلة باستخدام متغير سلسلة. نحن ببساطة نستخدم cin لإدخال سلسلة كما اعتدنا على القيام به باستخدام مصفوفة الأحرف. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
cin >> name;
cout << name << endl;
return 0;
}
الخرج : كود:
Hall Hall • إدخال كلمات متعددة : كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
cin >> name;
cout << name << endl;
return 0;
}
الخرج : كود:
Hall Doe Hall كما في المثال أعلاه ، تأخذ cin أحرفًا فقط إلى مسافة بيضاء. وبالتالي متغير السلسلة name سوف يخزن فقط القيمة Hall . • إدخال سلسلة كلمات متعددة باستخدام الدالة std::getline لإدخال سلسلة متعدد الكلمات ، نستخدم الدالة std :: getline. دعونا نرى مثالا يأخذ مدخلات متعددة الكلمات. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
getline(cin, name);
cout << name << endl;
return 0;
}
الخرج : كود:
Hall Doe Hall Doe العبارة : كود:
std::getline(std::cin, name); هذا هو بناء جملة استخدام الدالة getline() . يتم تعريف الدالة getline() أيضًا في مساحة الاسم std namespace وبالتالي نكتبها std::getline . تأخذ الدالة getline() بارامترين . أول بارامتر هو std :: cin والثاني هو اسم متغير السلسلة name . إلحاق سلسلتين Append two strings يمكننا أن نسلسل concatenate السلاسل (ربط join السلاسل) باستخدام العامل + وإلحاق append سلسلة إلى أخرى باستخدام العامل += . كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string st1("Hello");
string st2("World");
cout << st1 + st2 << endl;
st1 += "cpp";
cout << st1 << endl;
return 0;
}
الخرج : كود:
HelloWorld Hellocpp في المثال أعلاه ، تقوم متغيرات السلسلة s1 و s2 بتخزين القيم "Hello" و "World" على التوالي. العبارة : كود:
cout << st1 + st2 << endl; مكافئة للعبارة : كود:
cout << st1 << st2 << endl; التى تطبع سلسلة تلو الأخرى. فى العبارة : [CODEst1 += "cpp"; ] [/CODE] أضفنا السلسلة "cpp" إلى قيمة المتغير st1 وبالتالي نجعل قيمته "Hellocpp". دوال الأعضاء Member Functions هناك العديد من الدوال الأعضاء في الفئة std :: string (الدوال المعرفة مسبقًا والمعرفة في std :: string) مثل length() ، size() ، resize() ، reserve() . دعونا ننظر في بعض هذه الدوال . • الدالة length() : يتم استخدام الدالة length() لإيجاد طول سلسلة. هذه الدالة معرفة مسبقًا والتى تنتمي إلى الفئة std :: string. دعونا نرى مثالا . كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
name = "I have 4 chocolates";
cout << name.length() << endl;
return 0;
}
الخرج : كود:
19 وهكذا فإن الدالة length() تُرجع طول السلسلة 'name' بما في ذلك أحرف المسافة البيضاء. • الدالة empty : تقوم الدالة empty()بإرجاع ما إذا كانت السلسلة فارغة empty أم لا. تقوم بإرجاع 1 إذا كان طول السلسلة 0 (فارغة) و 0 إذا لم تكن فارغة . كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1, s2;
s1 = "";
s2 = "Brownie";
cout << s1.empty() << endl;
cout << s2.empty() << endl;
return 0;
}
الخرج : كود:
1 0 نظرا لأن s1 تخزن سلسلة فارغة ، لذلك فإن الدالة s1.empty() ترجع 1 وحيث أن s2 تخزن السلسلة "Brownie" ، فإن s2.empty() ترجع 0 . • الدالة size() : تستخدم أيضًا لإرجاع طول السلسلة. وهى ترجع نفس القيمة التى ترجعها length() . كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
name = "I have 4 chocolates";
cout << name.size() << endl;
return 0;
}
الخرج : كود:
19 • الدالة resize() : تقوم دالة تغيير الحجم resize() بتغيير حجم السلسلة إلى الطول المحدد. افترض أن الطول المحدد هو 5. إذا كان الطول المحدد (على سبيل المثال 5) أصغر من الطول الحالي (افترض 7) ، فلن تحتوي السلسلة إلا على الأحرف الخمسة الأولى. إذا كان الطول المحدد (5) أكبر من الطول الحالي (افترض 3) ، فستحتوي السلسلة على 5 أحرف (3 من السلسلة الأصلية وحرفين محددين آخرين). دعونا نرى مثالا لفهم هذا. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "I love C";
int size = s.size(); // size of s
s.resize( size+2, '+' ); // resizing s
cout << s << endl;
return 0;
}
الخرج : كود:
I love C++ في هذا المثال ، قمنا أولاً بتخزين حجم (8) وهى القيمة الأصلية للسلسلة في المتغير size. العبارة : كود:
s.resize( size+2, '+' ); تقوم بتغيير حجم السلسلة ‘s’ إلى 'size + 2' أي 10 وتعيين الحرف ‘+’ إلى مكاني الأحرف الزائدين في السلسلة التي تم تغيير حجمها. • العامل operator[ ] : يقوم بإرجاع الحرف في موضع معين في سلسلة. دعنا نرى مثالا. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "I love C";
cout << "Character at fifth position : " << s[5] << endl;
return 0;
}
الخرج : كود:
Character at fifth position : e هنا ، تمثل s السلسلة بأكملها و تمثل s[i] حرفًا في السلسلة في الموضع ith. لاحظ أن موضع الحرف الأول في السلسلة هو 0. • الدالة at() : تقوم أيضًا بإرجاع الحرف في موضع معين في سلسلة. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "I love C";
cout << "Character at fifth position : " << s.at(5) << endl;
return 0;
}
الخرج : كود:
Character at fifth position : e • الدالة compare() : تقوم الدالة compare() بمقارنة قيمة السلسلة (str1) بسلسلة أخرى (str2). تقوم بإرجاع 0 إذا كانت كلا من السلاسل متساوية. تقوم بإرجاع قيمة موجبة إذا كانت str1> str2 أو الحرف الأول غير المتطابق من str1 أكبر من str2. تقوم بإرجاع قيمة سالبة إذا كانت str1 <str2 أو الحرف الأول غير المتطابق من str1 أقل من str2. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 ("have apple");
string str2 ("have app");
cout << str1.compare(str2) << endl;
return 0;
}
الخرج : كود:
2 هنا ، طول السلسلة 'str1' هو 2 أكثر من طول السلسلة 'str2'. لذلك ، يكون الناتج هو 2. إذا تم تبادل قيم 'str1' و 'str2' ، فسيكون الناتج -2 . لنرى مثال آخر : كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 ("have gpple");
string str2 ("have apple");
cout << str1.compare(str2) << endl;
return 0;
}
الخرج : كود:
1 هذه المرة ، أول حرف لا مثيل له في 'str1' و 'str2' هما 'g' و 'a' على التوالي. نظرًا لأن قيمة ASCII الخاصة بـ "g" أكبر من القيمة "a" ، فقد حصلنا على ناتج موجب . عند تبادل قيم السلاسل ، سنحصل على إجابة سالبة . • الدالة find() : الدالة find() توجد موضع التواجد الأول للحرف أو السلسلة في السلسلة. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 ("I love C++");
cout << str1.find('l') << endl;
return 0;
}
الخرج : كود:
2 في هذا المثال ، أعادت الدالة find() موضع الحرف ‘l’ في السلسلة str1. الآن ، دعونا نرى مثالًا لإيجاد موضع سلسلة في سلسلة أخرى. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 ("I love C++");
string str2 ("C++");
cout << str1.find(str2) << endl;
return 0;
}
الخرج : كود:
7 • الدالة substr() : ترجع الدالة substr() سلسلة فرعية substring من سلسلة بتحديد موضعها. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 ("I love C++");
cout << str1.substr(3) << endl;
return 0;
}
الخرج : كود:
ove C++ المثال أعلاه يطبع كل الحروف من الموضع 3 حتى نهاية السلسلة str1. كود:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 ("I love C++");
cout << str1.substr(3,5) << endl;
return 0;
}
الخرج : كود:
ove C هنا ، تم طباعة 5 أحرف تبدأ من الموضع 3. |
|
||||||
|
المؤشرات Pointers المؤشرات هي غول البرمجة بلغة C++ (و C)، سنحاول في هذا الدرس إزالة الغموض عن المؤشرات وإظهار الاستخدامات العملية لها في برمجة C++ . ما هي استخدامات المؤشرات ؟ فيما يلي بعض الاستخدامات الشائعة: • الوصول Accessing إلى عناصر مصفوفة . • تمرير Passing الوسائط إلى دالة عندما تحتاج الدالة إلى تعديل الوسيط الأصلى . • تمرير Passing المصفوفات والسلاسل إلى الدوال . • الحصول على Obtaining الذاكرة من النظام . • إنشاء Creating هياكل البيانات مثل القوائم المرتبطة linked lists . العناوين والمؤشرات Addresses and Pointers الأفكار وراء المؤشرات ليست معقدة. إليك المفهوم الرئيسي الأول : لكل بايت byte في ذاكرة الكمبيوتر عنوان address . العناوين هي أعداد numbers ، تمامًا كما هي الحال بالنسبة للمنازل في الشارع . تبدأ الأرقام من 0 وتصعد ، 1 ، 2 ، 3 ، وهكذا. إذا كان لديك 1 ميغابايت من الذاكرة ، فإن أعلى عنوان هو 1,048,575 . (بالطبع لديك أكثر من ذلك بكثير.) يشغل (يحتل) برنامجك ، عند تحميله في الذاكرة ، نطاقًا معينًا من هذه العناوين. هذا يعني أن كل متغير وكل دالة في البرنامج الخاص بك تبدأ في عنوان معين. يوضح الشكل كيف يبدو هذا. ![]() الشكل يبين عناوين الذاكرة Memory addresses • عامل العنوان The Address-of Operator & يمكنك إيجاد العنوان الذي يشغله متغير باستخدام عامل العنوان & . إليك برنامج قصير ، VARADDR ، يوضح كيفية القيام بذلك : كود:
// varaddr.cpp
// addresses of variables
#include <iostream>
using namespace std;
int main()
{
int var1 = 11; //define and initialize
int var2 = 22; //three variables
int var3 = 33;
cout << &var1 << endl //print the addresses
<< &var2 << endl //of these variables
<< &var3 << endl;
return 0;
}
يعرّف هذا البرنامج البسيط ثلاثة متغيرات من نوع العدد الصحيح int ، ويقوم بتهيئتها إلى القيم 11 و 22 و 33. ثم يقوم بطباعة عناوين هذه المتغيرات. تعتمد العناوين الفعلية التي تشغلها المتغيرات في البرنامج على العديد من العوامل ، مثل الكمبيوتر الذي يعمل عليه البرنامج ، وحجم نظام التشغيل ، وما إذا كانت هناك أي برامج أخرى موجودة حاليًا في الذاكرة. لهذه الأسباب ، ربما لن تحصل على نفس العناوين التي حصلنا عليها عند تشغيل هذا البرنامج. (قد لا تحصل على نفس النتائج مرتين على التوالي.) وإليك الإخراج على الجهاز الذى لدينا: كود:
0x8f4ffff4 ← address of var1 0x8f4ffff2 ← address of var2 0x8f4ffff0 ← address of var3 تذكر أن عنوان المتغير لا يشبه محتوياته على الإطلاق. محتويات المتغيرات الثلاثة هي 11 و 22 و 33. ويبين الشكل المتغيرات الثلاثة في الذاكرة. ![]() الشكل يبين عناوين ومحتويات المتغيرات Addresses and contents of variables يفسر interprets عامل الإدراج << العناوين في النظام السداسي عشري ، كما هو مبين بالبادئة 0x قبل كل عدد . هذه هي الطريقة المعتادة لإظهار عناوين الذاكرة. إذا لم تكن على دراية بنظام الأرقام السداسية عشرية ، فلا تقلق. كل ما تحتاج إلى معرفته هو أن كل متغير يبدأ في عنوان فريد. ومع ذلك ، قد تلاحظ في الإخراج أن كل عنوان يختلف عن العنوان التالي بمقدار 2 بايت بالضبط. ذلك لأن الأعداد الصحيحة تشغل 2 بايت من الذاكرة (على نظام 16 بت). إذا استخدمنا متغيرات نوع char ، فستكون لديها عناوين متجاورة ، حيث أن char يشغل بايت واحد ؛ وإذا استخدمنا النوع double ، فستختلف العناوين بمقدار 8 بايت. تظهر العناوين بترتيب تنازلي لأنه يتم تخزين المتغيرات المحلية local على المكدس stack ، والذي ينمو نزولا في الذاكرة. إذا كنا قد استخدمنا المتغيرات العامة global ، فسيكون لها عناوين تصاعدية ، حيث يتم تخزين المتغيرات العامة على الكومة heap ، التي تنمو للأعلى. مرة أخرى ، لا داعي للقلق بشأن هذه الاعتبارات ، لأن المترجم يتتبع التفاصيل نيابة عنك . لا تخلط بين عامل العنوان & ، الذي يسبق اسم المتغير في إعلان متغير ، مع عامل المرجع & ، الذي يتبع اسم النوع في النموذج الأولي للدالة أو التعريف. (تم مناقشة المراجع فى درس الدوال ) • متغيرات المؤشر Pointer Variables العناوين في حد ذاتها محدودة إلى حد ما. من الجيد أن نعرف أنه يمكننا معرفة أين توجد الأشياء في الذاكرة ، كما فعلنا في VARADDR ، لكن طباعة قيم العنوان ليست كل الإفادة . تتطلب إمكانية زيادة قوة البرمجة لدينا فكرة إضافية : "المتغيرات التي تحتوي على قيم العنوان" . لقد رأينا أنواعًا متغيرة تخزن الأحرف والأعداد الصحيحة وأرقام الفاصلة العائمة وما إلى ذلك. يتم تخزين العناوين بالمثل. يُطلق على المتغير الذي يحمل قيمة العنوان اسم متغير المؤشر pointer variable ، أو ببساطة المؤشر pointer. ما هو نوع بيانات متغيرات المؤشر؟ قد تعتقد أن نوع بيانات المؤشر سيطلق عليه شيء مثل pointer أو ptr. ومع ذلك ، فإن الأمور أكثر تعقيدا قليلا. يعرض البرنامج التالي ، PTRVAR ، بناء جملة متغيرات المؤشر. كود:
// ptrvar.cpp
// pointers (address variables)
#include <iostream>
using namespace std;
int main()
{
int var1 = 11; //two integer variables
int var2 = 22;
cout << &var1 << endl //print addresses of variables
<< &var2 << endl << endl;
int* ptr; //pointer to integers
ptr = &var1; //pointer points to var1
cout << ptr << endl; //print pointer value
ptr = &var2; //pointer points to var2
cout << ptr << endl; //print pointer value
return 0;
}
يعرف هذا البرنامج متغيرين لعددين صحيحين integer variables ، var1 و var2 ، ويقوم بتهيئتهما للقيمتين 11 و 22. ثم يقوم بطباعة عناوينهما. بعد ذلك يعرّف البرنامج متغير مؤشر pointer variable في السطر : كود:
int* ptr; للمبتدئين هذا بناء جملة غريب إلى حد ما. علامة النجمة (*) تعني المؤشر إلى pointer to . وبالتالي فإن العبارة تعرف المتغير ptr كمؤشر إلى int. هذه طريقة أخرى للقول أن هذا المتغير يمكنه الاحتفاظ بعناوين متغيرات الأعداد الصحيحة. ما الخطأ في فكرة نوع مؤشر للأغراض العامة يحمل مؤشرات إلى أي نوع بيانات؟ إذا أطلقنا عليه النوع pointer ، فيمكننا كتابة إعلانات مثل كود:
pointer ptr; المشكلة هي أن المترجم يحتاج إلى معرفة نوع المتغير الذي يشير إليه المؤشر. (سنرى لماذا عندما نتحدث عن المؤشرات والمصفوفات .) يسمح بناء الجملة المستخدم في C++ بالإعلان عن أي نوع من المؤشرات: كود:
char* cptr; // pointer to char int* iptr; // pointer to int float* fptr; // pointer to float Distance* distptr; // pointer to user-defined Distance class وهكذا . • جدال حول بناء الجملة Syntax تجدر الإشارة إلى أنه من الشائع كتابة تعريفات المؤشر مع وجود علامة النجمة أقرب إلى اسم المتغير من النوع . كود:
char *charptr; هذا لا يهم المترجم ، لكن وضع علامة النجمة بجوار النوع يساعد في التأكيد على أن علامة النجمة جزء من نوع المتغير (مؤشر إلى حرف pointer to char ) ، وليست جزءًا من الاسم نفسه. إذا قمت بتعريف أكثر من مؤشر واحد من نفس النوع في سطر واحد ، فأنت بحاجة فقط إلى إدراج النوع المشار إليه مرة واحدة ، ولكن عليك وضع علامة نجمة قبل كل اسم متغير. كود:
char* ptr1, * ptr2, * ptr3; // three variables of type char* يمكنك استخدام نهج علامة النجمة بجوار الاسم . كود:
char *ptr1, *ptr2, *ptr3; // three variables of type char* • يجب أن تحتوي المؤشرات على قيمة يمكن اعتبار عنوان مثل 0x8f4ffff4 كثابت مؤشر pointer constant. يمكن اعتبار مؤشر مثل ptr كمتغير مؤشر pointer variable . مثلما يمكن تعيين متغير العدد الصحيح var1 القيمة الثابتة 11 ، كذلك يمكن تعيين متغير المؤشر ptr القيمة الثابتة 0x8f4ffff4 . عند تعريف المتغير لأول مرة ، فإنه لا يحمل أي قيمة (ما لم نقم بتهيئته في نفس الوقت). قد يحتوي على قيمة نفايات ، ولكن هذا ليس له معنى. في حالة المؤشرات ، فإن قيمة بيانات النفايات هي عنوان شيء ما في الذاكرة ، ولكن ربما لا يتعلق بأي شيء نريده. لذلك قبل استخدام المؤشر ، يجب وضع عنوان محدد فيه. في برنامج PTRVAR ، يتم تعيين ptr أولاً بعنوان var1 في السطر كود:
ptr = &var1; ← put address of var1 in ptr بعد ذلك ، يقوم البرنامج بطباعة القيمة الموجودة في ptr ، والتي يجب أن تكون هي نفس العنوان المطبوع &var1 . ثم يتم تعيين نفس المتغير المؤشر ptr بعنوان var2 ، ويتم طباعة هذه القيمة. يوضح الشكل تشغيل برنامج PTRVAR. ![]() الشكل يبين تغيير القيم فى المؤشر ptr إليك إخراج PTRVAR: كود:
0x8f51fff4 ←address of var1 0x8f51fff2 ← address of var2 0x8f51fff4 ← ptr set to address of var1 0x8f51fff2 ← ptr set to address of var2 الملخص : يمكن أن يحتوي المؤشر على عنوان أي متغير من نوع العدد الصحيح ؛ إنه وعاء في انتظار عنوان . ومع ذلك ، يجب منحه قيمة ، أو سيشير إلى عنوان لا نريد أن نشير إليه ، كما هو الحال في كود البرنامج أو نظام التشغيل لدينا. يمكن أن تؤدي قيم مؤشر ضال (مشرد) إلى تعطل النظام ويصعب تصحيحها ، لأن المترجم لا يعطي أي تحذير. المغزى : تأكد من إعطاء كل متغير مؤشر قيمة عنوان صالحة قبل استخدامه. • الوصول إلى المتغير ألمشار إليه Accessing the Variable Pointed To افترض أننا لا نعرف اسم المتغير ولكننا نعرف عنوانه. هل يمكننا الوصول إلى محتويات المتغير؟ (قد يبدو الأمر وكأنه سوء إدارة لفقدان أسماء المتغيرات ، لكننا سنرى قريبًا أن هناك العديد من المتغيرات التي لا نعرف أسماءها.) يوجد بناء جملة خاص للوصول إلى قيمة المتغير باستخدام عنوانه بدلاً من اسمه. إليك مثال على ذلك ، برنامج ، PTRACC ، يوضح كيفية تنفيذه: كود:
// ptracc.cpp
// accessing the variable pointed to
#include <iostream>
using namespace std;
int main()
{
int var1 = 11; //two integer variables
int var2 = 22;
int* ptr; //pointer to integers
ptr = &var1; //pointer points to var1
cout << *ptr << endl; //print contents of pointer (11)
ptr = &var2; //pointer points to var2
cout << *ptr << endl; //print contents of pointer (22)
return 0;
}
يشبه هذا البرنامج برنامج PTRVAR ، باستثناء أنه بدلاً من طباعة قيم العنوان في ptr ، فإننا نقوم بطباعة قيمة العدد الصحيح المخزنة في العنوان المخزن في ptr. إليك الإخراج: كود:
11 22 التعبير الذي يصل إلى المتغيرات var1 و var2 هو *ptr ، والذي يحدث في كل من جملتي cout. عند استخدام علامة النجمة (*) أمام اسم متغير ، كما هو الحال في التعبير *ptr ، يطلق عليه عامل dereference (أو أحيانًا عامل indirection ). وهذا يعني "قيمة المتغير المشار إليه بواسطة" . وبالتالي فإن التعبير *ptr يمثل قيمة المتغير الذي يشير إليه ptr. عندما يتم تعيين ptr على عنوان var1 ، يكون التعبير *ptr له القيمة 11 ، لأن var1 هو 11. عندما يتم تغيير ptr إلى عنوان var2 ، يكتسب التعبير *ptr القيمة 22 ، لأن var2 هو 22. اسم آخر بالنسبة لعامل dereference هو عامل contents of ، وهي طريقة أخرى لقول نفس الشيء. يوضح الشكل كيف يبدو هذا. ![]() الشكل يبين الوصول عبر المؤشر Access via pointer يمكنك استخدام المؤشر ليس فقط لعرض قيمة المتغير ، ولكن أيضًا لتنفيذ أي عملية تقوم بها على المتغير مباشرةً. فيما يلي برنامج ، PTRTO ، يستخدم مؤشرًا لتعيين قيمة لمتغير ، ثم لتعيين هذه القيمة لمتغير آخر: كود:
// ptrto.cpp
// other access using pointers
#include <iostream>
using namespace std;
int main()
{
int var1, var2; //two integer variables
int* ptr; //pointer to integers
ptr = &var1; //set pointer to address of var1
*ptr = 37; //same as var1=37
var2 = *ptr; //same as var2=var1
cout << var2 << endl; //verify var2 is 37
return 0;
}
تذكر أن علامة النجمة المستخدمة كعامل dereference لها معنى مختلف عن علامة النجمة المستخدمة في الإعلان عن متغيرات المؤشر. يسبق العامل dereference المتغير ويعني "قيمة المتغير المشار إليه بواسطة". علامة النجمة المستخدمة في الإعلان تعني "المؤشر إلى" . كود:
int* ptr; //declaration: pointer to int *ptr = 37; //indirection: value of variable pointed to by ptr يسمى استخدام عامل dereference للوصول إلى القيمة المخزنة في عنوان "عنونة غير مباشرة" indirect addressing ، أو في بعض الأحيان "إلغاء المؤشر" dereferencing. • فيما يلي ملخص لما تعلمناه حتى الآن: كود:
int v; //defines variable v of type int int* p; //defines p as a pointer to int p = &v; //assigns address of variable v to pointer p v = 3; //assigns 3 to v *p = 3; //also assigns 3 to v توضح العبارتان الأخيرتان الفرق بين العنونة العادية أو المباشرة ، حيث نشير إلى متغير بالاسم ، والمؤشر أو العنونة غير مباشرة ، حيث نشير إلى المتغير نفسه باستخدام عنوانه . في الأمثلة على البرامج التي أظهرناها حتى الآن في هذا الدرس ، لا توجد ميزة لاستخدام تعبير المؤشر للوصول إلى المتغيرات ، حيث يمكننا الوصول إليها مباشرة. تصبح قيمة المؤشرات واضحة عندما يتعذر عليك الوصول إلى متغير مباشرةً ، كما سنرى لاحقًا. • مؤشر إلى الفراغ Pointer to void قبل أن ننتقل لرؤية المؤشرات في العمل ، يجب أن نلاحظ خصوصية أنواع بيانات المؤشر. عادةً ، يجب أن يكون العنوان address الذي تضعه في المؤشر هو نفس نوع المؤشر. لا يمكنك تعيين عنوان متغير float لمؤشر int ، على سبيل المثال: كود:
float flovar = 98.6; int* ptrint = &flovar; //ERROR: can’t assign float* to int* ومع ذلك ، هناك استثناء لهذا. يوجد نوع مؤشر للأغراض العامة يمكن أن يشير إلى أي نوع بيانات. وهذا ما يسمى مؤشر للفراغ (خالى) pointer to void ، ويتم تعريفه مثل هذا: كود:
void* ptr; //ptr can point to any data type هذه المؤشرات لها استخدامات متخصصة معينة ، مثل تمرير المؤشرات إلى دوال والتى تعمل بشكل مستقل عن نوع البيانات المشار إليها. المثال التالي يستخدم مؤشرًا إلى void ويوضح أيضًا أنه إذا كنت لا تستخدم void ، فيجب أن تكون حريصًا على تعيين المؤشرات والعنوان من نفس النوع مثل المؤشر. إليك القائمة PTRVOID: كود:
// ptrvoid.cpp
// pointers to type void
#include <iostream>
using namespace std;
int main()
{
int intvar; //integer variable
float flovar; //float variable
int* ptrint; //define pointer to int
float* ptrflo; //define pointer to float
void* ptrvoid; //define pointer to void
ptrint = &intvar; //ok, int* to int*
// ptrint = &flovar; //error, float* to int*
// ptrflo = &intvar; //error, int* to float*
ptrflo = &flovar; // ok, float* to float*
ptrvoid = &intvar; //ok, int* to void*
ptrvoid = &flovar; //ok, float* to void*
return 0;
}
يمكنك تعيين عنوان intvar إلى ptrint لأنهما كلاهما int* ، لكن لا يمكنك تعيين عنوان flovar إلى ptrint لأن الأول هو نوع float* والثاني هو نوع int* . ومع ذلك ، يمكن إعطاء ptrvoid أي قيمة مؤشر ، مثل int* ، لأنها مؤشر إلى void . |
|
||||||
|
المؤشرات والمصفوفات Pointers and Arrays هناك ارتباط وثيق بين المؤشرات والمصفوفات. لقد رأينا كيفية الوصول إلى عناصر المصفوفة. البرنامج التالي ، ARRNOTE ، يوفر مراجعة. كود:
// arrnote.cpp
// array accessed with array notation
#include <iostream>
using namespace std;
int main()
{ //array
int intarray[5] = { 31, 54, 77, 52, 93 };
for(int j=0; j<5; j++) //for each element,
cout << intarray[j] << endl; //print value
return 0;
}
تقوم عبارة cout بطباعة كل عنصر في المصفوفة كل فى دوره. على سبيل المثال ، عندما تكون j هي 3 ، يأخذ التعبير intarray[j] قيمة intarray[3] ويصل إلى عنصر المصفوفة الرابع ، العدد الصحيح 52. إليك خرج ARRNOTE: كود:
31 54 77 52 93 والمثير للدهشة أن عناصر المصفوفة يمكن الوصول إليها باستخدام تدوين (بدلالة) المؤشر وكذلك تدوين المصفوفة . المثال التالي ، PTRNOTE ، يشبه ARRNOTE فيما عدا أنه يستخدم تدوين المؤشر. كود:
// ptrnote.cpp
// array accessed with pointer notation
#include <iostream>
using namespace std;
int main()
{ //array
int intarray[5] = { 31, 54, 77, 52, 93 };
for(int j=0; j<5; j++) //for each element,
cout << *(intarray+j) << endl; //print value
return 0;
}
التعبير *(intarray+j) في PTRNOTE له نفس التأثير تمامًا مثل intarray[j] في ARRNOTE ، وخرج البرنامج مماثل. لكن كيف نفسر التعبير *(intarray+j) ؟ افترض أن j هي 3 ، وبالتالي فإن التعبير يكافئ *(intarray+3) . نريد أن يمثل هذا محتويات العنصر الرابع للمصفوفة (52). تذكر أن اسم المصفوفة هو عنوانها. التعبير intarray + j هو بالتالي عنوان مع إضافة شيء إليه. قد تتوقع أن intarray + 3 يؤدي إلى إضافة 3 بايت إلى intarray. لكن هذا لا ينتج النتيجة التي نريدها : intarray هي مصفوفة من الأعداد الصحيحة ، و 3 بايت في هذه المصفوفة هي منتصف العنصر الثاني ، وهي ليست مفيدة للغاية. نريد الحصول على العدد الصحيح الرابع في المصفوفة ، وليس البايت الرابع ، كما هو موضح في الشكل. (هذا الشكل يفترض أعداد صحيحة 2 بايت.) ![]() الشكل يبين العد بالأعداد الصحيحة Counting by integers برنامج مترجم C++ ذكي بما يكفي لأخذ حجم البيانات في الاعتبار عندما ينفذ الحساب في عناوين البيانات. إنه يعرف أن intarray عبارة عن مصفوفة من النوع int لأنه تم إعلانها بهذه الطريقة. لذلك عندما يرى التعبير intarray + 3 ، فإنه يفسره كعنوان للعدد الصحيح الرابع في intarray ، وليس البايت الرابع. لكننا نريد قيمة عنصر المصفوفة الرابع هذا ، وليس العنوان. لأخذ القيمة ، نستخدم العامل dereference (*). التعبير الناتج ، عندما تكون j هى 3 ، هو *(intarray+3) ، وهو محتوى عنصر المصفوفة الرابع ، أو 52. الآن رأينا لماذا يجب أن يتضمن إعلان المؤشر نوع المتغير المشار إليه. يحتاج المترجم إلى معرفة ما إذا كان المؤشر هو مؤشر إلى int أو مؤشر إلى double بحيث يمكن إجراء الحساب الصحيح للوصول إلى عناصر المصفوفة فهو يضاعف قيمة الفهرس بمقدار 2 في حالة النوع int ، ولكن يضاعفه في 8 في حالة double. ثوابت المؤشر ومتغيرات المؤشر Pointer Constants and Pointer Variables افترض أنه ، بدلاً من إضافة j إلى intarray للدخول إلى عناوين المصفوفة ، أردت استخدام عامل الزيادة. هل يمكن أن تكتب *(intarray++) ؟ الجواب هو لا ، والسبب هو أنه لا يمكنك زيادة ثابت (أو تغييره بالفعل بأي طريقة). التعبير intarray هو العنوان الذي اختاره النظام لوضع المصفوفة الخاص بك ، وستظل على هذا العنوان حتى ينتهي البرنامج . intarray هو مؤشر ثابت. لا يمكنك قول intarray++ . (في نظام تعدد المهام ، قد تتغير العناوين المتغيرة أثناء تنفيذ البرنامج. قد يتم تبديل البرنامج النشط إلى القرص ثم إعادة تحميله في موقع ذاكرة مختلف. ومع ذلك ، فإن هذه العملية غير مرئية للبرنامج.) ولكن بينما لا يمكنك زيادة عنوان ، يمكنك زيادة مؤشر يحمل عنوانًا. المثال التالي ، PTRINC ، يوضح كيف: كود:
// ptrinc.cpp
// array accessed with pointer
#include <iostream>
using namespace std;
int main()
{
int intarray[] = { 31, 54, 77, 52, 93 }; //array
int* ptrint; //pointer to int
ptrint = intarray; //points to intarray
for(int j=0; j<5; j++) //for each element,
cout << *(ptrint++) << endl; //print value
return 0;
}
هنا نحدد مؤشرًا إلى int هو ptrint ونمنحه القيمة intarray ، عنوان المصفوفة . الآن يمكننا الوصول إلى محتويات عناصر المصفوفة بالتعبير كود:
*(ptrint++) يبدأ المتغير ptrint بنفس قيمة العنوان مثل intarray ، مما يتيح الوصول إلى عنصر المصفوفة الأول ، intarray[0] ، الذي يحتوي على القيمة 31 ، كما كان من قبل. ولكن نظرًا لأن ptrint متغير وليس ثابتًا ، فيمكن زيادته. بعد زيادته ، يشير إلى عنصر المصفوفة الثاني ، intarray[1] . يمثل التعبير *(ptrint++) محتويات عنصر المصفوفة الثانى أو 54. تؤدي الحلقة إلى وصول التعبير إلى كل عنصر من عناصر المصفوفة كل بدوره. خرج PTRINC هو نفسه خرج PTRNOTE. |
|
||||||
|
المؤشرات والدوال Pointers and Functions في الدوال ، هناك ثلاث طرق لتمرير الوسائط إلى دالة : بواسطة القيمة ، وبواسطة المرجع ، وبواسطة المؤشر. إذا كانت الدالة تهدف إلى تعديل المتغيرات في برنامج الاستدعاء ، لا يمكن تمرير هذه المتغيرات بالقيمة ، لأن الدالة لا تحصل إلا على نسخة من المتغير. ومع ذلك ، يمكن استخدام وسيط مرجعى أو مؤشر في هذا الموقف. تمرير متغيرات بسيطة Passing Simple Variables سنراجع أولاً الطريقة التي يتم بها تمرير الوسائط حسب المرجع ، ثم نقوم بمقارنتها بتمرير وسائط المؤشر . يظهر برنامج PASSREF التمرير بالمرجع . كود:
// passref.cpp
// arguments passed by reference
#include <iostream>
using namespace std;
int main()
{
void centimize(double&); //prototype
double var = 10.0; //var has value of 10 inches
cout << “var = “ << var << “ inches” << endl;
centimize(var); //change var to centimeters
cout << “var = “ << var << “ centimeters” << endl;
return 0;
}
//--------------------------------------------------------------
void centimize(double& v)
{
v *= 2.54; //v is the same as var
}
هنا نريد تحويل متغير var في main() من بوصة إلى سم. نقوم بتمرير المتغير بواسطة المرجع إلى الدالة centimize() . (تذكر أن العامل & الذى يتبع نوع البيانات double في النموذج الأولي لهذه الدالة يشير إلى أن الوسيط يتم تمريره بالمرجع .) الدالة centimize() تضرب المتغير الأصلي فى 2.54. لاحظ كيف تشير الدالة إلى المتغير. فهى تستخدم ببساطة اسم الوسيط v ؛ v و var هي أسماء مختلفة لنفس الشيء. بمجرد أن يتم تحويله var إلى سنتيمترات ، يعرض main() النتيجة. إليك إخراج PASSREF: كود:
var = 10 inches var = 25.4 centimeters يوضح المثال التالي PASSPTR موقفًا مكافئًا عند استخدام المؤشرات: كود:
// passptr.cpp
// arguments passed by pointer
#include <iostream>
using namespace std;
int main()
{
void centimize(double*); //prototype
double var = 10.0; //var has value of 10 inches
cout << “var = “ << var << “ inches” << endl;
centimize(&var); //change var to centimeters
cout << “var = “ << var << “ centimeters” << endl;
return 0;
}
//--------------------------------------------------------------
void centimize(double* ptrd)
{
*ptrd *= 2.54; //*ptrd is the same as var
}
خرج PASSPTR هو نفسه خرج PASSREF. يتم إعلان الدالة centimize() على أنها تأخذ وسيط يمثل مؤشرًا إلى double : كود:
void centimize(double*) // argument is pointer to double عندما تقوم main() باستدعاء الدالة ، فإنها تزود عنوان المتغير كوسيط : كود:
centimize(&var); تذكر أن هذا ليس هو المتغير نفسه ، حيث إنه يمرر بالمرجع ، ولكن عنوان المتغير. نظرًا لأن الدالة centimize() تمرر عنوان ، فيجب أن تستخدم عامل dereference ، * ptrd ، للوصول إلى القيمة المخزنة في هذا العنوان: كود:
*ptrd *= 2.54; // multiply the contents of ptrd by 2.54 بالطبع هذا هو نفسه كود:
*ptrd = *ptrd * 2.54; // multiply the contents of ptrd by 2.54 حيث تعني علامة النجمة المستقلة عملية الضرب. نظرًا لأن ptrd يحتوي على عنوان var ، فإن أي شيء يتم إجراؤه على *ptrd يتم فعلًا على var. يوضح الشكل كيف أن تغيير *ptrd في الدالة يغير var في برنامج الاستدعاء . ![]() الشكل يبين تمرير مؤشر إلى دالة Pointer passed to function إن تمرير المؤشر كوسيط للدالة يشبه إلى حد ما تمرير المرجع. كلاهما يسمح بتعديل المتغير في برنامج الاستدعاء بواسطة الدالة. ومع ذلك ، فإن الآلية مختلفة. المرجع هو اسم مستعار للمتغير الأصلي ، بينما المؤشر هو عنوان المتغير. |
|
جميع الحقوق محفوظة 2026
|


