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

[ تمت الإجابة ]كيف يمكن دمج مصفوفتين نصّيّتين ؟

مغلق
بدأه عباس(أ) في 31 يوليو 2012 · 19 رد · 2,059 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

إذا كان

char x[2] = "x";
char y[2] = "y";

كيف يمكن دمج المصفوفتين و الحصول علي "xy"

في الفيجوال بيسك كنت أستخدم العلامة & لدمج النصوص

تم تعديل هذه المشاركة بواسطة عباس(أ) في 31 يوليو 2012 في 22:37

#2

إنظر لهذا المثال, الشرح في الأكواد :

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

int main(int argc, char **argv) {

    char x[]    = "x";
    char y[]    = "y";
    char *new_string;

    /* أنشئ متغير جديد وخصص له ذاكرة تساوي مضروب حجم نوع المتغير في طول المتغيرين + واحد لل \0 بايت */
    new_string  = (char *) malloc(sizeof(char) * (strlen(x) + strlen(y) + 1));
    if(new_string == NULL)
        return(-1); /* لم تعد هناك ذاكرة كافية في النظام, لذا لافائدة من الإستمرار */

    /* إنقل البيانات للمتغير الجديد */
    sprintf(new_string, "%s%s", x, y);
    printf("%s\n", new_string);

    /* لأنك خصصت ذاكرة, فلابد من تحرير هذه الذاكرة مباشرة عند الإنتهاء منها */
    free(new_string);
    return(0);
}
#3

السلام عليكم

يمكنك استخدام الدالة strcat لمثل هذا الأمر.

كما يمكنك أيضا كتابة دالة تُحاكي strcat :

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

char *concatString(char *s1,char *s2){
    char *s3 = NULL;
    s3 = (char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
    strcpy(s3,s1);
    strcat(s3,s2);
    return s3;
}

int main(){
    printf("%s",concatString("ArabTeam","2000"));
    return 0;
}

أرجو لك التوفيق.

#4

أنا جربت هذا الكود ونفع

        char x[2] = "x";
	char y[2] = "y";
	char z[5];
	strcpy(z, x);
        strcat(z, y);

لكن هل يوجد شئ متبقي في الذاكرة أو قد يسبب خطأ

تم تعديل هذه المشاركة بواسطة عباس(أ) في 1 أغسطس 2012 في 00:56

#5
اقتباس
أنا جربت هذا الكود ونفع

char x[2] = "x";
char y[2] = "y";
char z[5];
strcpy(z, x);
strcat(z, y);

لكن هل يوجد شئ متبقي في الذاكرة أو قد يسبب خطأ

الكود عبارة عن حالة مبسطة من ردي السابق :)

عموما, اظن أن الكود صحيح في تلك الحالة لكن في تلك الحالة فقط !

إذا كنت لا تعرف طول كلا من x و y فسيلزمك الحجز الديناميكي لـ z.

بالمناسبة, لدي سؤال: لماذا طول z يساوي خمسة ؟ أظن أن 3 تكفي.

لا تنسى ترشيح الإجابات التي أفادتك.

بالتوفيق.

تم تعديل هذه المشاركة بواسطة أحمد الشنقيطي في 1 أغسطس 2012 في 11:14 — السبب: تحديث المشاركة.

#6

في السي++, يمكنك دمج السلاسل النصية باستخدام الجمع, هكذا :

#include<iostream>
#include<cstring>
using namespace std;

int main(){
    string forumName = "ArabTeam";
    string year = "2000";
    cout<<forumName + year ;
    return 0;
}

تم تعديل هذه المشاركة بواسطة أحمد الشنقيطي في 1 أغسطس 2012 في 14:21 — السبب: إضافة الكود.

#7

أخى اذا كنت تستخدم سي++ فأستخدم أمكانات المكتبة string كما اشاراحمد الشنقيطى هذا افضل لك واقوى

post-15367-027053900%201340345097.gifpost-15367-087183200%201340344597.gif
post-247365-0-10080400-1379403554_thumb.

#8
أحمد الشنقيطي كتب:

السلام عليكم

يمكنك استخدام الدالة strcat لمثل هذا الأمر.

كما يمكنك أيضا كتابة دالة تُحاكي strcat :

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

