Bài tập về vòng lặp cho người mới bắt đầu (1 người xem)

  • Thread starter Thread starter SA_DQ
  • Ngày gửi Ngày gửi
Liên hệ QC

Người dùng đang xem chủ đề này

BÀI 01: MÃ HÓA 1 ĐOẠN VĂN BẢN​

ABCDEFTS4BIQTOI YEU GIAI PHAP EXCEL TU 2006
GHIJKLRA5CJV
MNOPQRU06DKW?
STUVWXO17ELX
YZ0123N28FMY
456789G39HPZ
NM
Ta có bảng N với 36 ký tự & ký số được sắp xếp theo 1 trật tự qui ước



& bảng M cũng những kí tự & ký số đó ta bố trí theo mật mã có chìa khóa là 'TRUONG SA'

Đề bài yêu cầu chúng ta mã hòa câu "TOI YEU GIAI PHAP EXCEL TU 2006"

Xin lưu ý: Đề bài chỉ dành ch những lập trình viên VBA trình độ sơ cấp
Rất mong nhận được nhiều ý kiến & lời giải

[Gọi ý lần 1] (Sau 3 giờ): 'YEU' => 'NI7'
 
Lần chỉnh sửa cuối:
BÀI 01: MÃ HÓA 1 ĐOẠN VĂN BẢN​

ABCDEFTS4BIQTOI YEU GIAI PHAP EXCEL TU 2006
GHIJKLRA5CJV
MNOPQRU06DKW?
STUVWXO17ELX
YZ0123N28FMY
456789G39HPZ
NM
Ta có bảng N với 36 ký tự & ký số được sắp xếp theo 1 trật tự qui ước



& bảng M cũng những kí tự & ký số đó ta bố trí theo mật mã có chìa khóa là 'TRUONG SA'

Đề bài yêu cầu chúng ta mã hòa câu "TOI YEU GIAI PHAP EXCEL TU 2006"

Xin lưu ý: Đề bài chỉ dành ch những lập trình viên VBA trình độ sơ cấp
Rất mong nhận được nhiều ý kiến & lời giải

[Gọi ý lấn]: 'YEU' => 'NI7'
Cái này như kiểu là lấy đủ tên đó rồi còn thừa ký tự nào thì bỏ sang bên canh.Mà có giải thưởng không bác Sa.
 
Upvote 0
Cái này (2) như kiểu là lấy đủ tên đó rồi còn thừa ký tự nào thì bỏ sang bên canh. (1) Mà có giải thưởng không bác Sa.
(1) Có là hiển nhiên nhưng là tính điểm
(2) Chứ cái 'T' ở bảng N được thay bằng chứ cái ở đúng hàng & cột ở bảng M,. . . . ('1')
 
Lần chỉnh sửa cuối:
Upvote 0
Làm xong bài tập này thành công thì người học đạt (trình độ) gì?
Với "vòng lặp" thì nó quá căn bản. Chưa đủ để thách thức hiểu biết về vòng lặp.
Với kiến thức giải thuật (phép áp 1-1 chuyển đổi giữa hai tập hợp) thì nó lại vượt trên căn bản rồi.
Trước mắt thì có vài giải thuật về phép áp. Và độ cao cấp tuỳ thuộc vào sự uyển chuyển của bảng mã.
 
Upvote 0
Làm xong bài tập này thành công thì người học đạt (trình độ) gì?
Với "vòng lặp" thì nó quá căn bản. Chưa đủ để thách thức hiểu biết về vòng lặp. . . . .
Bài này chỉ nhắm là ôn lại kiến thức vòng lặp bình thường thôi mà anh!

Với các bạn khác: Đáp án ở bài #4 là phương án xài 3 vòng lặp
Nếu ta xài kết hợp với phương thức FIND() thì chỉ cần 1 vòng lặp để duyệt mệnh đề cần mã hóa; Các bạn có thể thử thêm xem sao?
 
Lần chỉnh sửa cuối:
Upvote 0
Bài này chỉ nhắm là ôn lại kiến thức vòng lặp bình thường thôi mà anh!

Với các bạn khác: Đáp án ở bài #4 là phương án xài 3 vòng lặp
Nếu ta xài kết hợp với phương thức FIND() thì chỉ cần 1 vòng lặp để duyệt mệnh đề cần mã hóa; Các bạn có thể thử thêm xem sao?
Cháu xin gửi lời giải như sau:
 

File đính kèm

Upvote 0
Sau khi các bạn mã hóa thành công Bác SA_DG dẫn các bạn đến đây luôn

Advanced Encryption Standard (Tiêu chuẩn mã hóa tiên tiến - AES)

Hoặc Twofish

Trót học mã hóa, học thêm để thành chuyên gia.
 
Lần chỉnh sửa cuối:
Upvote 0
Rốt cuộc lại thì bài này là học vòng lặp hay mã hoá?
Đã mang cái tiêu đề "căn bản" thì lo chu toàn cái "căn bản". Chưa gì hết đã tính lúc thành "chuyên gia".

Bài này chỉ nhắm là ôn lại kiến thức vòng lặp bình thường thôi mà anh!

Với các bạn khác: Đáp án ở bài #4 là phương án xài 3 vòng lặp
Nếu ta xài kết hợp với phương thức FIND() thì chỉ cần 1 vòng lặp để duyệt mệnh đề cần mã hóa; Các bạn có thể thử thêm xem sao?
Lúc ra cái đề ở bài #1, bạn đã hơi chủ quan.
Bạn không hề cho biết 2 cái bảng A và B nó ở dạng nào. Phải đọc đến bài #6 người ta mới đoán rằng nó là hai bản dữ liệu nằm trong một bảng tính - và chỉ đoán thôi chứ vẫn chưa có gì xác định.

Chú thích: theo tôi thì bài này chủ yếu về làm vệc với kiểu dữ liệu chuỗi. Duyệt chuỗi thì phải có căn bản vòng lặp. Thế thôi.
 
Lần chỉnh sửa cuối:
Upvote 0
Đúng là đề bài ở #1 chưa rõ ràng & có lời xin lỗi về điều này đến cộng đồng!
Đến thời điểm này cả hai lời giải đều thỏa mãn với đề ra.
Rất mong các anh chị khác tiếp tục có những bài giải khác hơn!

Các bạn cũng có thể viết 1 macro để giải mã mệnh đề đã được mã hóa
Cũng có thể các bạn đề ra 1 khóa mật mã khác & mã hóa câu mà đề bài đưa ra với 2 khóa mật mã.
Chúc các bạn vui & hào hứng trong công việc!
 
Upvote 0
Đúng là đề bài ở #1 chưa rõ ràng & có lời xin lỗi về điều này đến cộng đồng!
Đến thời điểm này cả hai lời giải đều thỏa mãn với đề ra.
Rất mong các anh chị khác tiếp tục có những bài giải khác hơn!

Các bạn cũng có thể viết 1 macro để giải mã mệnh đề đã được mã hóa
Cũng có thể các bạn đề ra 1 khóa mật mã khác & mã hóa câu mà đề bài đưa ra với 2 khóa mật mã.
Chúc các bạn vui & hào hứng trong công việc!
Code theo hướng dẫn của Bác với file của bài #4
Mã:
Sub MAHOA()
Dim k As Long
Dim Str As String, col As Long, rol As Long
Dim chuoiindex As String

