01/10/2018, 01:13

Mọi người có thể giải thích hộ em đoạn code này k? (ngôn ngữ C++ ạ)

#include<iostream>

using namespace std;

void mystery1(char *s1,char *s2){
    while(*s1 != ''){
        ++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;
}
Tao Không Ngu. viết 03:26 ngày 01/10/2018

Hi HoangHoangNew.
Bạn chạy thử code chưa ?

Hoang viết 03:14 ngày 01/10/2018

rùi ạ em chay điên aaa bbb nó ra aaabbb
em k hiểu tại sao ạ@@!

viết 03:13 ngày 01/10/2018

hàm mystery1 là nối chuỗi s2 vào chuỗi s1.

while(*s1 != ‘\0’){
++s1;
}

là để đi tới cuối chuỗi s1

for(;*s1 = *s2;s1++,s2++){

*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++;
}
Tao Không Ngu. viết 03:20 ngày 01/10/2018

Hi HoangHoangNew.
Bạn kiếm code này ở đâu thế ? Mình thấy code này có vấn đề!

Hoang viết 03:25 ngày 01/10/2018

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 ạ

Hoang viết 03:24 ngày 01/10/2018

em lấy ở trong cuốn cpphowtoprogram9theditor ạ

viết 03:26 ngày 01/10/2018

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
Hoang viết 03:20 ngày 01/10/2018

oke a em hiểu rùi ạ :D:D:D:D cảm ơn a nhiều

Tao Không Ngu. viết 03:29 ngày 01/10/2018

Sao họ lại code mẫu kiểu này nhỉ ?

viết 03:29 ngày 01/10/2018

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.

Tao Không Ngu. viết 03:20 ngày 01/10/2018

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ử @_@!

viết 03:21 ngày 01/10/2018

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ợ.

Tao Không Ngu. viết 03:18 ngày 01/10/2018

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. @_@!

viết 03:28 ngày 01/10/2018

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? @_@
Tao Không Ngu. viết 03:18 ngày 01/10/2018

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;
}

viết 03:22 ngày 01/10/2018

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.

viết 03:27 ngày 01/10/2018

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

Tao Không Ngu. viết 03:17 ngày 01/10/2018

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. @_@!

viết 03:24 ngày 01/10/2018

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

Tao Không Ngu. viết 03:19 ngày 01/10/2018

Thì đó không phải cấp phát, không quan tâm giải phóng cứ code thôi tạo bao nhiêu đối tượng cũng được @_@!

Bài liên quan
0