char *concatString(char *s1,char *s2){
    char *s3 = NULL;
    s3 = (char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
    strcpy(s3,s1);
    strcat(s3,s2);
    return s3;
}

int main(){
    printf("%s",concatString("ArabTeam","2000"));
    return 0;
}

أرجو لك التوفيق.

عزيزى احمد الا ترى ان هذه الدالة تسبب undefined behavior ؟

اقترح ارسال parameter ثالث عبارة عن مؤشر للمصفوفة التى تحفظ فيها نتيجة دمج المصفوفتين

وعندها يمكنك ارجاع مؤشر لها من الدالة كما تحب

تحياتى


﴿وَمَا كَانَ اللَّهُ لِيُعَذِّبَهُمْ وَأَنْتَ فِيهِمْ ۚ وَمَا كَانَ اللَّهُ مُعَذِّبَهُمْ وَهُمْ يَسْتَغْفِرُونَ﴾

الأنفال ۳۳                                  
 

#9

مرحبا أخي و أستاذي محمد :)

اقتباس
عزيزى احمد الا ترى ان هذه الدالة تسبب undefined behavior ؟

لماذا ؟

اقتباس
اقترح ارسال parameter ثالث عبارة عن مؤشر للمصفوفة التى تحفظ فيها نتيجة دمج المصفوفتين

النسخة الأصلية لــ strcat تستقبل مؤشرين فقط, يمكننا استخدام مؤشر ثالث عند محاكاة الدالة و لكن لا أعتقد أنه ضروري (مجرد وجهة نظر :happy: )

#10
اقتباس

مرحبا أخي و أستاذي محمد :)

مبدئيا انت اللى استاذى

اقتباس

لماذا ؟

انت ترجع مؤشر لمتغير داخل الدالة تنتهى حياته بمجرد الخروج من الدالة

ربما يعمل معك بطريقة صحيحة فى بعض المرات لكن ليس دائما

انظر هذا التوقيع للدالة

char * strcat ( char * destination, const char * source );

ثم انظر هذا الرابط

http://www.cplusplus.com/reference/clibrary/cstring/strcat/

وركز فى هذا الجزء

اقتباس

destination

Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.

source

C string to be appended. This should not overlap destination.

وانظر الى ماذا يشير المؤشر المعاد من الدالة

اقتباس

Return Value

destination is returned.

ليس بمؤشر جديد (كما فعلت فى برنامجك) وانما هو للمصفوفة الاولى الموجودة مسبقا خارج الدالة

1


﴿وَمَا كَانَ اللَّهُ لِيُعَذِّبَهُمْ وَأَنْتَ فِيهِمْ ۚ وَمَا كَانَ اللَّهُ مُعَذِّبَهُمْ وَهُمْ يَسْتَغْفِرُونَ﴾

الأنفال ۳۳                                  
 

#11
اقتباس
انت ترجع مؤشر لمتغير داخل الدالة تنتهى حياته بمجرد الخروج من الدالة

+1

معك حق :)

هناك قاعدة تقول :

Never return a reference or a pointer to a local object !

في هذه الحالة سيظل المؤشر يشير الى ذاكرة صالحة للاستخدام لكننا لا نضمن أنه لن يتم الكتابة عليها Overwrite عن طريق حجز متغير محلي آخر.

#12
MOHAMED FATHEI كتب:
نت ترجع مؤشر لمتغير داخل الدالة تنتهى حياته بمجرد الخروج من الدالة

ليست هذه الحالة هنا. السبب في ذلك أن المتغير موجود في جزء الـheap من ذاكرة البرنامج وليس الـstack. إنظر لهذا البرنامج :

#include<stdio.h>

/*
 * stack based
 */

struct values {
    char one;
    char two;
    char three;
};

struct values *init_struct(int x) {
    struct values va_local;
    if(x == 1) {
        va_local.one    = 'A';
        va_local.two    = 'B';
        va_local.three  = 'C';
    } else {
        va_local.one    = 'D';
        va_local.two    = 'E';
        va_local.three  = 'F';
    }
    return(&va_local);
}

