PDA

View Full Version : سوال: ذخیره رشته در آرایه



redflight
جمعه 28 شهریور 1393, 10:48 صبح
من یه رشته ی مثلا 500 کاراکتری رو به عنوان ورودی می خوام بگیرم مثلا
safksjafkldj.....safjdsikfjdskf که طولش 500 است
یه ارایه 250 تایی هم دارم
چطور می تونم دو تا دوتا کاراکتر های این رشته رو توی خونه های ارایه بریزم؟
مثلا خونه اول :sa
خونه دوم : fk
.....
بهترین راه برای این کار چیه؟ چطور؟ (تابعی هست؟ )

rahnema1
جمعه 28 شهریور 1393, 11:24 صبح
چون قراره در هر خانه آرایه مقصد ، دو بایت ذخیره بشه سریعترین روش cast کردن هست به یک آرایه از نو عunsigned short int
در واقع دو حرف کنار هم می تونند تشکیل یک عدد 2 بایتی بدهند اما دقت کنید هیچ عمل کپی صورت نمی گیره تنها خانه های آرایه قبلی که به صورت یک بایت بود ، به صورت دو بایتی در نظر گرفته می شه

char a[]="TGGGT";
unsigned short int * b= reinterpret_cast<unsigned short int *>(a);

redflight
جمعه 28 شهریور 1393, 11:38 صبح
میشه بیشتر توضیح بدید/

redflight
جمعه 28 شهریور 1393, 11:43 صبح
حالا یه سوال دیگه اگه من مثلا رشته
ACGTG داشته باشم بخوام در خانه های ارایه به این صورت ذخیره بشه چکارکنم؟
خانه اول AC
خانه دوم CG
سوم GT
چهارم TG
یعنی overlap داشته باشن

rahnema1
جمعه 28 شهریور 1393, 12:09 عصر
میشه بیشتر توضیح بدید/

گفتم که وقتی cast میشه aو b هر دو به یک مکان اشاره می کنن و کپی انجام نمیشه که address داره همین را نشون می ده
مورد بعد ببیند هر کاراکتر مثل T یک معادل عددی داره که به صورت hex اینجا نوشتیم

#include <iostream>
using namespace std;
int main()
{
char a[]="ACTG";
cout<< "address of a= 0x"<<hex << (int)a<<endl;
for (int i=0; i< sizeof(a); i++)
cout<< a[i]<<"= 0x"<<hex<<(int)a[i] <<endl;

unsigned short int * b= reinterpret_cast<unsigned short int *>(a);
cout<< "address of b= 0x"<< hex<< (int)b<<endl;
for (int i=0; i< sizeof(a)/2; i++)
cout<< "0x"<<hex<<b[i]<<endl;
}


و هر دو حرف هم یک معادل hex البته 2 بایتی داره که در برنامه زیر مشخص شده


#include <iostream>
using namespace std;
int main()
{
char a[]="ACTG";
char adad[3]={};
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
{
adad[0]=a[i];
adad[1]=a[j];
cout<< adad <<"= 0x"<<hex<<( reinterpret_cast<unsigned short int *>(adad))[0] <<endl;
}
}

البته به خاطر اینکه اکثر سیستم ها little endian هستند ترتیب بایتها معکوس میشه که این اهمیتی نداره چون روی تمام اعداد اعمال میشه

redflight
جمعه 28 شهریور 1393, 12:12 عصر
خیلییییییییی ممنونم
می شه حالت overlapesh هم برام توضیح بدین چکارکنم؟ چون از این راه نمی تونم اونو انجام بدم..

Ananas
جمعه 28 شهریور 1393, 12:12 عصر
#include <iostream>
using namespace std;

int main()
{
__int8 * str_8 = "abcdefgh123456789qwe";
__int16 str_16[21];
for (int i = 0; i < 20; i++)
{
str_16[i] = *(__int16 *)( &( str_8[i] ) );
};
str_16[20] = 0;
cout << (char *)str_16 << endl;
getchar();
return 0;
}

