الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

أهل الخبرة

مغلق
بدأه maro009 في 20 أبريل 2005 · 6 رد · 597 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بسم الله الرحمن الرحيم

يا اخوانى اريد المساعدة فى ايجاد خطأ ما.

الموضوع عمل class سيارة

المستخدم يجب عليه وضع الأسم و سعه المحرك,, وأيضا أجزاء جديده وتحديد السعر,,,

لقد قمت بعون الله بعمل هذا,,, المشاكل التى قابلتنى

1- مشكله فى مسح الأسم من ال destructor

2- يمكن للمستخدم ان يضع او يحذف اجزاء اخرى, المشكله هى الdestructor يقوم بالعمل تلقائيا فيقوم بمسح كل الأجزاء

القديمه

ارجو من الأدارة بعدم غلق الموضوع فأنا لا اطلب حل التمرين ولكن المساعدة , وها هو الكود الذى كتبته

أرجو من الأخوة اذا رايتم اى خطأ حتى لو صغير بالأفاده

ولكم جزيل الشكر مقدما

// 1-HEADER FILE

#ifndef __dclass_h
#define __dclass_h

const int size =50;
void  clearBuf();
void menu();

class Car
{
	private:
  int   _nr_parts;
  int    _hp;
  float *_parts;
  char  *_brandname;
  

	public:
   Car  (void);
   Car  (int hp, float *parts, int nr_parts, const char *name);
  ~Car  (void);

  void  set_hp (int hp);
  int   get_hp (void)const;

  void  set_brandname (const char *name);
  char  get_brandname ()const;

  void  set_Car (int hp,float *parts,int nr_parts, const char *brandname);

  void  print_car (void)const;

  void  add_part (int part_nr);
  void  remove_part (int part_nr);

  void  add_parts    (float *part_nrs, int nr_parts);
  void  remove_parts (float *part_nrs, int nr_parts);

};

#endif

//2-cpp

#include "D_class.h"
#include <iostream>
#include <cstring>

using namespace std;

void  clearBuf()  // this function to clear the buffer
{
	char k;
	do
	{
  cin.get(k);
	}while(k!='\n');

}

Car::Car  () //defualt constructor
{
  _nr_parts  = 0;
  _hp        = 0;
  _parts     = NULL;
  _brandname = NULL;

}

Car::Car  (int hp, float *parts, int nr_parts, const char *name) 
{
	_hp         = 0;
	_parts     = NULL;
	_brandname = NULL;
	_nr_parts  = 0;
	set_Car(hp,	parts, nr_parts, name);
	print_car();
}

Car::~Car  (void) //destructor
{
  cout<<"Destructor****"<<endl;
  if(_parts)
  {
 	 delete[]_parts;
 	 _parts=NULL;
 	 cout << "Dynamic parts deleted.."<<endl;
  }
  
  if(_brandname)
  {
 	 delete[]_brandname;
 	 _brandname=NULL;
 	 cout << "Dynamic name deleted.."<<endl;	
  }
  else
  {
 	 cout<<"something wrong"<<endl;
  }

}

//Set functions

void Car::set_hp (int hp)
{
	_hp = hp;
}

void Car::set_brandname (const char *name)
{
	int length = strlen(name); 
	_brandname = new char [length];
	strcpy(_brandname,name);
}

void Car::add_part (int part_nr)
{
	_nr_parts = _nr_parts + part_nr;
}

void Car::remove_part (int part_nr)
{
	if(_nr_parts>part_nr)
	{
  _nr_parts = _nr_parts - part_nr;
	}
	else
	{
  cout<< "you will remove all parts"<<endl;
  _nr_parts=0;
	}
  
}


void Car::add_parts    (float *part_nrs, int nr_parts)
{
	if (part_nrs)
	{
 	 cout << "What is the cost of the new parts ? "<<endl;
   	 for(int m=0;m<nr_parts; m++) // add values into the array
   	 {
      cout << "Part nr ("<<m+1<<") costs : ";
      cin  >> *(part_nrs+m);
   	 }	
  //Step 1 call add part function to set the length of the all array
  add_part (nr_parts);

  //Step 2 creat temp array to store the 2 arrays
  float *temp = new float [_nr_parts];
  if (temp)
  {
 	 if (_parts)
 	 {
   	 cout<<"\nThis nooooooooooooooooooooo work";
   	 for (int k=0; k< (_nr_parts); k++)
    {
   	 *(temp + k) = *(_parts + k);
    }

    for (int j = (_nr_parts - nr_parts); j<(_nr_parts); j++)
    {
   	 *(temp + j) = *(part_nrs+j);
    }
 	 }
  
 	 else if (_parts == NULL)
 	 {
   	 cout<<"\ntest that _part point to NULL"<<endl;
    for (int m=0; m< _nr_parts; m++)
    {
   	 *(temp + m) = *(part_nrs+m);
    }
 	 }
 	 delete []_parts;
 	 delete []part_nrs;
 	 _parts=temp;
  }
  else
 	 cout<<"no temp created"<<endl;
	}
	else 
  cout<<"no Dynamic array created... "<<endl;

}