With Sheet1
Str = .Range("P1").Value
For k = 1 To Len(Str)
    If Mid(Str, k, 1) = " " Then
        chuoiindex = chuoiindex & " "
    Else
        col = .Range("A1:F6").Find(What:=Mid(Str, k, 1), MatchCase:=True).Column
        rol = .Range("A1:F6").Find(What:=Mid(Str, k, 1), MatchCase:=True).row
        chuoiindex = chuoiindex & .Cells(rol, col + 8).Value
    End If
Next k
.Range("P2").Value = chuoiindex
End With
End Sub
 
Upvote 0
Đúng vậy. Thay đổi từng ký tự một là trường hợp kinh điển để sử dụng hàm MID.

Code theo hướng dẫn của Bác với file của bài #4
Mã:
Sub MAHOA()
Dim k As Long
Dim Str As String, col As Long, rol As Long
Dim chuoiindex As String

With Sheet1
Str = .Range("P1").Value
For k = 1 To Len(Str)
    If Mid(Str, k, 1) = " " Then
        chuoiindex = chuoiindex & " "
    Else
        col = .Range("A1:F6").Find(What:=Mid(Str, k, 1), MatchCase:=True).Column
        rol = .Range("A1:F6").Find(What:=Mid(Str, k, 1), MatchCase:=True).row
        chuoiindex = chuoiindex & .Cells(rol, col + 8).Value
    End If
Next k
.Range("P2").Value = chuoiindex
End With
End Sub
Code này còn lủng củng lắm.
vòng lặp làm việc Len(Str) lần. Mỗi lần thì bạn lại phải gọi cái hàm tính Range("A1:F6") ra 2 lần.
Nếu đặt Set rgN = .Range("A1:F6") từ đầu thì cứ từ đó mà làm, khỏi phải tính lại.
Và chỉ cần dùng hàm Find 1 lần, set 1 object range. Bên tra thì dùng hàm Offset
Set match = rgN.Find(What:=Mid(Str, k, 1), MatchCase:=True)
chuoiindex = chuoiindex & match.Offset(0, 8).Value
Hoặc như vầy luôn cho nó nguy hiểm:
chuoiindex = chuoiindex & rgN.Find(What:=Mid(Str, k, 1), MatchCase:=True).Offset(0, 8).Value
 
Lần chỉnh sửa cuối:
Upvote 0
Rất cảm ơn bạn vì lời giải!
Mã:
        col = .Range("A1:F6").Find(What:=Mid(Str, k, 1), MatchCase:=True).Column
        rol = .Range("A1:F6").Find(What:=Mid(Str, k, 1), MatchCase:=True).row
Đây là các dòng lệnh xác định 1 kí tự trong chuỗi cần mã hóa có trong bản N (bên trái) nằm ở cột & hàng nào.
Nhưng lỡ kí tự đó không có trong bảng N ( ví dụ " ", ":",. . . ) thì sao đây?
Nên chăng ta khai báo thêm 1 biến đối tượng để lưu kết quả công cuộc tìm kiếm này?
Khi đó nếu tìm không thấy thì thêm nó vô chuỗi mã hóa(!)
 
Upvote 0
...Nhưng lỡ kí tự đó không có trong bảng N ( ví dụ " ", ":",. . . ) thì sao đây?
Nên chăng ta khai báo thêm 1 biến đối tượng để lưu kết quả công cuộc tìm kiếm này?
Khi đó nếu tìm không thấy thì thêm nó vô chuỗi mã hóa(!)
Thêm bằng cách nào? Lúc giải mã thì dựa vào đâu để giải?
Cách dễ hơn hết là nếu không tìm thấy thì để yên. Và vì vậy, phải thêm phần nếu không tìm thấy thì xét bên bảng mã. Nếu bên bảng mã có thì hỏng bét, không mã hoá được.

Nhưng rốt lại, đây là bài tập về vòng lặp, cứ giữ nó thế đi.
Việc rắc rối của mã hoá tính ở chỗ khác.
Điểm quan trọng hơn là độ chuẩn của hai bảng mã. Ở bài #5 tôi có nói "đây là phép áp 1-1 giữa hai tập hợp". Và phép áp này phải có tính chất nghịch đảo được (mã hoá 1 ký tự sang 1 ký tự, và giải mã cũng 1 ra 1). Điều kiện quan trọng của phép áp nghịch đảo được là phần tử không có trùng lặp.
 
Upvote 0
Bảng N & bảng M là quan hệ với nhau 1-1; Như vậy những ký tự ngoại lai sẽ được giữ nguyện cả khi mã hóa hay giải mã mà anh.
Ý mình muốn nói là
PHP:
If Mid(Str, k, 1) = " " Then
        chuoiindex = chuoiindex & " "  '?    '
    Else
    . . . . . .
    End If
là quá chắc cú & có thể viết cách khác được chăng?
 
Upvote 0
BÀI 01: MÃ HÓA 1 ĐOẠN VĂN BẢN​

ABCDEFTS4BIQTOI YEU GIAI PHAP EXCEL TU 2006
GHIJKLRA5CJV
MNOPQRU06DKW?
STUVWXO17ELX
YZ0123N28FMY
456789G39HPZ
NM
Ta có bảng N với 36 ký tự & ký số được sắp xếp theo 1 trật tự qui ước





& bảng M cũng những kí tự & ký số đó ta bố trí theo mật mã có chìa khóa là 'TRUONG SA'

Đề bài yêu cầu chúng ta mã hòa câu "TOI YEU GIAI PHAP EXCEL TU 2006"

Xin lưu ý: Đề bài chỉ dành ch những lập trình viên VBA trình độ sơ cấp
Rất mong nhận được nhiều ý kiến & lời giải

[Gọi ý lần 1] (Sau 3 giờ): 'YEU' => 'NI7'
Code không lấy dữ liệu trên Range
Mã:
Option Explicit
Function MaHoa(ByVal iStr$, ByVal iCode$, ByVal sRow&) As String
  Dim abc$, def$, BangMa$, j&

  abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  def = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  iStr = UCase(iStr)
  BangMa = TronMa(def, UCase(Replace(iCode, " ", "", 1)), sRow) & " "
  abc = abc & " "
  For j = 1 To Len(iStr)
    Mid(iStr, j, 1) = Mid(BangMa, InStr(1, abc, Mid(iStr, j, 1)), 1)
  Next j
  MaHoa = iStr
End Function

Function GiaiMa(ByVal iStr$, ByVal iCode$, ByVal sRow&) As String
  Dim abc$, def$, BangMa$, j&

  abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  def = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  iStr = UCase(iStr)
  BangMa = TronMa(def, UCase(Replace(iCode, " ", "", 1)), sRow) & " "
  abc = abc & " "
  For j = 1 To Len(iStr)
    Mid(iStr, j, 1) = Mid(abc, InStr(1, BangMa, Mid(iStr, j, 1)), 1)
  Next j
  GiaiMa = iStr
End Function