عبارت :
&( str_8[i] )
آدرس str_8[i] هست که تبدیل میکنیم به اشاره گر به __int16 با استفاده از عبارت:
(__int16 *)
و بعد برای دسترسی به محتویات اشاره گر، یک ستاره اضافه میکنیم قبل از عبارت :
(__int16 *)( &( str_8[i] ) )
که میشه :
*(__int16 *)( &( str_8[i] ) )
میتونستیم به جای اضافه کردن ستاره قبل از اون، بعد از این عبارت (که کاملا داخل پرانتز قرار گرفته باشه) از [0] استفاده کنیم (به معنی اولین عضو آرایه) که میشد:
( (__int16 *)( &( str_8[i] ) ) )[0]

redflight
جمعه 28 شهریور 1393, 12:16 عصر
#include <iostream>
using namespace std;

int main()
{
__int8 * str_8 = "abcdefgh123456789qwe";
__int16 str_16[21];
for (int i = 0; i < 20; i++)
{
str_16[i] = *(__int16 *)( &( str_8[i] ) );
};
str_16[20] = 0;
cout << (char *)str_16 << endl;
getchar();
return 0;
}

عبارت :
&( str_8[i] )
آدرس str_8[i] هست که تبدیل میکنیم به اشاره گر به __int16 با استفاده از عبارت:
(__int16 *)
و بعد برای دسترسی به محتویات اشاره گر، یک ستاره اضافه میکنیم قبل از عبارت :
(__int16 *)( &( str_8[i] ) )
که میشه :
*(__int16 *)( &( str_8[i] ) )
میتونستیم به جای اضافه کردن ستاره قبل از اون، بعد از این عبارت (که کاملا داخل پرانتز قرار گرفته باشه) از [0] استفاده کنیم (به معنی اولین عضو آرایه) که میشد:
( (__int16 *)( &( str_8[i] ) ) )[0]

اگه با حالت overlap دار اون طور که گفتم بخوام ذخیره کنم شما می دونین چکار کنم
من نفهمیدم الان شما چی گفتین:خجالت:

rahnema1
جمعه 28 شهریور 1393, 12:30 عصر
حالت overlap


#include <iostream>
using namespace std;
int main()
{
char a[]="ACGTG";
unsigned short * b =new unsigned short[ (sizeof(a)-2)];
//vector<unsigned short> b((sizeof(a)-2));
for (int i=0;i< sizeof(a)-2;i++)
b[i]=(reinterpret_cast<unsigned short int *> (a+i))[0];
}

Ananas
جمعه 28 شهریور 1393, 15:22 عصر
تو پست اول شما گفتید:

یه ارایه 250 تایی هم دارم
یک آرایه ی 250 تایی از چی؟!! آرایه ای از رشته؟ آرایه ای از تک کاراکتر؟ کاراکترش 8 بیتی هست یا 16 بیتی؟
ما فرض رو بر این گرفتیم که میخواید دو تا دو تا کاراکترهای 8 بیتی رو در متغیر های 16 بیتی ذخیره کنید. که جواب نوشتیم. حالا من اگر بخوام ساده تر بگم:
مساله رو به قسمت های کوچیکتر تقسیم کنید بعد حل کنید.
من اول یک تابع تعریف میکنم که دو تا مقدار 8 بیتی رو بگیره و کنار هم تو یک متغیر 16 بیتی ذخیره کنه و بعد تو حلقه ازش استفاده میکنم:

#include <iostream>
using namespace std;

__int16 DoubleInt8ToInt16(const __int8 iA, const __int8 iB)
{
return (iA + (iB << 8));
};

int main()
{
__int8 str_8 [20] = "ABCDEFGHIJ0123456789";
__int16 str_16[10];
//--------------------------------------
for (int i = 0; i < 10; i++)
{
str_16[i] = DoubleInt8ToInt16(
str_8[i * 2],
str_8[i * 2 + 1]);
};
for (int i = 0; i < 10; i++)
{
cout << ((char *)str_16)[i * 2] << ((char *)str_16)[i * 2 + 1] << " ";
};
getchar();
return 0;
};

