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

[ تمت الإجابة ]خطأ في Chaînes de caractères

بدأه The Hidden Ghost في 16 أكتوبر 2012 · 12 رد · 1,030 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

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

السلام عليكم ورحمة الله تعالى وبركاته ، أريد أن أعرف أين يتواجد الخطأ في هذا السورس كود ، علما أني أظن أن الكود صحيح نسبيا ، عندما أنفذ البرنامج يقع crash ، لماذا ؟؟؟


#include <stdio.h>
#include <conio.h>
int main(){

char *Nom[4];
int i;
scanf("%s %s %s %s",&Nom[0],&Nom[1],&Nom[2],&Nom[3]);
for(i = 0; i < 4 ; i++){
printf("\nVotre nom est : %s\n",Nom);
}
getch();
return 0;
}

ويقع نفس الخطأ في الكود التالي :


#include <stdio.h>
#include <stdlib.h>

int max;

int main(){
struct stagiaire
{
int mat;
int age;
char nom[10];
char prenom[10];
char addresse[10];
}stg[max];

printf("\n\n\t Entrer le nombre des stagiaires : ");
scanf("%d",&max);
int n = 0, j = 0;
do{
system("cls");
printf("\n\n\t\t Stagiaire N %d ",n+1);
printf("\n\n\t Matricule : ");
scanf("%d",&stg[n].mat);
printf("\n\t Nom : ");
scanf("%s",&stg[n].nom);
printf("\n\t Prenom : ");
scanf("%s",&stg[n].prenom);
printf("\n\t Age : ");
scanf("%d",&stg[n].age);
printf("\n\t Addresse : ");
scanf("%s",&stg[n].addresse);
n++;
}while(n!=max);
printf("\n\n\t\t\t*********** Affichage ****************\n\n");
printf("Mat\tNom\t\tPrenom\t\tAge\t\tAddresse\n\n");
do{
printf("%d\t%s\t\t%s\t\t%d\t\t%s\n",
stg[j].mat,stg[j].nom,stg[j].prenom,
stg[j].age,stg[j].addresse);
j++;
}while(j!=max);

system("pause");

return 0;
}

هل هناك طريقة للتعامل مع المصفوفات الحرفية التي تحوي العديد من العناصر بدون حدوث هذا الخطأ ؟؟؟؟

تم تعديل هذه المشاركة بواسطة Hamza+C+ASM في 16 أكتوبر 2012 في 16:04

rS3eY.png
#2

الخطأ لديك في تعريف Nom, عرفته على أنه مصفوفة من أربع مؤشرات, لأماكن غير معروفة, ومن ثم قمت بالكتابة على تلك العنوانين:

scanf("%s %s %s %s",&Nom[0],&Nom[1],&Nom[2],&Nom[3]);

وهذا خطأ. يُمكنك تصحيحة ليصبح :

#include <stdio.h>
#include <string.h>


int main(int argc, char **argv)

{
    char array[4][5];
    memset(&array[0], 0, sizeof(array));

/*
array[0] = {'\0', '\0', '\0', '\0', '\0'};
array[1] = {'\0', '\0', '\0', '\0', '\0'};
array[2] = {'\0', '\0', '\0', '\0', '\0'};
array[3] = {'\0', '\0', '\0', '\0', '\0'};
*/

    /* حتى لا يحدث طفح بالذاكرة, يلزم وضع %4 حتى لاتضع الدالة نص طوله أكثر من أربع حروف في كل متغير. */
    scanf("%4s %4s %4s %4s", &array[0][0], &array[1][0], &array[2][0], &array[3][0]);

    /*

لو أدخلت الآن :

AAAA BBBB CCCC DDDD

فستحمل المصفوفة :

array[0] = {'A', 'A', 'A', 'A', '\0'};
array[1] = {'B', 'B', 'B', 'B', '\0'};
array[2] = {'C', 'C', 'C', 'C', '\0'};
array[3] = {'D', 'D', 'D', 'D', '\0'};

    */

    printf("%s | %s | %s | %s\n", array[0], array[1], array[2], array[3]);

    return 0;

}
#3