Private Function TronMa(ByVal def$, ByVal iCode$, ByVal sRow&) As String
  Dim Res$, sCol&, j&, jC&, q&, n&

  q = Len(def)
  sCol = (q - 1) \ sRow + 1
  def = iCode & def
  For j = 1 To Len(iCode)
    def = Mid(def, 1, j) & Replace(Mid(def, j + 1, Len(def)), Mid(iCode, j, 1), "")
  Next j
  Res = def
  n = sCol * sRow - 1
  For j = 0 To n
    If j < q Then
      If j Mod sCol = 0 Then jC = j \ sCol + 1 Else jC = jC + sRow
      If jC <= q Then Mid(Res, j + 1, 1) = Mid(def, jC, 1)
    End If
  Next j
  TronMa = Res
End Function
Công thức trên bảng tính
=MaHoa("TOI YEU GIAI PHAP EXCEL VBA","TRUONG SA",6)
=GiaiMa("165 NI7 R5T5 DATD IX4IV EST","TRUONG SA",6)
số 6 là số dòng của bảng chuyển mã
Thật ra gộp 2 Function thánh 1 sẽ gọn hơn
 
Upvote 0
Rất cảm ơn bạn vì lời giải!

Đây là các dòng lệnh xác định 1 kí tự trong chuỗi cần mã hóa có trong bản N (bên trái) nằm ở cột & hàng nào.
Nhưng lỡ kí tự đó không có trong bảng N ( ví dụ " ", ":",. . . ) thì sao đây?
Nên chăng ta khai báo thêm 1 biến đối tượng để lưu kết quả công cuộc tìm kiếm này?
Khi đó nếu tìm không thấy thì thêm nó vô chuỗi mã hóa(!)
Xin được gửi lại bài theo hướng dẫn của Bác
Mã:
Sub MAHOA()
Dim k As Long, Lr As Long
Dim Str As String
Dim chuoiindex As String, bangma As String, Arr As Range, Rng As Range

With Sheet1
Str = .Range("P1").Value
Lr = .Range("A1000").End(xlUp).row
Set Arr = .Range("A2:F" & Lr + 1)
With WorksheetFunction
    bangma = .TextJoin("", True, Arr)
End With

For k = 1 To Len(Str)
    
    If Mid(Str, k, 1) = " " Then
        chuoiindex = chuoiindex & " "
    Else
        If InStr(bangma, Mid(Str, k, 1)) = 0 Then
            For Each Rng In Arr
                If Rng.Value = "" Then
                    Rng = Mid(Str, k, 1)
                    Rng.Offset(, 8) = InputBox("ky tu: " & Mid(Str, k, 1) & " da duoc tu dong them vao bang N " & Chr(10) & "Vui long nhap ma chuyen doi cho bang M: ", "GPE")
                    Exit For
                End If
            Next Rng
        End If
        chuoiindex = chuoiindex & Arr.Find(What:=Mid(Str, k, 1), MatchCase:=True).Offset(, 8).Value
    End If
Next k
.Range("P2").Value = chuoiindex
End With
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Bảng N & bảng M là quan hệ với nhau 1-1; Như vậy những ký tự ngoại lai sẽ được giữ nguyện cả khi mã hóa hay giải mã mà anh.
Ý mình muốn nói là
PHP:
If Mid(Str, k, 1) = " " Then
        chuoiindex = chuoiindex & " "  '?    '
    Else
    . . . . . .
    End If
là quá chắc cú & có thể viết cách khác được chăng?
Function mã hóa và giải mã, tịnh tiến cột chuyển mã sẽ khó dò ký tự để giải mã, các ký tự chưa khai báo sẽ giữ nguyên
Mã:
Option Explicit
Function MaHoa(ByVal iStr$, ByVal iCode$, ByVal sRow&, Optional bGiaiMa As Boolean = False) As String
  Dim abc$, def$, BangMa$, iChar$, j&, n&, jC&

  abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  iStr = UCase(iStr)
  BangMa = TronMa(abc, UCase(Replace(iCode, " ", "", 1)), sRow)
  n = Len(iStr)
  For j = 1 To n
    iChar = Mid(iStr, j, 1)
    If InStr(1, abc, Mid(iStr, j, 1)) Then
      If bGiaiMa = False Then
        jC = (InStr(1, abc, Mid(iStr, j, 1)) + j) Mod n + 1
        Mid(iStr, j, 1) = Mid(BangMa, jC, 1)
      Else
        jC = (InStr(1, BangMa, Mid(iStr, j, 1)) - j - 2) Mod n + 1
        If jC < 1 Then jC = n + jC
        Mid(iStr, j, 1) = Mid(abc, Abs(jC), 1)
      End If
    End If
  Next j
  MaHoa = iStr
End Function

Private Function TronMa(ByVal def$, ByVal iCode$, ByVal sRow&) As String
  Dim Res$, sCol&, j&, jC&, q&, k&
 
  q = Len(def)
  sCol = (q - 1) \ sRow + 1
  def = iCode & def
  For j = 1 To Len(iCode)
    def = Mid(def, 1, j) & Replace(Mid(def, j + 1, Len(def)), Mid(iCode, j, 1), "")
  Next j
  Res = def
  jC = 1 - sRow: k = 1
  For j = 1 To q
    If jC + sRow > q Then
      k = k + 1
      jC = k
    Else
      jC = jC + sRow
    End If
    Mid(Res, j, 1) = Mid(def, jC, 1)
  Next j
  TronMa = Res
End Function
Cách dùng trong file
 

File đính kèm

Upvote 0
Thay vì phải sử dụng ví dụ mã hóa chuỗi cho vòng lặp cơ bản ta có thể tham khảo một số code dưới đây:

Một số ví dụ về vòng lặp:
1. Lặp sử dụng Step:
PHP:
For I = 1 to 10 Step 2
   Debug.Print I
Next
2. Lặp sử dụng phương pháp thêm bớt giá trị:
PHP:
For I = 1 to 10 Step 1
   Debug.Print I
   I = I + 1
Next
For J = 10 to 1 Step -1
   Debug.Print J
   J = J - 1
Next
3. "Nhảy" trong Vòng Lặp lòng một Vòng Lặp sử dụng Goto:
PHP:
For I = 1 to 10
   For J = 1 to 10
      If J = 7 Then Goto LockCondition
   Next J
   If False Then
LockCondition:
     J = J + 3
   End If
Next I
4. "Nhảy" trong Vòng Lặp lòng một Vòng Lặp sử dụng Gosub:
PHP:
Sub Exam_00A()
For I = 1 to 10
   For J = 1 to 10
      If J = 7 Then Gosub LockCondition: Exit For
   Next J
Next I
Exit Sub
LockCondition:
   J = J + 3
Return
End Sub

5. Vòng lặp Biến I nằm trong Vòng lặp của Biến I:
PHP:
Sub Exam_00B()
  Dim I&
  For I = 1 To 100
    GoSub NewI
    Debug.Print I
  Next I
  Exit Sub
NewI:
  For I = I To I + 1
    If 100 Mod I = 2 Then Exit For
  Next I
Return
End Sub

Tất cả các phương thức Vòng lặp trong VBA:
PHP:
Sub basic_loop_For()
'For...Next()'
Dim I As Long
For I = 0 To 1

Next I
'For Each...Next()'
Dim Ia:
For Each Ia In Array(1, 2, 3)
  Exit For