void Car::remove_parts (float *part_nrs, int nr_parts)
{
	cout<<"Remove Function"<<endl;
	if (part_nrs)
	{
 	 cout<<"\ntest if i pass D array"<<endl;
  // the following part is to store what will be removed
  if (_nr_parts>0)
  {
    for (int k=(_nr_parts-nr_parts-1); k<nr_parts; k++)
    {
      *(part_nrs+k)=*(_parts+k);
      cout<<"Part nr("<<k+1<<") with price of <"<<*(part_nrs+k)<<">will be remove"<<endl;
    }
  }
  else
  {
 	 cout<<"there is no items to be remove.....!!!!!"<<endl;
 	 delete[]_parts;
  }

  // now start remove the parts
  remove_part (nr_parts);
  if (_nr_parts>0) // to test if the user doesn't wants to remove all parts
  {
 	 float *temp = new float [_nr_parts];
 	 for (int i=0; i<_nr_parts; i++)
 	 {
    *(temp+i)=*(_parts+i); 
 	 }
 	 delete []_parts;
 	 _parts=temp;
  }
  else
  {
 	 cout<<"all parts have been removed"<<endl;
 	 delete []_parts;
 	 _parts=NULL;
  }
	}
	else
  cout<<"no Darray have pased"<<endl;
}

void Car::set_Car (int hp, float *parts,int nr_parts, const char *brandname)
{
	set_hp(hp);
	cout<<"confirm your choice"<<endl;
	int choose=0;
	menu();
	cin>>choose;
	switch (choose)
	{
	case 1 : add_parts (parts, nr_parts);
    break; 
	case 2 : remove_parts(parts, nr_parts);
    break;
	default: cout << " invalid Number..."<<endl;
  
	}
	set_brandname(brandname);
}



void menu()
{
	cout << "choose .."<<endl;
	cout << "1 - Add part "<<endl;
	cout << "2 - remove parts "<<endl;

}


// get function
char Car::get_brandname ()const
{
	for (int i=0; i<strlen(_brandname); i++)
	{
  cout<<*(_brandname+i);
	}
	return 0;
}

int   Car::get_hp (void)const
{
	return _hp; 
}

//print function 
void Car::print_car()const
{
	cout <<"the name is :";
	cout<<get_brandname ();
	cout<<"\nwith ";
	cout<<get_hp ();
	cout<<" Hp."<<endl;
	cout<<"Parts Details :"<<endl;
	for (int n =0; n<(_nr_parts); n++)
	{
  cout << " part Nr <"<<n+1<<"> cost :";
  cout << *(_parts+n)<<" Euro"<<endl;
	}

}

//3-Main

#include <iostream>
#include <stdlib.h>
#include "D_class.h"

using namespace std;

int main()
{
	char *names = NULL;
	int Hp=0;
	float *Part=NULL;
	int Nr_parts=0;
	int choose=0;
	char c='n';

	cout << "Enter a Car Details "<<endl;
	cout << "1- Enter the name : ";
	names=new char [size];
	cin.get (names , size);
	clearBuf();
	cout << "2- Enter the Hp: ";
	cin >> Hp;

	do
	{
  if (Part)
  {
 	 delete[]Part;
 	 Part=NULL;
  }

  menu();
  cin >> choose;
  switch (choose)
  {
  case 1 : cout <<"How Many Parts? ";
     cin>>Nr_parts;
     Part = new float [Nr_parts];
     break; 
  case 2 : cout <<"How Many Parts? ";
     cin>>Nr_parts;
     Part = new float [Nr_parts];
     break;
  default: cout << " invalid Number..."<<endl;
  }

  Car maro (Hp, Part, Nr_parts,names);
  cout<<"do you want to add or remove other parts..(Y/N)?";
  cin>>c;
  cout<<endl;
  
	}while (c!='n');



	return 0;
}

شكرا والسلام عليكم

#2

همممم مشكلة غريبة

الخطأ يحدث عند:

delete[]_brandname;

لا يوجد شيء غير طبيعي سوى أن _brandname هو مؤشر لـ char ...

قمت ببعض التجارب .. و لاحظت التالي:

إذا جربت هذا الكود (في أي مكان)

	char y[] = "helloo!";

	char * x = new char[10];
	strcpy(x, y);
	delete[] x;

فلن يحدث خطأ ..