ماذا تعني بهذا السطر :


memset(&array[0], 0, sizeof(array));
لماذا قمت بكتابة المصفوفة أحادية و هي في الحقيقة ثنائية البعد ، ولماذا اخترت العنصر الأول //
و الذي 0 من بين باقي العناصر //

كيف يمكنني العمل بالمصفوفة التي قدمتها لي ، بدون أن تقتصر على 4 حروف ، أي تصبح المصفوفة غير محدودة ، هل هذا ممكن ؟

rS3eY.png
#4

memset لملئ المصفوفة بأصفار, فقط أعطها بداية العنوان والقيمة والحجم وستملأها لك بتلك القيمة.

لا لايُمكنك, عمل مصفوفة مفتوحة الحجم في C الا بطرق معقدة ,على الأقل ليس مع scanf.

#6

ألا يمكننا استعمال مصفوفة أحادية البعد فقط أخي الكريم ؟ + هل هناك تجميعة للدوال المختصة بالذاكرة في لغة السي ؟

rS3eY.png
#7

أهلا حمزة ..

الخطأ في الحالة الأولى أنك استعملت مكانا في الذاكرة لم تحجزه بعد وهذا ماقد يتسبب في segfault

هذه محاولتي


#include <stdlib.h>
#define MAX 20

int main(){
int i;
char (*Nom)[MAX]=NULL;
Nom= malloc(4* sizeof(*Nom));
if(!Nom){
puts("error memory!!");
exit(EXIT_FAILURE);
}
scanf("%s%s%s%s",Nom[0],Nom[1],Nom[2],Nom[3]);
for(i = 0; i < 4 ; i++)
puts((char*)Nom);
free(Nom);
getchar();
return 0;
}
#include <stdio.h>

في الحالة الثانية تعيد نفس الخطأ الذي ارتكبته في الحالة الأولى

    	printf("\n\t Addresse : ");
    	scanf("%s",&stg[n].addresse);

كان عليك أن تكتب فقط

    	printf("\n\t Addresse : ");
    	scanf("%s",stg[n].addresse);

stg[n].addresse هو عنوان أول حرف يشير إليه المؤشر الثابت في الذاكرة فما حاجتك ل '&'؟

و يمكن التأكد من خلال هذا المثال

#include <stdio.h>

int main()
{

char a[20];
printf("entrer:\t");
fgets(&a[0],20,stdin);
puts(a);

return 0;
}

التصحيح للكود الثاني

#include <stdio.h>
#include <stdlib.h>

    	typedef struct stagiaire
    	{
    	int mat;
    	int age;
    	char nom[10];
    	char prenom[10];
    	char addresse[10];
    	}stg;

int main(){

    	const char *const mot[5]={"Mat","Age","Preom","Nom","Adresse"};
    	stg *tab=NULL;
    	int max=0,n = 0;
    	printf("\n\n\t Entrer le nombre des stagiaires : ");
    	scanf("%d",&max);
    	tab=(stg*)malloc(max*sizeof(stg));
    	if(!tab)
    	{
        	puts("error memory");
        	exit(EXIT_FAILURE);
    	}

do{
    	printf("\n\n\tStagiaire N %d ",n+1);
    	printf("\n\n\t\tMatricule:");
    	scanf("%d",&tab[n].mat);
    	printf("\n\t\tAge\t:");
    	scanf("%d",&tab[n].age);
    	printf("\n\t\tPrenom\t:");
    	scanf("%s",tab[n].prenom);
    	printf("\n\t\tNom\t:");
    	scanf("%s",tab[n].nom);
    	printf("\n\t\tAddresse:");
    	scanf("%s",tab[n].addresse);
    	n++;
}while(n!=max);

n=0;

puts("\n\n********************* Affichage *********************\n\n");
printf("%s\t\t%s\t\t%s\t\t%s\t\t%s\n\n",mot[0],mot[1],mot[2],mot[3],mot[4]);

while(n<max)
{
    	printf("%d\t\t%d\t\t%s\t\t%s\t\t%s\n",
    	tab[n].mat,tab[n].age,tab[n].prenom,tab[n].nom,tab[n].addresse);
    	n++;
}

free(tab);
getchar();

return 0;
}