Next Ia
'Do ... Loop  ----> Endless Loop - sTop by Exit Do'
Do
  DoEvents
  If True Then Exit Do
Loop
I = 1
Do While I < 5 '(Loop If True <> Exit If False)'
  I = I + 1
  Debug.Print "Do While", I
Loop
I = 1
Do
  I = I + 1
  Debug.Print "Loop While", I
Loop While I < 5 '(Loop If True <> Exit If False)'
I = 0
Do Until I > 5 '(Loop If False <> Exit If True)'
  I = I + 1
  Debug.Print "Do Until", I
Loop
I = 0
Do
  I = I + 1
  Debug.Print "Loop Until", I
Loop Until I > 5 '(Loop If False <> Exit If True)'
'While ... Wend  -----> sTop by Condition False'
I = 0
While I <= 10
  Debug.Print "While Wend", I
  I = I + 1
Wend
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Cách truyền đạt của bạn là rất bài bản & thường được coi là thời thượng;
Còn cách của mình làm cho đối tương thích thú, hứng khỏi trước & chủ yếu sẽ phải tự học sau này các món truyền thống đó thôi!
Rất cám ơn bạn nhiều vì những bài viết rất bổ ích trong loạt bài đăng này!
 
Upvote 0
Vì đây chỉ là "bài tập" cho nên tôi không muốn đi sâu gì nhiều.

Muốn nói về lý thuyết vòng lặp thì khá dài, vì đầu tiên là phải phân loại:
1. Loại vòng lặp xác định vật thể để đếm hoặc để duyệt (vòng lặp For-Next)
2. Loại vòng lặp không xác định, chủ yếu là để lặp lại một đoạn code (vòng lặp Do-Loop [while/until], While-Wend]

1. Loại xác định thì chia ra hai loại là loại For biến=[Trị Đầu] To [Trị Cuối] (*) và loại For Each [variant] In [Collection]
(a) Loại For Each là ngôn ngữ tương đối mới cho nên khá chuẩn.
(b) Loại For biến = ... To ...là loại cổ điển, đây là loại cần đào sâu thêm về tính chất, bởi vì mỗi ngôn ngữ có thể theo tiêu chuẩn khác nhau.
Điều này tôi đã đề cập vài lần trong các thớt liên quan đến sử dụng vòng lập cấp cao.

2. Loại Do-Loop [While/Until (biểu thức điều kiện)] là kinh điển lý thuyết vòng lặp thô. Nó tự giải thích (**)

Chú thích:
(*) For biến=[Trị Đầu] To [Trị Cuối] nó có kỹ thuật cao về biến.

(**) cần để ý là kiểu code sau đây bảo đảm vòng lặp chạy ít nhất 1 lần. Các kiểu khác chưa chắc bảo đảm.
Do
(code ở đây)
Loop While/Until (điều kiện)

(***) While/Until : chỉ là điều kiện nghịch nhau. Cùng mọt trị biểu thức điều kiện. Dùng cái nào tuỳ theo tình trạng điều kiện nào đọc dễ hiểu hơn.

(****) While-Wend là loại code cổ lắm rồi. Không cần biết tới nữa. Những gì While-Wend làm được Do While-Loop đều làm được và nhiều hơn.

(*****) có kiểu lặp code cổ hơn một bậc. Đó là kiểu dùng goto để vòng ngược lại một label đã được cho trước. Cũng như While-Wend những gì nó làm được Do-Loop While đều làm được và nhiều hơn.
Label: code BASIC đời mới lập không có label, và mỗi câu lệnh phải được xác định bằng một con số dòng, ngừoi ta dùng số dòng này để Goto
 
Upvote 0
*Nhân tiện vô đây viết bài mới, chúc mừng Bác SA_DQ, bài viết đã được vào "hiệu sách".

Hôm trước đăng bài lại quên những cơ chế vòng lặp khác, hôm nay xin củng cố thêm kiến thức về vòng lặp không sử dụng For, Do, While.
Các bạn có thể xem lại bài trước tại đây

I. Vòng lặp sử dụng GoTo:
*Điều quan trọng với GoTo kết hợp GoSub: Thuộc cấp lập trình "Siêu cao", khó bị đánh cắp mã.

Vì sao vậy? Đơn giản là vì cấu trúc GoTo và GoSub quá khó để đọc, nếu có đến hàng 100 nhánh đi kèm thuật toán ma trận rẽ nhánh.

1. Gợi nhớ lại kiến thức về GoTo: GoTo là một phương thức rẽ nhánh vô điều kiện. Sử dụng GoTo sẽ đi đến một phân nhánh trong cùng một thủ tục được khai báo ở đầu dòng là một số nguyên hoặc một khai báo như tên biến kèm dấu hai chấm ":" , và GoTo không thể đi từ ngoài vào trong nhánh một thủ tục Con (Thủ tục con GoSub là gì? ở cuối bài).
Cấu trúc:
+ GoTo <đích >
+ On <biểu thức > GoTo <đích>


PHP:
Sub VongLap_GoTo()
    Dim K%:
    K = 1
    'On K GoTo 2
    'On K GoTo 1, 2, 3, 4, Goto2
    GoTo 1
Goto1: K = K + 1
1  K = K + 1
2  K = K + 1
3  K = K + 1
4  K = K + 1
Goto2: K = K + 1
Debug.Print K
End Sub

2. Vòng lặp sử dụng GoTo

PHP:
Sub VongLap_GoTo()
  Dim K%
Lap1:
  K = K + 1
  If K > 10 Then GoTo Lap2
GoTo Lap1
Lap2:
  K = K + 1
  If K > 20 Then GoTo Lap3
GoTo Lap2
Lap3:
  If K > 30 Then GoTo Het
GoTo Lap3
Het:
End Sub


II. Vòng lặp do Lỗi:

PHP:
Sub VongLap_GoTo_Error()
  Dim K%, N, I
  N = -10
On Error GoTo Lap1
  I = -N / K
Exit Sub
Lap1:
  N = N + 1
  K = IIf(N < 0, 0, N)
  Debug.Print N
  Err.Clear
  Resume
End Sub

====================================



====================================

*Thủ tục con: Gồm 1 hoặc nhiều khai báo như tên biến kèm dấu hai chấm ":" nằm ở đầu dòng Code,miễn sao kết thúc khối lệnh này là return. Tất cả các Thủ tục con luôn luôn nằm trong một thủ tục và nằm sau một Khai báo kết thúc Thủ tục chính (Như Exit Sub , Exit Function, ...).
GoTo Chỉ có thể rẽ nhánh từ trong rẽ trong nhánh hoặc ra ngoài Nhánh GoSub. GoTo không thể từ ngoài rẽ vào nhánh GoSub.

Cấu trúc:
+ GoSub <đích >
+ On <biểu thức > GoSub <đích>

Ví dụ:
PHP:
Sub VongLap_GoTo()
   Dim K%
    GoSub SubConLaDay1
    GoSub SubConLaDay2
    GoSub SubConLaDay3

    GoTo GoToODaySeDuoc
Exit Sub
SubConLaDay1:
    GoTo SubConLaDay3
SubConLaDay2:
SubConLaDay3:
  K = K + 1
  Debug.Rpint K
  If True Then Return