int main(int argc, char **argv) {
    struct values *va_one;
    struct values *va_two;

    va_one = init_struct(1);
    printf("%c | %c | %c\n", va_one->one, va_one->two, va_one->three);
    va_two = init_struct(2);
    printf("%c | %c | %c\n", va_two->one, va_two->two, va_two->three);
    return(0);
}

عند تشغيله فسيطبع :

PS C:\Users\Barakat\Desktop> .\a.exe[\b][\i]A | B | C
D | E | F
PS C:\Users\Barakat\Desktop>

لكن بمجرد تغيير ترتيب الأكود للترتيب التالي:

#include<stdio.h>

/*
 * stack based
 */

struct values {
    char one;
    char two;
    char three;
};

struct values *init_struct(int x) {
    struct values va_local;
    if(x == 1) {
        va_local.one    = 'A';
        va_local.two    = 'B';
        va_local.three  = 'C';
    } else {
        va_local.one    = 'D';
        va_local.two    = 'E';
        va_local.three  = 'F';
    }
    return(&va_local);
}

int main(int argc, char **argv) {
    struct values *va_one;
    struct values *va_two;

    va_one = init_struct(1);
    va_two = init_struct(2);

    printf("%c | %c | %c\n", va_one->one, va_one->two, va_one->three);
    printf("%c | %c | %c\n", va_two->one, va_two->two, va_two->three);
    return(0);
}

PS C:\Users\Barakat\Desktop> .\a.exe[\b][\i]D | E | F
  |   |  
PS C:\Users\Barakat\Desktop>

نحن لم نغير شيء يفترض أن يسبب شيء الا أن النتائج إختلفت تماماً.

سبب الخطأ أن المؤشر الذي تعيده الدالة يشير لبيانات موجودة في الـstack frame الخاص بالدلة init_struct. عند الخروج من الدالة فإن الـstack frame يُحرر ولكن البيانات لاتختفي بل تبقى. عند إستدعاء الدالة مرة أخرى أو أي دالة أخرى فستكتب فوق البيانات السابقة.

هذا البرنامج لايعاني من نفس المشكلة :

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

/*
 * heap based
 */

struct values {
    char one;
    char two;
    char three;
};

struct values *init_struct(int x) {
    struct values *va_local = (struct values *) malloc(sizeof(struct values));
    if(va_local == NULL)
        return(NULL);
    if(x == 1) {
        va_local->one    = 'A';
        va_local->two    = 'B';
        va_local->three  = 'C';
    } else {
        va_local->one    = 'D';
        va_local->two    = 'E';
        va_local->three  = 'F';
    }
    return(va_local);
}

int main(int argc, char **argv) {
    struct values *va_one;
    struct values *va_two;

    va_one = init_struct(1);
    if(va_one == NULL) return(-1);
    printf("%c | %c | %c\n", va_one->one, va_one->two, va_one->three);
    va_two = init_struct(2);
    if(va_two == NULL) return(-1);
    printf("%c | %c | %c\n", va_two->one, va_two->two, va_two->three);

    free(va_one);
    free(va_two);
    return(0);
}

وحتى لو عكسنا الترتيب :

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

/*
 * heap based
 */

struct values {
    char one;
    char two;
    char three;
};

struct values *init_struct(int x) {
    struct values *va_local = (struct values *) malloc(sizeof(struct values));
    if(va_local == NULL)
        return(NULL);
    if(x == 1) {
        va_local->one    = 'A';
        va_local->two    = 'B';
        va_local->three  = 'C';
    } else {
        va_local->one    = 'D';
        va_local->two    = 'E';
        va_local->three  = 'F';
    }
    return(va_local);
}

int main(int argc, char **argv) {
    struct values *va_one;
    struct values *va_two;

    va_one = init_struct(1);
    if(va_one == NULL) return (-1);
    va_two = init_struct(2);
    if(va_two == NULL) return (-1);

    printf("%c | %c | %c\n", va_one->one, va_one->two, va_one->three);
    printf("%c | %c | %c\n", va_two->one, va_two->two, va_two->three);

    free(va_one);
    free(va_two);
    return(0);
}

فالنتيجة واحدة :

PS C:\Users\Barakat\Desktop> .\a.exe[\b][\i]A | B | C
D | E | F
PS C:\Users\Barakat\Desktop>