و لكن, لو جربت:

	char y[] = "helloo!";

	char * x = new char[strlen(y)];
	strcpy(x, y);
	delete[] x;

فستحدث نفس المشكلة!!

اعتقد المشكلة هي أن strlen يطلع في الحقيقة عدد الحروف, و ليس الحجم الحقيقي للـ string, لان النص (او الـ string) ينتهي بـ '\0' و لكن strlen لا يحسب هذا الصفر!

عندما تنسخ النص, فإنك تنسخ النص بكامله (بما في ذلك الصفر '\0') و هنا المشكلة, حيث ان هناك حرف زائد اكبر من حجم النص.

أعتقد هذا هو سبب المشكلة .. لماذا يتسبب هذا الأمر في المشكلة؟ لا أدري,

و لكن لو جربت هذا الكود:

	char y[] = "helloo!";
	char * x = new char[strlen(y) + 1];
	strcpy(x, y);
	delete[] x;

فلن تحدث المشكلة!!!

إذا, مجرد تغيير بسيط:

void Car::set_brandname (const char *name)
{
int length = strlen(name) + 1; 
_brandname = new char [length];
strcpy(_brandname,name);
}

يحل المشكلة.

جرب و خبرني شيصير معاك.

#3

اخى hasan_aljudy

أولا اشكرك على اهتمامك

لقد اصبت يا اخى المشكلة تم حلها,,,,

والله ماشاء الله عليك,, لقد سألت العديد من الآصدقاء الذى لديهم خبره عنى ولكن لم يعرفوا

اللهم لا حسد

ولكن هناك مشكله اخرى مع delete ايضا , فى ال main عندما يسأل المستخدم اذا كان يريد ان يضع جزاء اخرى عن طريق

do while loop يحدث نفس المشكلة ولكن هذه المرة مع float

المشكله هنا

//3-Main

#include <iostream>
#include <stdlib.h>
#include "D_class.h"

using namespace std;

int main()
{
char *names = NULL;
int Hp=0;
float *Part=NULL;
int Nr_parts=0;
int choose=0;
char c='n';

cout << "Enter a Car Details "<<endl;
cout << "1- Enter the name : ";
names=new char [size];
cin.get (names , size);
clearBuf();
cout << "2- Enter the Hp: ";
cin >> Hp;

do
{

 if (Part)
 {
  delete[]Part;//********************** Here is the problem, هنا المشكله
  Part=NULL;
 }

 menu();
 cin >> choose;
 switch (choose)
 {
 case 1 : cout <<"How Many Parts? ";
    cin>>Nr_parts;
    Part = new float [Nr_parts];
    break; 
 case 2 : cout <<"How Many Parts? ";
    cin>>Nr_parts;
    Part = new float [Nr_parts];
    break;
 default: cout << " invalid Number..."<<endl;
 }

 Car maro (Hp, Part, Nr_parts,names);
 cout<<"do you want to add or remove other parts..(Y/N)?";
 cin>>c;
 cout<<endl;

}while (c!='n');



return 0;
}
#4

في الـ NAME لما لا تستخدم الـ class string !!!

فهو أفضل بلا شك .. لأن الـ name سيكون بداخل الـ object لا خارجه كما تفعل انت ..

فإختيارك لـ char * name يعني ان ما بداخل الـ object إنما هو مؤشر لشي خارجة ..

وهنا ضعف في إستخدام مبديء OOP :)

تحياتي

Wase3 Sadr

#5