Return
GoToODaySeDuoc:

End Sub

Tags: vòng lặp goto, gosub, resume next, on error
 
Lần chỉnh sửa cuối:
Upvote 0
Dân lập trình "siêu cao" thì chỉ muốn trao đổi chứ đâu lại muốn "khó bị đánh cắp mã"? Chả nhẽ "siêu cao" đi đôi với "siêu ích kỷ"?
Viết code khó đọc đồng thời cũng có nghĩa là đi trái với đường lối "reusable code" (code viết một lần, dùng nhiều lần)

Từ thuở biết nói chuyện lập trình đến nay, mình chỉ nghe nói "viết sao cho dễ đọc". Đây là lần đầu tiên được mở mắt với chính sách "viết cho khó đọc".
 
Upvote 0
Trước đây được biết về vòng lặp không thấy nói đến vòng lặp goto hay là go...
Nếu goto cũng gọi là vòng lặp thì đệ quy có thể gọi là 1 kiểu vòng lặp?
 
Upvote 0
Dân lập trình "siêu cao" thì chỉ muốn trao đổi chứ đâu lại muốn "khó bị đánh cắp mã"? Chả nhẽ "siêu cao" đi đôi với "siêu ích kỷ"?
Viết code khó đọc đồng thời cũng có nghĩa là đi trái với đường lối "reusable code" (code viết một lần, dùng nhiều lần)

Từ thuở biết nói chuyện lập trình đến nay, mình chỉ nghe nói "viết sao cho dễ đọc". Đây là lần đầu tiên được mở mắt với chính sách "viết cho khó đọc".
Bài viết đâu có đoạn "khuyến khích các bạn nên siêu ích kỷ"
 
Upvote 0
Dân lập trình "siêu cao" thì chỉ muốn trao đổi chứ đâu lại muốn "khó bị đánh cắp mã"? Chả nhẽ "siêu cao" đi đôi với "siêu ích kỷ"?
Viết code khó đọc đồng thời cũng có nghĩa là đi trái với đường lối "reusable code" (code viết một lần, dùng nhiều lần)

Từ thuở biết nói chuyện lập trình đến nay, mình chỉ nghe nói "viết sao cho dễ đọc". Đây là lần đầu tiên được mở mắt với chính sách "viết cho khó đọc".
Dùng vòng lặp hay viết code cho dễ đọc chỉ dành cho các đối tượng "hạng xoàng" như anh Vetmini thôi. Cấp độ "siêu cao" ưu việt hơn nhiều, tư duy và cách viết code phải khác biệt giữa đám đông. Anh Vetmini nên cố gắng tiếp thu và học tập tư duy "vòng lặp siêu cấp" để tiệm cận được cấp độ "siêu cao" nhé.
 
Upvote 0
Trước đây được biết về vòng lặp không thấy nói đến vòng lặp goto hay là go...
Nếu goto cũng gọi là vòng lặp thì đệ quy có thể gọi là 1 kiểu vòng lặp?
Goto là một hình thức để thực hiện vòng lặp không có cấu trúc.
Định nghĩa cấu trúc trong ngữ cảnh vòng lặp:
Loại vòng lặp có cấu trúc được ngôn ngữ quy định cho nên chúng cũng có sự chặt chẽ của chúng. Điển hình là giới hạn (boundary) và phạm vi (scope) vòng lặp được xác định rõ rệt. Giới hạn: vòng lặp có đầu và đuôi (điển hình đầu For, đuôi Next), ở giữa là một nhóm code (block). Phạm vi: hai vòng lặp chỉ có thể chứa nhau chứ không thể móc vào nhau. Chính trình dịch sẽ kiểm soát hai luật này, không cho vi phạm.
Loại vòng lặp không cấu trúc hoàn toàn không có sự kiểm soát của trình dịch. Muốn mấy đầu mấy đuôi đều chả ai cản được. Muốn vòng chỗ nào thì vòng. Muốn móc chỗ nào thì móc.

Tuy nhiên, GoSub mà bảo làm vòng lặp thì gượng ép quá. GoSub là một lệnh cổ, thời ngôn ngữ chưa được cấu trúc hoá. Người ta bây giờ chỉ dùng nó làm một xảo thuật để lặp lại một nhóm code (lưu ý là từ "lặp" thì đúng, nhưng "vòng" thì gượng ép).
Nhiều người vẫn thích dùng GoSub vì có hai lý do:
1. cái "sub" mà GoSub nhảy vào vẫn còn nằm trọn trong Sub mẹ cho nên chia sẻ cùng tầm vực biến với Sub mẹ. Như vậy khỏi mất công truyền tham số mà vẫn tránh không phải dùng biến toàn cục. Lưu ý là cũng như biến toàn cục, được cái lợi chia biến thì cũng mang cái hại là khó kiểm soát biến.
2. khi GoSub thì VBA chỉ phải chép địa chỉ "Return" vào stack, không phải làm mấy thủ tục khác như khi Call cho nên GoSub nhanh hơn Call.

Kết luận: Goto và GoSub là loại lệnh nhảy của code mỳ Ý (gú gô từ khoá spaghetti code). Trường phái chung chung viết code có cấu trúc không dùng.
Người dùng hai lệnh Goto/GoSub này thuộc về hai hạng:
a. viết code cẩu thả, không nắm vững cấu trúc.
b. viết code rất giỏi (vì vậy mới có cái chuyện tự phong "siêu cao" [sic] ở trên), và không màng tới cấu trúc. Tuy nhiên, họ tự có một số quy luật riêng để theo. Không có số quy luật này thì chắc chắn sẽ bị:
i) không kiểm soát được biến, không kiểm soát được các đường rẽ nhánh.
ii) vài tháng sau, đọc lại code sẽ chẳng hiểu mình viết gì.

Dùng vòng lặp hay viết code cho dễ đọc chỉ dành cho các đối tượng "hạng xoàng" như anh Vetmini thôi. Cấp độ "siêu cao" ưu việt hơn nhiều, tư duy và cách viết code phải khác biệt giữa đám đông. Anh Vetmini nên cố gắng tiếp thu và học tập tư duy "vòng lặp siêu cấp" để tiệm cận được cấp độ "siêu cao" nhé.
Ở môi trường tôi, người ta tính tiền công theo các Tiêu Chí Vận Hành (Functional Benchmarks) của code. Code "viết cho khó đọc" thì bên nghiệm thu họ lấy gì nghiệm thu mà trả tiền?
Chuyện code bị đánh cắp là chuyện của bên nhận code. Mấy chục năm làm việc với họ, tôi chưa hề nhận một hợp đồng nào có tiêu chí "code khó bị đánh cắp".
Chức vị "siêu cao" nhường cho mấy người muốn ngồi trên bục thờ đi. Tôi còn trần tục lắm, vẫn cần cơm ăn áo mặc.
Thực ra lúc về sau này tôi làm bên nghiệm thu nhiều hơn bên viết code. Code viết không chú thích đầy đủ là tôi xổ toẹt. Mấy thằng lập trình đống code bên Xi Lợt Lợt hoặc Ê Ét Em thì chỉ làm khổ xếp chúng (thằng Xi Nho) thôi. Tôi bắt thằng trưởng nhóm phải viết lại cái pseudo-code, và bảo đảm là code bên trong thực sự như vậy trước khi nghiệm thu.
 