برای حالت overlap هم به جای i * 2 می نویسم i و طول آرایه دوم رو هم اندازه آرایه اول میگیرم:

#include <iostream>
using namespace std;

__int16 DoubleInt8ToInt16(const __int8 iA, const __int8 iB)
{
return (iA + (iB << 8));
};

int main()
{
__int8 str_8 [20] = "ABCDEFGHIJ0123456789";
__int16 str_16[20];
//--------------------------------------
for (int i = 0; i < 20; i++)
{
str_16[i] = DoubleInt8ToInt16(
str_8[i], // [i * 2] // overlap
str_8[i + 1]); // [i * 2 + 1] // overlap
};
str_16[19] = 0;
for (int i = 0; i < 20; i++)
{
cout << ((char *)str_16)[i * 2] << ((char *)str_16)[i * 2 + 1] << " ";
};
getchar();
return 0;
};

omid_kma
جمعه 28 شهریور 1393, 16:38 عصر
این کد undefined behavior هست :
__int8 str_8 [20] = "ABCDEFGHIJ0123456789";
چون تعداد این کاراکتر ها 20 تا هست که با \0 آخر رشته میشه 21 پس ساز باید 21 باشه نه 20
unsigned short int * b= reinterpret_cast<unsigned short int *>(a);
این هم cross platform نیست چون سایز short int , char میتونن 8 و 16 نباشن و بیشتر باشن . بهتره از int16_t موجود در هدر cstdint استفاده بشه.

من پیشنهادم اینه که از std::string استفاده کنین درسته حافظه بیشتری مصرف می کنه ولی احتمالا از shift و cast های بالا خیلی سریع تر هست و مهمتر از همه قابل فهم و توسعه هم هست .

#include <iostream>
#include <vector>
#include <string>
int main()
{
std::string a="ABCDEFGHI";
std::vector<std::string> overlaps;
overlaps.reserve(a.size());
//por kardan
for(auto it=a.begin();it != a.end()-1;++it){
overlaps.push_back(std::string(it,it+2));
}
//chap
for(auto str : overlaps){
std::cout<<str<<"\n";
}
}

redflight
جمعه 28 شهریور 1393, 18:32 عصر
خیلیییییییی ممنونننننننن
بعد من می تونم یه سوال دیگه اینجا بپرسم؟
من مثلا یک آرایه دارم که از کاراکتر های m تایی تشکیل شده مثلا اگه m=3
خانه اول آرایه daf
خانه دوم afg
خانه سوم lkd
.....
چطور می تونم overlap خانه اول با دوم و سوم رو بررسی کنم منظورم اینه که چطور می تونم بفهمم m-1 کاراکتر اخر خونه ی اول ارایه با m-1 کاراکتر اول خانه های بعدی برابر است یا نه؟
من یه تابع نوشتم که این کار رو می کنه اما خودش تابعی نداره که راحت تر باشه؟ چون من طول رشته ها رو می گیرم و یکی کم می کنم و....

rahnema1
جمعه 28 شهریور 1393, 18:56 عصر
من پیشنهادم اینه که از std::string استفاده کنین درسته حافظه بیشتری مصرف می کنه ولی احتمالا از shift و cast های بالا خیلی سریع تر هست
یه مساله سرعت تبدیل تک تک کاراکترها به زوج کاراکتر هست که باید تست بشه ببینیم کدوم سرعتش بیشتره
و مساله بعدی انجام محاسبات بعدی مثل مقایسه هست که فکر کنم مقایسه دو تا short با هم سریعتر باشه از مقایسه دو تا string دو حرفی
گاهی وقتها حجم محاسبات ( مخصوصا در داده های حجیم مثل DNA ) اونقدر زیاده که یه ذره بهبود در هر محاسبه جزئی هزینه کلی را به مقدار قابل توجهی کاهش میده. شاید در یک کاربرد، سرعت از قابل فهم و توسعه بودن اهمیت بیشتری داشته باشه