بالتوفيق

تم تعديل هذه المشاركة بواسطة مومو (momo) في 16 أكتوبر 2012 في 21:39

1

i love you mama

#8

شكرا أخي مومو الغالي smile.gif + كما قلت سابقا هل هناك تجميعة للدوال المختصة بالذاكرة ؟

أقصد مجموعة من الدروس المختصة في هذا المجال ، حبذا لو تكون تجميعة مثل ملفات hlp.*

أو chm.*

لم يعمل الكود أخي مومو ،،،

dnB9Q.png

بالنسبة للكود الثاني فهو يعمل بشكل جيد smile.gif

rS3eY.png
#9
اقتباس
شكرا أخي مومو الغالي smile.gif

على واجب أخي حمزةhuh.gif

اقتباس
+ كما قلت سابقا هل هناك تجميعة للدوال المختصة بالذاكرة ؟

هذه بعض الروابط قد تساعدك

allocation-dynamique

Allocation dynamique en C - complément

Tableaux, pointeurs et allocation dynamique

اقتباس

لم يعمل الكود أخي مومو ،،،

dnB9Q.png

غريب فعلا !! هذا الكود يشتغل عندي بشكل ممتاز

لكن على مايبدو فأنت تستعمل النسخة القديمة

عدل هذا السطر من الكود الأول

Nom= malloc(4* sizeof(*Nom));

بهذا

Nom= (char (*)[MAX])malloc(4* sizeof(*Nom));

الكود النهائي

#include <stdio.h>
#include <stdlib.h>
#define  MAX 20

int main(){
int i;
char (*Nom)[MAX]=NULL;
Nom= (char (*)[MAX])malloc(4* sizeof(*Nom));
if(!Nom){
    	puts("error memory!!");
    	exit(EXIT_FAILURE);
}
scanf("%s%s%s%s",Nom[0],Nom[1],Nom[2],Nom[3]);
for(i = 0; i < 4 ; i++)
puts((char*)Nom);
free(Nom);
getchar();
return 0;
}

إذا في خطأ ثاني لا تتردد في الإبلاغ عنه يا حمزة؟wink.gif

1

i love you mama

#10

الكود يشتغل أخي مومو ، لكن هل من توضيح لهذا الكود :


char (*Nom)[MAX]=NULL;
Nom= (char (*)[MAX])malloc(4* sizeof(*Nom));

أين تعلمت هذا ؟ + ما كل هذا التعقيد ولماذا لم نكتف بهذا فقط ؟ :


char (*Nom)[MAX]=NULL;
Nom= malloc(4* sizeof(*Nom));

rS3eY.png
#11
char (*Nom)[MAX]=NULL;

هنا نعلن عن مؤشر لمصفوفة ل 20 عنصر من نوع char ونسند إليه القيمة NULL حتى نتجنب segfault

Nom= (char (*)[MAX])malloc(4* sizeof(*Nom));

في هذا السطر نقوم بالحجز الديناميكي للمؤشر Nom

نحجز ل 4 عناصر من نوع مصفوفة ل 20 عنصر من نوع char

هنا نستعمل التحويل القصري

 (char (*)[MAX])

لأن الدالة malloc تعيد *void بينما المؤشر nom هو مؤشر مصفوفة تضم 20 عنصر من نوع char

لم تسألني لماذا اكتفيت فقط بتحرير البعد الأول ؟

البعد الثاني سيتم تحريره تلقائيا لذا لسنا في حاجة للدالة free