Upvote 0
Trước đây được biết về vòng lặp không thấy nói đến vòng lặp goto hay là go...
Nếu goto cũng gọi là vòng lặp thì đệ quy có thể gọi là 1 kiểu vòng lặp?
Nếu tư duy của bạn cao hơn bạn sẽ hiểu "lặp là gì".
Goto có thể lặp vô tận tương tự vòng Do, bởi vì goto là phương thức rẻ nhánh vô điều kiện, vòng for kết thúc ở giá trị cuối cùng, vòng while kết thúc ở giá trị false.
Goto , for, do, while đều gửi vào vùng nhớ tương tự nhau, nhưng for , do, while, có điều kiện để nhảy ra khỏi vùng nhớ đó. Trong khi Goto có thể đi đến bất kì vùng nhớ nào trong một Block không khóa. Còn bạn nghe theo Bác Vietmicritiki kia thì bạn theo bác ấy. Còn tôi chỉ mang cái biết của tôi trao cho người đọc. Còn chuyện phản bát chỉ là cái "tôi có mục đích".
 
Upvote 0
nói chung cách hoạt động của mấy ngôn ngữ cấp cao thì cũng phải dựa vào nền tảng tập lệnh của vi xử lý , trong tập lệnh của vi xử lý muốn lặp lại 1 khối lệnh chỉ có hàm jump thoai , chắc đó là lý do mấy ngôn ngữ cấp cao giữ lại lệnh này , đệ quy cũng là cách lặp lại , tập lệnh vi xử lý có hỗ trợ , nhưng nó không lặp lại 1 khối lệnh , mà gọi ra 1 khối lệnh khác , nên nếu gọi nhiều quá sẽ tràn bộ đệm !
 
Upvote 0
Nếu tư duy của bạn cao hơn bạn sẽ hiểu "lặp là gì".
Goto có thể lặp vô tận tương tự vòng Do, bởi vì goto là phương thức rẻ nhánh vô điều kiện, vòng for kết thúc ở giá trị cuối cùng, vòng while kết thúc ở giá trị false.
Goto , for, do, while đều gửi vào vùng nhớ tương tự nhau, nhưng for , do, while, có điều kiện để nhảy ra khỏi vùng nhớ đó. Trong khi Goto có thể đi đến bất kì vùng nhớ nào trong một Block không khóa. Còn bạn nghe theo Bác Vietmicritiki kia thì bạn theo bác ấy. Còn tôi chỉ mang cái biết của tôi trao cho người đọc. Còn chuyện phản bát chỉ là cái "tôi có mục đích".
Tôi có chính kiến của mình, bạn nghĩ thế nào thì tùy, không quan trọng.
Việc tham gia viết bài vào thớt này là để trao đổi kiến thức, không khẳng định tôi ta gì hết bạn.

"Nếu tư duy của bạn cao hơn bạn sẽ hiểu "lặp là gì". Về điều này thì tôi thấy tư duy của bạn tốt đấy, cứ dùng go... mà "lặp" nhé.
 
Upvote 0
Nếu tư duy của bạn cao hơn bạn sẽ hiểu "lặp là gì".
Goto có thể lặp vô tận tương tự vòng Do, bởi vì goto là phương thức rẻ nhánh vô điều kiện, vòng for kết thúc ở giá trị cuối cùng, vòng while kết thúc ở giá trị false.
Goto , for, do, while đều gửi vào vùng nhớ tương tự nhau, nhưng for , do, while, có điều kiện để nhảy ra khỏi vùng nhớ đó. Trong khi Goto có thể đi đến bất kì vùng nhớ nào trong một Block không khóa. Còn bạn nghe theo Bác Vietmicritiki kia thì bạn theo bác ấy. Còn tôi chỉ mang cái biết của tôi trao cho người đọc. Còn chuyện phản bát chỉ là cái "tôi có mục đích".
Nhờ bạn tư duy xem đây có được gọi là lặp?
Chẳng có go, chẳng có for next, do...loop...
Mã:
Dim i
Sub VLap1(i)
If i = 0 Then
    i = 1
Else
    i = 0
End If
VLap2 (i)
End Sub
Sub VLap2(i)
If i = 0 Then
    i = 1
Else
    i = 0
End If
VLap1 (i)
End Sub
Sub A()
Call VLap1(i)
End Sub
 
Upvote 0
Nhờ bạn tư duy xem đây có được gọi là lặp?
Chẳng có go, chẳng có for next, do...loop...
Mã:
Dim i
Sub VLap1(i)
If i = 0 Then
    i = 1
Else
    i = 0
End If
VLap2 (i)
End Sub
Sub VLap2(i)
If i = 0 Then
    i = 1
Else
    i = 0
End If
VLap1 (i)
End Sub
Sub A()
Call VLap1(i)
End Sub
"Go lặp", tôi có đăng duy nhất một bài Go lặp. "Phí lời". Đệ quy suy ra "lặp" phí lời.
 
Upvote 0
Đã nói từ bài GoTo chuyển nhánh vô điều kiện tạo nên cơ chế lặp vô điều kiện, mà bác Vietmicritini bày "đủ trò". Toàn "ngồi không phách đốc". Tôi gọi bác "Vietmicritini" là ẩn ý của chính tôi, thực ra chẳng tồn tại. Bác chẳng hiểu cái câu khởi đầu của người ta viết, bác chẳng hiểu cái gọi là truyền kiến thức, chỉ mang cái nhỏ lẻ không tương xứng ra mò mẩm, giống như nồi cơm chỉ có một phần cơm cháy mà đem ra phân tích giống như Nhà khoa học xuất hiện như đấng cứu thế. Thực ra chỉ là "kẻ phá hoại".
"Vietmicritini - kẻ rên khóc"
 
Lần chỉnh sửa cuối:
Upvote 0
nói chung cách hoạt động của mấy ngôn ngữ cấp cao thì cũng phải dựa vào nền tảng tập lệnh của vi xử lý , trong tập lệnh của vi xử lý muốn lặp lại 1 khối lệnh chỉ có hàm jump thoai , chắc đó là lý do mấy ngôn ngữ cấp cao giữ lại lệnh này , ...
Hiểu chết liền.
Ở đây tôi đang giải thích về sự khác biệt giữa cách viết code có cấu trúc và không cấu trúc.
Khi trình dịch đọc đến từ khoá FOR thì nó biết đây là mở đầu một vòng lặp, và nó tự biết rằng đến từ khoá NEXT gần nhất thì khẳng định đó là kết vòng lặp ấy. Nếu trước khi gặp NEXT mà gặp một FOR khác thì nó tự biết là cái FOR trước phải bọc ngoài cái FOR này. Đó là có cấu trúc.
Mặt khác, khi trình dịch đọc một cái Label thì nó chỉ biết đó là một cái địa chỉ (lưu ý: không phải từ khoá). Một lúc sau, khi đọc đến từ khoá GOTO <Label> thì nó cũng chỉ biết đấy là lệnh nhảy về cái địa chỉ kia. Tuy đối với người viết code, vòng ngược trở về thì có thể coi như vòng lặp, nhưng đối với trình dịch, nó không hề quan tâm đến chuyện đó (có muốn quan tâm cũng chẳng được). Đó là vòng lặp không cấu trúc.
Tóm lại, vòng lặp có cấu trúc được trình dịch kiểm soát. Vòng lặp không cấu trúc không được trình dịch kiểm soát vì chả có cách nào để nó kiểm soát cả.
GOSUB cũng tương tự như vậy. Cái thủ tục con này không bắt buộc phải bó trọn một nhóm code trong từ khoá mở đầu và từ khoá kết thúc. GOSUB <Label> đối với trình dịch chỉ là nhảy đến cái địa chỉ Label, cộng thêm một điều kiện là khi gặp lệnh RETURN thì quay trở về tiếp tục ở lệnh kế tiếp GOSUB. Theo nguyên tắc trình dịch thì đây là hình thức thủ tục con không cấu trúc.
(Thủ tục con có cấu trúc được xác định rõ rệt tầm vực là vùng giữa từ khoá SUB và từ khoá END SUB)
 
