#include<iostream>
using namespace std;
void mystery1(char *s1,char *s2){
while(*s1 != '\0'){
++s1;
}
for(;*s1 = *s2;s1++,s2++){
cout << "Hello" <<endl;
}
}
int main(){
char string1[80];
char string2[80];
cout << "Enter two string: ";
cin >> string1 >>string2;
mystery1(string1,string2);
cout <<string1 <<endl;
system("pause");
return 0;
}
Nhờ giải thích đoạn code ngôn ngữ C++
Hi HoangHoangNew.
Bạn chạy thử code chưa ?
rùi ạ em chay điên aaa bbb nó ra aaabbb
em k hiểu tại sao ạ@@!
hàm mystery1 là nối chuỗi s2 vào chuỗi s1.
là để đi tới cuối chuỗi s1
*s1 = *s2 là copy ký tự hiện tại mà s2 trỏ vào sang *s1, sau đó kiểm tra xem nếu *s1 == 0 thì dừng vòng for, còn ko thì tiếp tục copy. Trong C/C++ thì phép gán có trả về giá trị, là giá trị của vế trái. *s1 = *s2 thì ngoài gán ra nó còn trả về giá trị của *s1. Khi *s1 == 0 hay ‘\0’ thì đồng nghĩa với false, vòng lặp bị dừng, còn những giá trị khác 0 thì đồng nghĩa với true, vòng lặp tiếp tục.
viết dài ra là
while (true)
{
*s1 = *s2;
if (*s1 == '\0') break;
s1++;
s2++;
}
Hi HoangHoangNew.
Bạn kiếm code này ở đâu thế ? Mình thấy code này có vấn đề!
thank anh nhiều ạ nhưng a có thể giải thích tại sao lúc em debug:
vd em nhập :string s1 = aaa, string s2 = bbb;
rồi chạy tới hàm mystery1(s1,s2).
mỗi khi s1++ thì chữ (a) nó giảm bớt đi 1 không ạ
em lấy ở trong cuốn cpphowtoprogram9theditor ạ
ko, tại C string là chuỗi kết thúc bằng ký tự ‘\0’. Nên chuỗi “aaa” thật ra có 4 ký tự là ‘a’, ‘a’, ‘a’, và ‘\0’. Sau vòng while thì s1 trỏ tới ‘\0’. Vòng for thứ nhất sẽ gán ‘\0’ này thành ‘b’, rồi tiếp tục tới khi gặp ‘\0’ trong chuỗi s2 thì dừng, s1 lúc này chứa ‘a’,‘a’,‘a’,‘b’,‘b’,‘b’,‘b’, và ‘\0’.
//ban đầu
['a']['a']['a']['\0']
^
s1
['b']['b']['b']['b']['\0']
^
s2
//sau khi vòng while kết thúc
['a']['a']['a']['\0']
^
s1
['b']['b']['b']['b']['\0']
^
s2
//sau vòng for thứ nhất
['a']['a']['a']['b'][???]
^
s1
['b']['b']['b']['b']['\0']
^
s2
//sau vòng for thứ hai
['a']['a']['a']['b']['b'][???]
^
s1
['b']['b']['b']['b']['\0']
^
s2
//sau vòng for thứ ba
['a']['a']['a']['b']['b']['b'][???]
^
s1
['b']['b']['b']['b']['\0']
^
s2
//sau vòng for thứ bốn
['a']['a']['a']['b']['b']['b']['b'][???]
^
s1
['b']['b']['b']['b']['\0']
^
s2
//sau vòng for thứ năm
['a']['a']['a']['b']['b']['b']['b']['\0']
^
s1
['b']['b']['b']['b']['\0']
^
s2
oke a em hiểu rùi ạ :D:D:D:D cảm ơn a nhiều
Sao họ lại code mẫu kiểu này nhỉ ?
code kiểu từng bước thì tác giả có lẽ sợ bị chê thiếu hiểu biết Code gọn lại mấy bước thì lại gây khó hiểu.
Không chỉ là việc code không tường mình vòng lặp.
Mà việc thao tác với con trỏ một cách không an toàn. Mình đang tìm tải về xem thử @_@!
cái kiểm tra *s1 = *s2 đó là đoạn code đẹp nhất trong C đó. Nếu đọc source strcpy thì thấy có while (*dst++ = *src++);
cực kì đẹp, tác giả này còn viết tách ++ ra là hên rồi. Đáng lẽ viết là while (*s1++ = *s2++);
là đủ rồi.
https://en.wikibooks.org/wiki/C_Programming/C_Reference/string.h/strcpy
char *strcpy(char *dest, const char *src)
{
unsigned i;
for (i=0; src[i] != '\0'; ++i)
dest[i] = src[i];
dest[i] = '\0';
return dest;
}
char *strcpy(char *dest, const char *src)
{
char *save = dest;
while(*dest++ = *src++);
return save;
}
cái nào đẹp hơn
ban đầu mình đọc thấy while(*dest++ = *src++);
rồi hiểu nó thì thấy nổ não lắm, ít ra C nó xài null terminated string cũng ra được 1 dòng code đẹp như vậy
https://www.quora.com/What-is-the-most-beautiful-piece-of-code/answer/Albert-Sheu?srid=8rsK
Everything you need to know about C-style strings and pointers in an example implementation of strcpy():
while (*str1++ = *str2++);
ko an toàn thì đúng rồi, s1 phải bảo đảm đủ dài để chứa thêm s2 vào. Còn s1 s2 có trỏ tới đâu thì kệ nó, ko cần gán lại đâu vì nó là bản copy mà, ko phải bản chính đâu mà sợ.
Tất nhiên là khi dùng hàm strcpy có bước cấp phát vùng nhớ đủ cho cả hai sâu trước.
Nhưng mà code lib kiểu vầy thì quả là cạn lời. @_@!
cấp phát thì phải có giải phóng. Khi 1 hàm tự cấp phát thì người sử dụng có biết mà giải phóng ko? Vd gọi mystery1 1000 lần mà ko có lần nào giải phóng chuỗi cũ thì leak ~ 100KB, game nào mà xài hàm kiểu này thì chơi 2 3 tiếng chắc phải reset máy vì hết RAM @_@
hàm trong C nên tránh cấp phát mà ko giải phóng. Cấp phát/giải phóng là nhiệm vụ của hàm gọi nó @_@
đây cũng là lý do mà ko ai xài strdup là hàm ko chuẩn, vì nó có cấp phát động, ko ai muốn nhớ phải free() nó đâu, và nó gây memory leak cực kì thường xuyên vì chả ai nhớ free nó cả. Vd
printf("%s", strdup("abcdef")); //leak
char* temp = strdup("abcdef");
printf("%s", temp);
free(temp); //có free đây, code đúng, nhưng người đọc sẽ tự hỏi: malloc ở đâu vậy? @_@
Không ý là trước khi gọi hàm strcpy thì có bước kiểm tra và cấp phát vùng nhớ rồi mới gọi hàm. Hoặc dùng mem copy. Chứ thường thì khi thao tác với sâu đa phần là cấp phát động sau vừa đủ size luôn.
#include<iostream>
#include<cstring>
using namespace std;
int main(){
char tmp[80];
char *str1;
char *str2;
cout << "Enter two string: ";
cin >> tmp;
str1 = new char[strlen(tmp)];
strcpy(str1, tmp);
cin >> tmp;
str2 = new char[strlen(tmp)];
strcpy(str2, tmp);
cout << str1 << " " << str2;
delete str1;
delete str2;
system("pause");
return 0;
}
làm mấy cái đó tỉ mỉ lắm, chả ai muốn viết thêm 2 dòng malloc/free cả, nên để chuỗi có kích thước cố định ví dụ 40 char, rồi truyền số 40 này vào hàm copy luôn, để strcpy tới 40 char là đủ. => strncpy()
. Bởi vậy VS nó thường hay phàn nàn strcpy()
là ở chỗ này.
C++ thì xài std::string
cho lành, đừng nên new
với delete
(hoặc new[]
, delete[]
)
mà phải là delete[] s1;
, delete[] s2;
, delete
ko thì ko đủ cho mảng (sai). Lỗi liền đó, dễ sai lắm
Thảo nào họ bỏ cấp phát động trong java với C#. Có lẽ không phải ai cũng tối ưu từng byte bộ nhớ một. @_@!
trong C# Java toàn bộ là cấp phát động mà, đâu phải bỏ, mà là giấu nó đi , có mấy kiểu nguyên thủy hay struct (C# only) thì mới là ko cấp phát động thôi