اقتباس
ما كل هذا التعقيد ولماذا لم نكتف بهذا فقط ؟

لا ليس هنالك أي تعقيد إذا راجعت قليلا الروابط الذي وضعتها لك أعلاه فستتمكن بسهولة من فهم عملية الحجز بشكلها الصحيح

بالتوفيقhappy.gif

1

i love you mama

#12

هل هناك إضافات أخي مومو smile.gif ؟؟؟

rS3eY.png
#13
اقتباس
هل هناك تجميعة للدوال المختصة بالذاكرة ؟

هناك أربع دوال قياسية تُستخدم بكثرة عند التعامل مع الذاكرة في لغة سي و هي :

calloc, malloc, realloc, free

من سلسلة الأسئلة الأكثر شيوعاً (فصل المؤشرات, المصفوفات الحرفية و التراكيب) لأستاذنا أحمد الشنقيطي :

اقتباس
ما هي فائدة الدالة malloc ؟

الدالة malloc تستقبل عدد البايتات (نوعية حجم البيانات) و تعيد مؤشر void يشير إلى مكان الحجز مع العلم أنها لا تقوم بتصفير الذاكرة لذلك سنحتاج إلى الدالة memset (إن أردنا التصفير) التي تستقبل ثلاث معاملات, المعامل الأول هو المؤشر نفسه و الثاني هو القيمة المراد وضعها بداخل الخانة التي يشير إليها المؤشر و الثالث هو عدد البايتات أو كمية البيانات المُؤشر عليها انظر المثال:

char* ptr = malloc(sizeof (char));
if (ptr != NULL) {
    memset(ptr, 0x00, sizeof (char));
    …
    free(ptr);
}

ما هي فائدة الدالة calloc ؟

الدالة calloc تستقبل معاملين, الأول هو عدد العناصر المراد حجزها، و المعامل الثاني هو حجم العنصر الواحد بالبايت, هذه الدالة تُعيد مؤشر void يشير إلى مكان أول خانة من هذه الخانات مع العلم أنها متتالية في الترتيب لذلك يمكننا الوصول إلى بقية الخانات عن طريقة تحريك المؤشر. مثلا اذا اردنا حجز 5 عناصر من نوع int اذا نقوم بالتالي :

malloc(5 * sizeof(int));

أو

calloc(5, sizeof(int));

مع اختلاف بسيط وهو أن الدالة calloc تقوم بتصفير البيانات التي تحجزها، وفي العادة calloc تقوم باستدعاء malloc داخلها .

ما الفائدة من استخدام calloc إذا كانت malloc تفي بالغرض !؟

عمليا ليس هناك فرق بينهما, لكن لجعل الكود اكثر وضوحا يفضل استخدام malloc عند حجز ذاكرة لكائن واحد و calloc عند حجز مصفوفة.

لتقريب الفكرة, يمكنك اعتبار أن malloc + memset = calloc.

ما هي فائدة الدالة realloc ؟

realloc تقوم باعادة حجز ذاكرة تم حجزها مسبقا عن طريق calloc/malloc بحجم مختلف وتقوم بنسخ البيانات من الذاكرة القديمة الى الاحدث اذا كان هذا ممكنا ثم تقوم بتحرير الذاكرة القديمة وارجاع عنوان للذاكرة الاحدث . (يمكن استخدامها عندما نريد حذف أو إضافة عناصر إلى المصفوفة)

مالفرق بين الدالة malloc و المعامل new ؟

يكمن الفرق الأساسي في النقاط التالية:

  • malloc لاتستدعي المشيد كما يفعل new.
  • malloc لاتحتوي على آلية لمعالجة الأخطاء داخليا.
  • تشترط malloc تحديد حجم البايتات المراد حجزه حسب نوع المتغير.

للمزيد :

تم تعديل هذه المشاركة بواسطة khaled_prg في 17 أكتوبر 2012 في 12:45

1

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