Upvote 0
Bây giờ đến lúc đem tiếng Anh ra bày trò nữa đây.
Hồi nào giờ chỉ biết vài ngôn ngữ có kỹ thuật "name mangling", điển hình để xử lý tên hàm. Bi giờ mới thấy kỹ thuật này được đem ra dùng để khoe tiếng ngoại.
 
Lần chỉnh sửa cuối:
Upvote 0
Trong khi bài viết Bác SA_DQ đăng để học hỏi, thì toàn những "Kẻ Sĩ" đăng những bài "Xàm xí" làm cho những lớp mầm non muốn học hỏi cũng phải bị lây nhiễm "Triết lý phá hoại", thậm chí một bài viết xây dựng, đóng góp cũng không có. Cái nôi của học tập "nằm ở những kẻ này chăng". Thực là "Chân tài thực học" thì thêm bài đóng góp. Cứ "Quăng" cái bài của mình lên xem như mình là "Kẻ soi sáng văn minh nhân loại". Cứ như mình là người sáng tạo cái "Triết lí xã hội". Tài thì lấy cái tài của mình ra đóng góp. "Nhân văn" còn chưa nắm vững thì lấy đâu "cái trí đối nhân xử thế".

Đọc bài viết thì đọc thiếu trước hụt sau. Rồi phán "như thẩm phán Hollywood".
 
Lần chỉnh sửa cuối:
Upvote 0
Ở đây tôi đang giải thích về sự khác biệt giữa cách viết code có cấu trúc và không cấu trúc.
Khi trình dịch đọc đến từ khoá FOR thì nó biết đây là mở đầu một vòng lặp, và nó tự biết rằng đến từ khoá NEXT gần nhất thì khẳng định đó là kết vòng lặp ấy. Nếu trước khi gặp NEXT mà gặp một FOR khác thì nó tự biết là cái FOR trước phải bọc ngoài cái FOR này. Đó là có cấu trúc.
nói chung bác nói cũng đúng chứ không sai ^^ , với quan điểm của bác thì phân ra hai loại có cấu trúc và không cấu trúc để dễ phân biệt
nhưng cũng có quan điểm khác họ chỉ coi là các cách để lặp lại thôi, một cái gọi là không cấu trúc thì cũng phải theo 1 cấu trúc nào đó , lan man tí thì vòng lặp có cấu trúc tuy dễ hiểu nhưng bị trình biên dịch hạn chế năng lực , nên chỉ giải được 1 số dạng toán nhất định , nếu với các dạng toán vét cạn dùng đến đệ quy , thì có thể thiết kế bằng vòng lặp goto cũng tốt tương đương !
 
Upvote 0
... nếu với các dạng toán vét cạn dùng đến đệ quy , thì có thể thiết kế bằng vòng lặp goto cũng tốt tương đương !
Việc này là vấn đề khác. Nó là cách trải phẳng đệ quy phi tuyến chứ đâu có liên quan gì đến code khó bị đánh cắp. Ba cái mớ nhiều nhánh đương nhiên là khó hiểu, nếu không có chú thích thì khó mò. Chân lý là vậy.
Tôi đâu có tranh luận về "dùng hay không dùng Goto" ở đây.
Ở đây, tôi chỉ cảnh báo với quý vị cần học về vòng lặp, và tôi lặp lại rằng:
Goto là lệnh rẽ nhánh chỉ dùng khi đã tự định cho mình những luật lệ đi kèm. Không tuân thủ những luật tự kềm chế mình thì code sẽ nát bét hết.

Và ở những bài trước, tôi khuyên người học nên hỏi lại người viết code giải thích các luật lệ của mình. Không có những giải thích này thì code chỉ là loại code sao chép đem về dùng chứ chả học được gì cả. Trừ phi người học biết kỹ thuật tái cấu trúc code (refactor và reverse engineering).
 
Upvote 0
nhìn chung không phải chỉ có nghề code két này mới có việc keep job như thế , nhiều nghề khác cũng vậy thôi ,
giống như nhà em thuê thợ sửa cái máy lạnh , thợ đấu điện ngoằn ngoèo làm bác sau mệt bở hơi tai , ^^
nhưng ấy chỉ là tiểu xảo của nghề , và nếu cứ làm thế thì chỉ đạt tầm manh mún , không phát triển lên được !
nói chung em cũng đa tạ bác vì đã chia sẻ 1 tinh thần học tập và làm việc đúng đắn ^^
 
Upvote 0
Cái này như kiểu là lấy đủ tên đó rồi còn thừa ký tự nào thì bỏ sang bên canh.Mà có giải thưởng không bác Sa.

C++ góp vui tí
Mã:
#include <iostream>
#include <iostream>
#include <conio.h>
#include<cstring>
using namespace std;

const int Max = 100;
char BanRo[] = "TRUONGSA"; // Bang M
char* BanMa;
int nStr = strlen(BanRo);
int M[Max];


void ConverterNumberToChar(int kt);
void ConverterCharToNumber(char* Str);