لأن البيانات موجودة في الـheap والذي لايرتبط مع حياة الدالة , الـstack frame. الكود الذي كتبه أحمد مثل الحالة الثانية , البيانات موجود في الـheap لذا لايوجد قلق من هذه الناحية.

أغلب المصرفات التي أعرفها تنبه على مثل هذا الخطأ, فـgcc سيعطيك الرسالة :

warning: function returns address of local variable

و vc سيعطي :

warning C4172: returning address of local variable or temporary

الخطأ يدور حول الـstack frame. إذا فهمته فسيتضح الموضوع.

----

@ أحمد : إنبه لهذا الخطأ هنا :

s3 = (char *) malloc( (strlen(s1) + strlen(s2)) * sizeof(char) );

الدالة strlen تحسب طول النص بدون الـnull بايت الموجود بنهاية السلسلة النصية. لو مرر أحد "A" و "BC" فستخصص ذاكرة بطول 3 بايت وأنت فعلياً تحتاج 3 بايت + 1 بايت للـ"0\". لذا إجعلها :

s3 = (char *) malloc( (strlen(s1) + strlen(s2) + 1) * sizeof(char) );

ودوماً تأكد من أن malloc لم تعد NULL (أي فشلت) لأن هذه الحالة تحدث. وإستخدم free لتحرير الذاكرة بعد التأكد من أن الذاكرة فعلاً محجوزة ولاتحتوي على NULL.

#13

الموضوع كله لا علاقه له بحجز ذواكر, هو يخص سوء تعامل مع الـ stack.

يتعلق الأمر بالـ Stack وكيف تكون الــ local variables و الـ frame.

اقتباس
المتغير موجود في جزء الـheap من ذاكرة البرنامج وليس الـstack.

نحن نتكلم هنا عن المؤشر نفسه وليس الذاكرة التي يشير اليها, بالطبع المؤشر موجود داخل الـ Stack لأنه Local Variable في حالتنا.

ما كنت أريد قوله هو أن المتغيرات المحلية لا يتم "تحريرها" عند الخروج من الـ Scope الخاص بالدالة, بل يتم استخدام Frame مختلف عن طريق زيادة الـ Stack pointer مما يؤدي الى جعل الـ Frame السابق قابل للكتابة عليه عن طريق تعريف متغيرات محلية اخرى في الـ Parent Routine.

اقتباس
@ أحمد : إنبه لهذا الخطأ هنا

عادة, لا أدقق في مثل هذه التفاصيل حتى لا أربك القارئ (الذي ربما يكون جديدا على هذه الأمور), لذا أكتب الكود بغض النظر عن ما يحدث وراء الكواليس :)

عموما, هذا الكود بعد التعديل:

char *concatString(char *s1,char *s2){
    char *s3 = NULL;
    s3 = (char *) malloc( (strlen(s1) + strlen(s2) + 1) * sizeof(char) );
    if(s3 != NULL){
      strcpy(s3,s1);
      strcat(s3,s2);
      return s3;
    }else return NULL;
}
#14
أحمد الشنقيطي كتب:

نحن نتكلم هنا عن المؤشر نفسه وليس الذاكرة التي يشير اليها, بالطبع المؤشر موجود داخل الـ Stack لأنه Local Variable في حالتنا.

لم أفهم مامشكلة المؤشر نفسه. هلا وضحت.

#15
اقتباس
لم أفهم مامشكلة المؤشر نفسه. هلا وضحت.

الداله التى تحتوى على المتغير من نوع مؤشر قد انتهى عملها و تمت العودة منها ليتم تنفيذ باقى البرنامج, فى هذه الحاله المكان الموجود داخل ذاكرة الـ stack و الذى كان مستخدما من قبل المتغير من نوع المؤشر سيظل محتفظ بالقيمة التى به طالما لم يُستخدم ذلك المكان من قبل دالة أخرى.

#16

عند الخروج من الدالة فلن تبقى قيمتة المؤشر, عنوان البيانات, في المكدس, بل سيتم نقلها للمسجل eax (لأنها ستضيع) وتستلمها الدالة التي إستدعته. فلا يوجد هناك undefined behavior أو أي خلل كما قال MOHAMED FATHEI.