redflight
جمعه 28 شهریور 1393, 19:46 عصر
راستش سرعت برای من خیلی مهمه روی data set ام دوتاشو اجرا می کنم و مقایسه می کنم واقعا ممنونممم
سوال بعدیم رو می شه جواب بدید لطفا؟

rahnema1
جمعه 28 شهریور 1393, 21:37 عصر
راستش سرعت برای من خیلی مهمه روی data set ام دوتاشو اجرا می کنم و مقایسه می کنم واقعا ممنونممم
سوال بعدیم رو می شه جواب بدید لطفا؟

تابع memcmp از هدر cstring این کار را انجام میده
http://www.cplusplus.com/reference/cstring/memcmp

redflight
جمعه 28 شهریور 1393, 22:02 عصر
تابع memcmp از هدر cstring این کار را انجام میده
http://www.cplusplus.com/reference/cstring/memcmp

اون سایز مشخصی رو می دیم از یه متغیر استرینگ داخل یکی دیگه کپی می کنه
اما من می خوام m-1 کاراکتر اول یه رشته رو از m-1 کاراکتر آخر یه رشته رو بدست بیارم بعد مقایسه کنم یکی هس یانه؟ :متفکر:

rahnema1
جمعه 28 شهریور 1393, 22:05 عصر
اون سایز مشخصی رو می دیم از یه متغیر استرینگ داخل یکی دیگه کپی می کنه
اما من می خوام m-1 کاراکتر اول یه رشته رو از m-1 کاراکتر آخر یه رشته رو بدست بیارم بعد مقایسه کنم یکی هس یانه؟ :متفکر:


memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
Compare two blocks of memory

هیچ کس نیست

redflight
جمعه 28 شهریور 1393, 22:07 عصر
memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
Compare two blocks of memory

هیچ کس نیست

رشته ها یکی هست یانه:لبخند:
خوب الان اینی که نوشتین اینی که من میگم نمی شه دیگه

redflight
جمعه 28 شهریور 1393, 22:13 عصر
اوه من فکر کردم می گین memcpy شرمندممممم
میشه بگین چطور این رو بنویسم؟ مثلا فرض کنین دو تا رشته توی خانه صفر و یک آرایه A باشه..... (ممنونم... )

rahnema1
جمعه 28 شهریور 1393, 22:16 عصر
char a[]="aaaxabc";
char b[]="abcdfrw";
int c = memcmp(a+4,b,3);

از خانه با اندکس 4 مربوط به آرایه a مقایسه شروع میشه با خانه با اندکس 0 آرایه b
تعداد خانه هایی که مقایسه میشن هم برابر 3 می باشد
اگر c برابر 0 شد دو رشته با هم برابرند در غیر اینصورت برابر نیستند

redflight
جمعه 28 شهریور 1393, 22:39 عصر
ممنونمممممممممم

redflight
شنبه 29 شهریور 1393, 00:23 صبح
ببخشید کار نمی کنه
+ رو نمی شناسه! می گه :
IntelliSense: no operator "+" matches these operands

redflight
شنبه 29 شهریور 1393, 21:46 عصر
حالت overlap


#include <iostream>
using namespace std;
int main()
{
char a[]="ACGTG";
unsigned short * b =new unsigned short[ (sizeof(a)-2)];
//vector<unsigned short> b((sizeof(a)-2));
for (int i=0;i< sizeof(a)-2;i++)
b[i]=(reinterpret_cast<unsigned short int *> (a+i))[0];
}


کار نمی کنه!
مثلا من این کد رو run کردم:

#include <iostream>
using namespace std;
int main()
{
char a[]="ACGTG";
unsigned short * b =new unsigned short[ (sizeof(a)-2)];
//vector<unsigned short> b((sizeof(a)-2));
for (int i=0;i< sizeof(a)-2;i++)
b[i]=(reinterpret_cast<unsigned short int *> (a+i))[0];
for (int i=0;i<3;i++)
cout<<b[i]<<endl;
return 0 ;
}