int main()
{
   cout<<"Bang ro: "<<endl;
   cout<<BanRo<<endl;
   ConverterCharToNumber(BanRo);
   cout<<"\nBang ro dang so (Z26):"<<endl;
   for(int i = 0; i < nStr; i++)
      cout<<M[i]<<" ";
   cout<<endl;

   // Cac ham ma hoa va giai ma
   // dat o day.

   cout<<"\nChuoi ban dau la: "<<endl;
   for(i = 0; i < nStr; i++)
      ConverterNumberToChar(M[i]);
   cout<<endl;

   getch();
   return 0;
}
// Trong Z26 ta gan so cho ky tu nhu sau:
// A B C D E F G H I ... Z
// 0 1 2 3 4 5 6 7 8 ... 25
void ConverterNumberToChar(int kt)
{
   char digit[26] ={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
   int i;
   i = kt%26;
   kt = kt/26;
   if(i>=26)
      cout<<digit[i%10];
   else
      cout<<digit[i];
}
void ConverterCharToNumber(char* Str)
{  
   char* Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   int StrStr = strlen(Str), StrAlphabet = strlen(Alphabet);
   for(int k = 0; k < StrStr; k++)
      for(int j = 0; j < StrAlphabet; j++)
      {
         if(BanRo[k] == Alphabet[j])
         {
            M[k] = j;break;
         }
      }
}
 
Upvote 0
Code lủng củng lắm. Thử chỉnh lại đi.
Điển hình 1:
char digit[26] ={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
làm như vầy hơi nguy hiểm vì digit bắt buộc phải là mảng, không thể coi như string vì nó không có \0 ở sau
char digit[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
sẽ được trình dịch cho thêm cái \0 ở cuối
Điển hình 2:
Hàm ConverterNumberToChar code quá sức cẩu thả
i = kt%26; ---> chắc chắn i < 26
kt = kt/26; ---> trị này tính xong chả làm gì cả
if(i>=26) ---> theo cách tính i ở trên thì chuyện này không bao giờ xảy ra
Code dùng nhiều lần "magic number" 26. Đáng lẽ phải đặt nó là const (C++), hoặc #define (C)

Gợi ý thêm:
1. C++ dùng nhiều từ khoá const hơn
2. Theo quan niệm mới bây giờ, người ta ít khi viết hàm void. Nếu hàm xử lý chuỗi thì trả về con trỏ chuỗi.
3. Code trên chỉ là C, thêm cái phần i/o của C++. Nếu thực sự là C++ thì viết quách một cái class chứa hết mọi phương thức vào mã, giải mã...
 
Lần chỉnh sửa cuối:
Upvote 0
Thay vì phải sử dụng ví dụ mã hóa chuỗi cho vòng lặp cơ bản ta có thể tham khảo một số code dưới đây:

Một số ví dụ về vòng lặp:
1. Lặp sử dụng Step:
PHP:
For I = 1 to 10 Step 2
   Debug.Print I
Next
2. Lặp sử dụng phương pháp thêm bớt giá trị:
PHP:
For I = 1 to 10 Step 1
   Debug.Print I
   I = I + 1
Next
For J = 10 to 1 Step -1
   Debug.Print J
   J = J - 1
Next
3. "Nhảy" trong Vòng Lặp lòng một Vòng Lặp sử dụng Goto:
PHP:
For I = 1 to 10
   For J = 1 to 10
      If J = 7 Then Goto LockCondition
   Next J
   If False Then
LockCondition:
     J = J + 3
   End If
Next I
4. "Nhảy" trong Vòng Lặp lòng một Vòng Lặp sử dụng Gosub:
PHP:
Sub Exam_00A()
For I = 1 to 10
   For J = 1 to 10
      If J = 7 Then Gosub LockCondition: Exit For
   Next J
Next I
Exit Sub
LockCondition:
   J = J + 3
Return
End Sub

5. Vòng lặp Biến I nằm trong Vòng lặp của Biến I:
PHP:
Sub Exam_00B()
  Dim I&
  For I = 1 To 100
    GoSub NewI
    Debug.Print I
  Next I
  Exit Sub
NewI:
  For I = I To I + 1
    If 100 Mod I = 2 Then Exit For
  Next I
Return
End Sub

Tất cả các phương thức Vòng lặp trong VBA:
PHP:
Sub basic_loop_For()
'For...Next()'
Dim I As Long
For I = 0 To 1

Next I
'For Each...Next()'
Dim Ia:
For Each Ia In Array(1, 2, 3)
  Exit For
Next Ia
'Do ... Loop  ----> Endless Loop - sTop by Exit Do'
Do
  DoEvents
  If True Then Exit Do
Loop
I = 1
Do While I < 5 '(Loop If True <> Exit If False)'
  I = I + 1
  Debug.Print "Do While", I
Loop
I = 1
Do
  I = I + 1
  Debug.Print "Loop While", I
Loop While I < 5 '(Loop If True <> Exit If False)'
I = 0
Do Until I > 5 '(Loop If False <> Exit If True)'
  I = I + 1
  Debug.Print "Do Until", I
Loop
I = 0
Do
  I = I + 1
  Debug.Print "Loop Until", I
Loop Until I > 5 '(Loop If False <> Exit If True)'
'While ... Wend  -----> sTop by Condition False'
I = 0
While I <= 10
  Debug.Print "While Wend", I
  I = I + 1
Wend
End Sub
Mã:
Do While Arr(i, 285) >= 96
                For j1 = 10 To 257 Step 8
                    If Arr(i, 285) < 96 Then
                        Exit For
                    ElseIf Arr(i, j1 + 2) > 1.5 Then
                        Arr(i, j1 + 2) = Arr(i, j1 + 2) - T1
                        Arr(i, 278) = Arr(i, 278) - 1
                        Arr(i, 285) = Arr(i, 285) - 1
                    End If
                Next j1
            Loop
Code này của em sai ở đâu mà không tài nào thoát được vòng lặp anh nhỉ?
 
Upvote 0
Mã:
Do While Arr(i, 285) >= 96
                For j1 = 10 To 257 Step 8
                    If Arr(i, 285) < 96 Then
                        Exit For
                    ElseIf Arr(i, j1 + 2) > 1.5 Then
                        Arr(i, j1 + 2) = Arr(i, j1 + 2) - T1
                        Arr(i, 278) = Arr(i, 278) - 1
                        Arr(i, 285) = Arr(i, 285) - 1
                    End If
                Next j1
            Loop
Code này của em sai ở đâu mà không tài nào thoát được vòng lặp anh nhỉ?
Không thoát được là đúng rồi vì Nó thỏa mãn điều kiện Arr(i,285) >=96.Mà ở đây giá trị của i luôn bằng giá trị khi thỏa mãn điều kiện nếu mình đoán không sai.Bạn phải làm cách nào cho biến i nó chạy chứ để thế kia nó luôn thỏa mãn điều kiện vòng lặp Do loop thì nó chẳng chạy hoài à.
 
Upvote 0
Không thoát được là đúng rồi vì Nó thỏa mãn điều kiện Arr(i,285) >=96.Mà ở đây giá trị của i luôn bằng giá trị khi thỏa mãn điều kiện nếu mình đoán không sai.Bạn phải làm cách nào cho biến i nó chạy chứ để thế kia nó luôn thỏa mãn điều kiện vòng lặp Do loop thì nó chẳng chạy hoài à.
Giá trị Arr(i, 285) có thay đổi ở dòng này:
Arr(i, 285) = Arr(i, 285) - 1
Tuy nhiên, vì dòng ấy nằm trong điều kiện:
ElseIf Arr(i, j1 + 2) > 1.5 Then
cho nên nếu Arr(i, j1 + 2) <= 1.5 trước khi Arr(i, 285) giảm xuống dưới 96 thì vòng lặp sẽ vô tận.
 
Upvote 0
Giá trị Arr(i, 285) có thay đổi ở dòng này:
Arr(i, 285) = Arr(i, 285) - 1
Tuy nhiên, vì dòng ấy nằm trong điều kiện:
ElseIf Arr(i, j1 + 2) > 1.5 Then
cho nên nếu Arr(i, j1 + 2) <= 1.5 trước khi Arr(i, 285) giảm xuống dưới 96 thì vòng lặp sẽ vô tận.
Cảm ơn hai anh để em xem lại nhé. Chúc mọi người an toàn trong mùa dịch!
 
Upvote 0

Bài viết mới nhất

Back
Top Bottom