بصراحة انا اكتشفتها بالصدفة .. كنت احاول اعادة انتاج المشكلة بصورة مبسطة (برنامج صغير) فقمت في البداية بكتابة كلاس صغير الكونستركتر يسوي new و الدستركتر يسوي delete بعدين جربت اعملهابدون كلاس .. و هذه المرة قلت ما في داعي انسخ من string آخر (تعاجزت اكتب سطرين زيادة!) .. خليت رقم 10 في الـ [new char[10 و نسخت نص جاهز ("strcpy(x, "hello.. فلما جربت ذلك لم تحدث المشكلة!! قلت لنفسي اجرب انسخة بطريقة strlen .. جربت فحدثت المشكلة .. فعرفت ان المشكلة في الـ strlen!

اما المشكلة الجديدة هذه, فلو تتبع الكود ستجد انك حذفت الـ Part في مكان آخر ..

تتبع حركة سيرها:

 Car maro(Hp, Part, Nr_parts,names);

هنا اصبحت ثاني بارامتر في الكونستركتر:

Car::Car  (int hp, float *parts, int nr_parts, const char *name) 
{
_hp         = 0;
_parts     = NULL;
_brandname = NULL;
_nr_parts  = 0;
set_Car(hp, parts, nr_parts, name);
print_car();
}

هنا ثاني بارامتر اسمه parts لكنه مؤشر يشير لنفس المكان ..

و قد تم ارساله الى set_Car و هو أيضا ثاني بارامتر

void Car::set_Car (int hp, float *parts,int nr_parts, const char *brandname)
{
set_hp(hp);
cout<<"confirm your choice"<<endl;
int choose=0;
menu();
cin>>choose;
switch (choose)
{
case 1 : add_parts (parts, nr_parts);
   break; 
case 2 : remove_parts(parts, nr_parts);
   break;
default: cout << " invalid Number..."<<endl;

}
set_brandname(brandname);
}

هنا ايضا اسمه parts و هو مؤشر يشير لنفس المكان .. يتمإرساله إما الى add_parts او remove_parts حسب ما يدخله المستخدم.

في add_parts:

void Car::add_parts    (float *part_nrs, int nr_parts)

اسمه اصبح part_nrs

لاحظ انك في نهاية الفنكشن تقوم بعملية delete عليه

delete []part_nrs;

لاحظ ان هذا الـ part_nrs هو مؤشر يشير الى نفس المكان اللذي تشير اليه Parts في الفنكشن main ..

فهنا قد قمت بحذف المساحة المحجوزة .. و لكن Parts في main مازال يشير الى نفس العنوان!!! لذلك فإنه يتجاوز اختبار (if(Parts لأنه فعلا ليس صفر ..

و لكن عندما تأتي لحذفها .. سيحدث خطأ لأنها حذفت من قبل .. و لا يوجد شيء جديد ليتم حذفه!

الحل ان تحذف هذا السطر

delete []part_nrs;

من add_parts لأن المؤشر part_nrs هو مؤشر جائنا من العالم الخارجي (بالنسبة للفنكشن يعني) لذلك لا يجوز للفنكشن هذا ان ياخذ زمام الأمور و يحذفه بنفسه .. بل يدع هذه المهمة للشخص اللذي أرسل اليه هذا المؤشر, تفاديا لمشاكل مثل هذه. (الشخص هنا هو main)

بس ملاحظة صغيرة, لاحظت انك تلعب كثيرا مع المؤشرات

cin  >> *(part_nrs+m);

صحيح انها بهذه الطريقة تصبح اسرع, لكن هناك مخاطرة ايضا, كثرة اللعب مع المؤشرات بهذه الطريقة تزيد من نسبة احتمال حدوث الأخطاء .. و أنا برأيي أن الأفضل هو استعمال الطريقة ائمن و هي

part_nrs[m]

و صدقني فرق السرعة طفيف جدا .. ربما بضعة nanoseconds يعني اجزاء من المليار من الثانية .. يعني ما يستاهل.

و هذا مجرد رأي طبعا.

...

تعقيب:

اقتباس
في الـ NAME لما لا تستخدم الـ class string !!!

فهو أفضل بلا شك .. لأن الـ name سيكون بداخل الـ object لا خارجه كما تفعل انت ..

فإختيارك لـ char * name يعني ان ما بداخل الـ object إنما هو مؤشر لشي خارجة ..

وهنا ضعف في إستخدام مبديء OOP

تحياتي

Wase3 Sadr

الـ string أفضل لأنه يعتني بالمؤشرات نيابة عنك ..

و لكن .. هذه الفقرة غير صحيحة:

اقتباس
فإختيارك لـ char * name يعني ان ما بداخل الـ object إنما هو مؤشر لشي خارجة ..

وهنا ضعف في إستخدام مبديء OOP

بالعكس, هذه قوة في الـ OOP و لو تلاحظ في لغة مثل Java فإن التعامل مع الكائنات يتم عن طريق المؤشرات فقط, و لا تسمح لك اللغة بالتعامل مع الكائنات by value لأن هذا يعتبر أمر سيئ. و البرامج المكتوبة بالسي تجدها دائما تستخدم المؤشرات .. خصوصا في التعامل مع الكائنات, حتى إذا كان عندك كائن يحتوي على كائن آخر, فإن المبرمج سيستعمل مؤشر الى الكائن الآخر .. و لا يضع الكائن الآخر نفسه داخل كائنه.

عموما, الـ string في النهاية يحتوي في داخله على مؤشر لـ char* خارجي!

تم تعديل هذه المشاركة بواسطة hasan_aljudy في 20 أبريل 2005 في 18:07

#6

ماذا تقصد ب class string

ما هذا؟ :blink: :blink: :blink:

#7
#include <string>
#include <iostream>
using namespace std;

int main()
{
    string text = "hello";
    string text2;
    text2 = text + " world!!";

    cout << text2 << endl;
}

هذا الموضوع مغلق.

مواضيع مشابهة