نتایج زیر را چاپ کرد!!! :
17217
18243
21575
چرا اینجوری شد؟

rahnema1
شنبه 29 شهریور 1393, 22:08 عصر
چرا اینجوری شد؟

چه جور باید باشه خب یک عدد دو بایتی چاپ می کنه دیگه اگه بخواهید hex باشه
cout<< "0x"<<hex <<b[i];

redflight
شنبه 29 شهریور 1393, 22:25 عصر
چرا عدد؟
من می خوام یه رشته بدم مثل ACGTAAGCT
اینا چاپ بشه:
ACG
CGT
GTA
......

rahnema1
شنبه 29 شهریور 1393, 22:31 عصر
این جور میشه چاپ کرد

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char a[]="ACGTG";
unsigned short * b =new unsigned short[ (sizeof(a)-2)];
//vector<unsigned short> b((sizeof(a)-2));
for (int i=0;i< sizeof(a)-2;i++)
b[i]=(reinterpret_cast<unsigned short int *> (a+i))[0];
for (int i=0;i<3;i++)
printf("%.2s\n",reinterpret_cast<char *>(b+i));
return 0 ;
}

redflight
شنبه 29 شهریور 1393, 22:44 عصر
#include <iostream>
#include<fstream>
#include <cstdio>
using namespace std;
int main()
{
char a[5392];
FILE *file = fopen("F:\\nemone.txt", "r");
for(int i=0; i<5392; i++)
fscanf(file,"%s", a[i]);
fclose(file);
unsigned short * b =new unsigned short[ (sizeof(a)-2)];
//vector<unsigned short> b((sizeof(a)-2));
for (int i=0;i< sizeof(a)-2;i++)
b[i]=(reinterpret_cast<unsigned short int *> (a+i))[0];
for (int i=0;i<3;i++)
printf("%.2s\n",reinterpret_cast<char *>(b+i));
return 0 ;
}
ورودی من 5392 تا کاراکتر داره که از فایل دریافت می کنم
اما برنامه اجرا نمی شه! سایزش فکر می کنم چون زیاده! چکار کنم برای این حالت؟

rahnema1
شنبه 29 شهریور 1393, 23:02 عصر
char a[5392];
//char *a = new char[5392];
FILE *file = fopen("F:\\nemone.txt", "r");
fread(a,1,5392,file);
fclose(file);

redflight
یک شنبه 30 شهریور 1393, 22:47 عصر
من این کار رو کردم اما بعضی جاها یکی بر می گردونه! به جای دوتا دوتا ....
اگه بخوام overlap های سه تایی رو برگردونم و توی فایل بنویسه چی؟ یعنی به جای دوتا m تایی....
مثلا ورودی اینه:
http://s5.picofile.com/file/8142025618/nemone.txt.html

rahnema1
یک شنبه 30 شهریور 1393, 23:15 عصر
من این کار رو کردم اما بعضی جاها یکی بر می گردونه! به جای دوتا دوتا ....
اگه بخوام overlap های سه تایی رو برگردونم و توی فایل بنویسه چی؟ یعنی به جای دوتا m تایی....
مثلا ورودی اینه:
http://s5.picofile.com/file/8142025618/nemone.txt.html

فایل شما کاراکتر ها 60 تا 60 تا جدا شده بود که درست کردم وپیوسته شد حالا هر سه تا را در یک سطر قرار می ده
http://www.sharefile.ir/uploads/1411384313.zip

redflight
دوشنبه 31 شهریور 1393, 08:42 صبح
فایل شما کاراکتر ها 60 تا 60 تا جدا شده بود که درست کردم وپیوسته شد حالا هر سه تا را در یک سطر قرار می ده
http://www.sharefile.ir/uploads/1411384313.zip

درسته ممنون