إذا كان
char x[2] = "x"; char y[2] = "y";
كيف يمكن دمج المصفوفتين و الحصول علي "xy"
في الفيجوال بيسك كنت أستخدم العلامة & لدمج النصوص
إذا كان
char x[2] = "x"; char y[2] = "y";
كيف يمكن دمج المصفوفتين و الحصول علي "xy"
في الفيجوال بيسك كنت أستخدم العلامة & لدمج النصوص
تم تعديل هذه المشاركة بواسطة عباس(أ) في 31 يوليو 2012 في 22:37
إنظر لهذا المثال, الشرح في الأكواد :
#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);
}السلام عليكم
يمكنك استخدام الدالة 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;
}أرجو لك التوفيق.
C++ and Java, say, are presumably growing faster than plain C, but I bet C will still be around. ― Dennis Ritchie
~OoO~________--------------------------------------------________~OoO~
من مواضيعي :
أنا جربت هذا الكود ونفع
char x[2] = "x";
char y[2] = "y";
char z[5];
strcpy(z, x);
strcat(z, y);لكن هل يوجد شئ متبقي في الذاكرة أو قد يسبب خطأ
تم تعديل هذه المشاركة بواسطة عباس(أ) في 1 أغسطس 2012 في 00:56
اقتباسأنا جربت هذا الكود ونفع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 — السبب: تحديث المشاركة.
C++ and Java, say, are presumably growing faster than plain C, but I bet C will still be around. ― Dennis Ritchie
~OoO~________--------------------------------------------________~OoO~
من مواضيعي :
في السي++, يمكنك دمج السلاسل النصية باستخدام الجمع, هكذا :
#include<iostream>
#include<cstring>
using namespace std;
int main(){
string forumName = "ArabTeam";
string year = "2000";
cout<<forumName + year ;
return 0;
}تم تعديل هذه المشاركة بواسطة أحمد الشنقيطي في 1 أغسطس 2012 في 14:21 — السبب: إضافة الكود.
C++ and Java, say, are presumably growing faster than plain C, but I bet C will still be around. ― Dennis Ritchie
~OoO~________--------------------------------------------________~OoO~
من مواضيعي :
أحمد الشنقيطي كتب:السلام عليكم
يمكنك استخدام الدالة 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 ثالث عبارة عن مؤشر للمصفوفة التى تحفظ فيها نتيجة دمج المصفوفتين
وعندها يمكنك ارجاع مؤشر لها من الدالة كما تحب
تحياتى
﴿وَمَا كَانَ اللَّهُ لِيُعَذِّبَهُمْ وَأَنْتَ فِيهِمْ ۚ وَمَا كَانَ اللَّهُ مُعَذِّبَهُمْ وَهُمْ يَسْتَغْفِرُونَ﴾
الأنفال ۳۳
مرحبا أخي و أستاذي محمد :)
اقتباسعزيزى احمد الا ترى ان هذه الدالة تسبب undefined behavior ؟
لماذا ؟
اقتباساقترح ارسال parameter ثالث عبارة عن مؤشر للمصفوفة التى تحفظ فيها نتيجة دمج المصفوفتين
النسخة الأصلية لــ strcat تستقبل مؤشرين فقط, يمكننا استخدام مؤشر ثالث عند محاكاة الدالة و لكن لا أعتقد أنه ضروري (مجرد وجهة نظر :happy: )
C++ and Java, say, are presumably growing faster than plain C, but I bet C will still be around. ― Dennis Ritchie
~OoO~________--------------------------------------------________~OoO~
من مواضيعي :
اقتباسمرحبا أخي و أستاذي محمد :)
مبدئيا انت اللى استاذى
اقتباسلماذا ؟
انت ترجع مؤشر لمتغير داخل الدالة تنتهى حياته بمجرد الخروج من الدالة
ربما يعمل معك بطريقة صحيحة فى بعض المرات لكن ليس دائما
انظر هذا التوقيع للدالة
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
معك حق :)
هناك قاعدة تقول :
Never return a reference or a pointer to a local object !
في هذه الحالة سيظل المؤشر يشير الى ذاكرة صالحة للاستخدام لكننا لا نضمن أنه لن يتم الكتابة عليها Overwrite عن طريق حجز متغير محلي آخر.
C++ and Java, say, are presumably growing faster than plain C, but I bet C will still be around. ― Dennis Ritchie
~OoO~________--------------------------------------------________~OoO~
من مواضيعي :
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.
الموضوع كله لا علاقه له بحجز ذواكر, هو يخص سوء تعامل مع الـ 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;
}C++ and Java, say, are presumably growing faster than plain C, but I bet C will still be around. ― Dennis Ritchie
~OoO~________--------------------------------------------________~OoO~
من مواضيعي :
أحمد الشنقيطي كتب:نحن نتكلم هنا عن المؤشر نفسه وليس الذاكرة التي يشير اليها, بالطبع المؤشر موجود داخل الـ Stack لأنه Local Variable في حالتنا.
لم أفهم مامشكلة المؤشر نفسه. هلا وضحت.
اقتباسلم أفهم مامشكلة المؤشر نفسه. هلا وضحت.
الداله التى تحتوى على المتغير من نوع مؤشر قد انتهى عملها و تمت العودة منها ليتم تنفيذ باقى البرنامج, فى هذه الحاله المكان الموجود داخل ذاكرة الـ stack و الذى كان مستخدما من قبل المتغير من نوع المؤشر سيظل محتفظ بالقيمة التى به طالما لم يُستخدم ذلك المكان من قبل دالة أخرى.
C++ and Java, say, are presumably growing faster than plain C, but I bet C will still be around. ― Dennis Ritchie
~OoO~________--------------------------------------------________~OoO~
من مواضيعي :
عند الخروج من الدالة فلن تبقى قيمتة المؤشر, عنوان البيانات, في المكدس, بل سيتم نقلها للمسجل 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);
}ولكن لاتنطبق على المثال الذي كتبته.
أحمد الشنقيطي كتب:الداله التى تحتوى على المتغير من نوع مؤشر قد انتهى عملها و تمت العودة منها ليتم تنفيذ باقى البرنامج, فى هذه الحاله المكان الموجود داخل ذاكرة الـ stack و الذى كان مستخدما من قبل المتغير من نوع المؤشر سيظل محتفظ بالقيمة التى به طالما لم يُستخدم ذلك المكان من قبل دالة أخرى.
يمكنك زيارة الرابط التالى للمزيد عن هذة المشكلة الغير معرفة السلوك
مرحبا Mr.B
نقاش مفيد و جيد بكل تأكيد
ما رأيك فى التالى :
من Stroustrup ؟
انا مع احمد فى
اقتباسفي هذه الحالة سيظل المؤشر يشير الى ذاكرة صالحة للاستخدام لكننا لا نضمن أنه لن يتم الكتابة عليها Overwrite عن طريق حجز متغير محلي آخر.
تم تعديل هذه المشاركة بواسطة MOHAMED FATHEI في 4 أغسطس 2012 في 12:31
﴿وَمَا كَانَ اللَّهُ لِيُعَذِّبَهُمْ وَأَنْتَ فِيهِمْ ۚ وَمَا كَانَ اللَّهُ مُعَذِّبَهُمْ وَهُمْ يَسْتَغْفِرُونَ﴾
الأنفال ۳۳
الصفحة التي وضعتها تتحدث عن عدم تهيئة مؤشر بعنوان صالح. لكن مالرابط بينها وبين هذا الكود :
#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 وتعديلك عليه. بصراحة أنا لا أرى شيء خاطئ به وفعلت جميع تحذيرات المصرف ولم يظهر شيء.
معك حق 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)
تحياتى
﴿وَمَا كَانَ اللَّهُ لِيُعَذِّبَهُمْ وَأَنْتَ فِيهِمْ ۚ وَمَا كَانَ اللَّهُ مُعَذِّبَهُمْ وَهُمْ يَسْتَغْفِرُونَ﴾
الأنفال ۳۳
هذا الموضوع مغلق.
المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية
جارٍ التحقق من المتواجدين…