هذه القاعدة والتي وصفها MOHAMED FATHEI :

اقتباس

Never return a reference or a pointer to a local object !

تتحدث عن مثل هذه الحالة :

char *foo(void) {
    char x[] = "foo";
    return(&x);
}

ولكن لاتنطبق على المثال الذي كتبته.

#17
أحمد الشنقيطي كتب:

الداله التى تحتوى على المتغير من نوع مؤشر قد انتهى عملها و تمت العودة منها ليتم تنفيذ باقى البرنامج, فى هذه الحاله المكان الموجود داخل ذاكرة الـ stack و الذى كان مستخدما من قبل المتغير من نوع المؤشر سيظل محتفظ بالقيمة التى به طالما لم يُستخدم ذلك المكان من قبل دالة أخرى.

يمكنك زيارة الرابط التالى للمزيد عن هذة المشكلة الغير معرفة السلوك

post-15367-027053900%201340345097.gifpost-15367-087183200%201340344597.gif
post-247365-0-10080400-1379403554_thumb.

#18

مرحبا Mr.B

نقاش مفيد و جيد بكل تأكيد

ما رأيك فى التالى :

post-165385-086850900 1344071915_thumb.p

من Stroustrup ؟

انا مع احمد فى

اقتباس

في هذه الحالة سيظل المؤشر يشير الى ذاكرة صالحة للاستخدام لكننا لا نضمن أنه لن يتم الكتابة عليها Overwrite عن طريق حجز متغير محلي آخر.

المرفقات
ptr.png

تم تعديل هذه المشاركة بواسطة MOHAMED FATHEI في 4 أغسطس 2012 في 12:31


﴿وَمَا كَانَ اللَّهُ لِيُعَذِّبَهُمْ وَأَنْتَ فِيهِمْ ۚ وَمَا كَانَ اللَّهُ مُعَذِّبَهُمْ وَهُمْ يَسْتَغْفِرُونَ﴾

الأنفال ۳۳                                  
 

#19

الصفحة التي وضعتها تتحدث عن عدم تهيئة مؤشر بعنوان صالح. لكن مالرابط بينها وبين هذا الكود :

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

char *concatString(char *s1,char *s2){
    char *s3 = NULL;
    s3 = (char *) malloc( (strlen(s1) + strlen(s2) + 1) * sizeof(char) );
    if(s3 != NULL){
      strcpy(s3,s1);
      strcat(s3,s2);
      return s3;
    } else return NULL;
}

int main(int argc, char **argv) {

    char *foo  = concatString("One", "Two");

    if(foo != NULL) {
        printf("%s\n", foo);
        free(foo);
    }

    return(0);
}

حدد على الجزء الذي يمكن أن يحدث undefined behavior وتعديلك عليه. بصراحة أنا لا أرى شيء خاطئ به وفعلت جميع تحذيرات المصرف ولم يظهر شيء.

1
#20

معك حق Mr.B

malloc تحجز مكان فى ال Heap وليس ال Stack

اقتباس

malloc

A function in the standard C library that performs dynamic allocation of memory(2).

Many people use "malloc" as a verb to mean "allocate dynamically".

وهو فى هذه الحالة لا يشير الى automatic variable داخل الدالة

اقتباس

heap allocation (also known as dynamic allocation)

Heap allocation or dynamic allocation means run-time allocation and deallocation of storage in arbitrary order.

Dynamic allocation is usually for objects whose size, quantity, or lifetime could not be determined at compile-time. It is necessary to implement modern data structures, such as recursive trees and full closures.

Objects on the heap can be managed manually, as in C, or automatically, as in Lisp and JavaTM.

وبما اننا حتى النهاية لم نستدعى الدالة ()free على هذا المؤشر

اذا هو مازال صالحا للاستخدام مع انى لدى احساس انه (unsafe)

تحياتى


﴿وَمَا كَانَ اللَّهُ لِيُعَذِّبَهُمْ وَأَنْتَ فِيهِمْ ۚ وَمَا كَانَ اللَّهُ مُعَذِّبَهُمْ وَهُمْ يَسْتَغْفِرُونَ﴾

الأنفال ۳۳                                  
 

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

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

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…