[Powered by Google Translate] [Mục 5: LESS COMFORTABLE] [Nate hardison, Đại học Harvard] [Đây là CS50.] [CS50.TV] Vì vậy, chào đón trở lại, guys. Chào mừng bạn đến phần 5. Tại thời điểm này, đã hoàn thành bài kiểm tra 0 và sau khi nhìn thấy bạn đã thực hiện như thế nào, hy vọng bạn cảm thấy thực sự tốt bởi vì tôi đã rất ấn tượng bởi điểm số trong phần này. Cho người xem trực tuyến của chúng tôi, chúng tôi đã có một vài câu hỏi về hai vấn đề cuối cùng trên các thiết lập vấn đề - hoặc trên các bài kiểm tra, thay vì. Vì vậy, chúng ta sẽ đi qua những người thực sự nhanh chóng để mọi người thấy những gì đã xảy ra và làm thế nào để đi qua các giải pháp thực tế hơn là chỉ xem các giải pháp riêng của mình. Chúng ta sẽ đi qua vài vấn đề thực sự nhanh chóng, 32 và 33. Chỉ là, một lần nữa, vì vậy mà người xem trực tuyến có thể thấy điều này. Nếu bạn chuyển sang vấn đề của bạn 32, mà là trên trang 13, 13 trong số 16, vấn đề 32 là tất cả về giao dịch hoán đổi. Đó là tất cả về trao đổi hai số nguyên. Đó là vấn đề mà chúng tôi muốn đi qua một vài lần trong bài giảng. Và ở đây, những gì chúng tôi đã yêu cầu bạn làm một dấu vết bộ nhớ nhanh chóng. Để điền vào các giá trị của các biến như họ đang ở trên stack như là mã đi qua chức năng này trao đổi. Đặc biệt, những gì chúng tôi đang tìm kiếm tại - tôi sẽ đặt này iPad - Đặc biệt, những gì chúng tôi đang tìm kiếm ở dòng này số 6 ngay tại đây. Và nó số 6 chỉ tiếp giáp với các vấn đề trước. Những gì chúng tôi muốn làm là hiển thị hoặc nhãn trạng thái của bộ nhớ vì nó là vào thời điểm khi chúng tôi thực hiện này số dòng 6, đó là hiệu quả trở lại từ chức năng trao đổi của chúng tôi ngay tại đây. Nếu chúng ta di chuyển xuống đây, chúng tôi thấy rằng các địa chỉ của tất cả mọi thứ trong bộ nhớ đã được cung cấp cho chúng tôi. Điều này là rất quan trọng, chúng ta sẽ trở về với nó trong thời điểm này chỉ là một. Và sau đó xuống đây ở phía dưới, chúng tôi đã có một sơ đồ rất ít bộ nhớ mà chúng tôi sẽ giới thiệu cho. Tôi đã thực sự làm được điều này trên iPad của tôi. Vì vậy, tôi sẽ phải luân phiên qua lại giữa iPad và mã này chỉ để tham khảo. Hãy bắt đầu. Trước tiên, chúng ta hãy tập trung vào các cặp vợ chồng đầu tiên của dòng chính quyền ở đây. Để bắt đầu, chúng ta sẽ khởi tạo x 1 và y đến 2. Vì vậy, chúng tôi có hai biến số nguyên, họ cả hai sẽ được đặt trên stack. Chúng ta sẽ đặt một 1 và 2 trong chúng. Vì vậy, nếu tôi lật qua iPad của tôi, hy vọng, chúng ta hãy xem - Apple TV phản chiếu, và ở đó chúng tôi đi. Okay. Vì vậy, nếu tôi đưa bạn đến iPad của tôi, Tôi muốn khởi tạo x 1 và y đến 2. Chúng tôi làm điều đó khá đơn giản bằng cách viết một 1 trong hộp đánh dấu x và 2 trong hộp đánh dấu y. Khá đơn giản. Vì vậy, bây giờ chúng ta hãy quay trở lại máy tính xách tay, xem những gì sẽ xảy ra tiếp theo. Vì vậy, dòng này tiếp theo là nơi mà mọi thứ trở nên khó khăn. Chúng tôi vượt qua địa chỉ của x và địa chỉ của y là tham số a và b đến chức năng trao đổi. Địa chỉ của x và địa chỉ của y là điều mà chúng tôi không thể tính toán mà không đề cập đến những viên đạn chỉ phải xuống ở đây. Và may mắn thay, hai điểm đạn đầu tiên cho chúng tôi biết chính xác những gì các câu trả lời. Địa chỉ của x trong bộ nhớ là 10, và địa chỉ của y trong bộ nhớ là 14. Vì vậy, những giá trị mà có được thông qua tại như a và b lên hàng đầu trong chức năng trao đổi của chúng tôi. Vì vậy, một lần nữa, chuyển đổi trở lại sơ đồ của chúng tôi, tôi có thể viết 10 trong một và 14 in b. Bây giờ, thời điểm này là nơi mà chúng tôi tiến hành trao đổi. Vì vậy, lật lại cho máy tính xách tay một lần nữa, chúng ta thấy rằng cách trao đổi các công trình là lần đầu tiên tôi tới đích và lưu trữ các kết quả trong tmp. Vì vậy, các nhà điều hành dereference nói, "Hey Hãy đối xử với các nội dung của một biến như là một địa chỉ. Tới bất cứ điều gì được lưu trữ tại địa chỉ đó, và tải nó. " Những gì bạn nạp của biến sẽ được lưu trữ vào một biến tmp của chúng tôi. Lật lại iPad. Nếu chúng tôi đi để giải quyết 10, chúng ta biết rằng địa chỉ 10 là x varible bởi vì chúng tôi mới biết điểm bullet của chúng tôi là địa chỉ của x trong bộ nhớ là 10. Vì vậy, chúng ta có thể đi đến đó, nhận được giá trị của nó, mà là 1, như chúng ta thấy trên iPad của chúng tôi, và tải đó vào tmp. Một lần nữa, đây không phải là nội dung cuối cùng. Chúng ta sẽ phải đi bộ qua và chúng tôi sẽ nhận được trạng thái của chương trình cuối cùng của chúng tôi ở cuối. Nhưng ngay bây giờ, chúng tôi có giá trị 1 được lưu trữ trong tmp. Và có một câu hỏi nhanh chóng hơn ở đây. Alexander dereference điều hành - đó chỉ là quyền ngôi sao ở phía trước của biến? >>. Vì vậy, các nhà điều hành dereference, khi chúng tôi lật lại cho máy tính xách tay của chúng tôi một lần nữa, là ngôi sao này ngay trước mặt. Trong ý nghĩa đó, nó là bạn tương phản với các nhà điều hành nhân đòi hỏi hai điều, các nhà điều hành dereference là một nhà điều hành unary. Chỉ cần áp dụng một giá trị như trái ngược với một nhà điều hành nhị phân, nơi bạn áp dụng hai giá trị khác nhau. Vì vậy, đó là những gì xảy ra trong dòng này. Chúng tôi được nạp giá trị 1 và lưu trữ nó vào một biến số nguyên của chúng tôi tạm thời. Dòng tiếp theo, chúng tôi lưu trữ các nội dung của b vào - hoặc, đúng hơn, chúng tôi lưu trữ các nội dung mà b đang trỏ vào nơi được trỏ đến. Nếu chúng ta phân tích từ phải sang trái, chúng ta sẽ để b dereference, chúng ta sẽ để giải quyết 14, chúng ta sẽ lấy các số nguyên đó là có, và sau đó chúng ta sẽ đi đến địa chỉ 10, và chúng ta sẽ ném kết quả của dereference của chúng tôi của b vào không gian đó. Flipping trở lại iPad của chúng tôi, nơi chúng tôi có thể làm cho nhiều hơn một chút cụ thể, nó có thể giúp nếu tôi viết con số trên tất cả các địa chỉ ở đây. Vì vậy, chúng ta biết rằng ở y, chúng tôi tại địa chỉ 14, x là tại địa chỉ 10. Khi chúng tôi bắt đầu b, chúng tôi dereference b, chúng tôi đang đi để lấy giá trị 2. Chúng tôi sẽ lấy giá trị này bởi vì đó là giá trị sống tại địa chỉ 14. Và chúng ta sẽ phải đặt nó vào biến sống tại địa chỉ 10, mà là phải có, tương ứng với biến x của chúng tôi. Vì vậy, chúng ta có thể làm một ít ghi đè nơi mà chúng tôi nhận được thoát khỏi 1 của chúng tôi và thay vào đó chúng ta viết 2. Vì vậy, tất cả là tốt và tốt nhất trên thế giới, mặc dù chúng tôi đã x ghi đè. Chúng tôi đã được lưu trữ giá trị cũ của x trong biến tmp của chúng tôi. Vì vậy, chúng ta có thể hoàn thành việc trao đổi với các dòng tiếp theo. Lật lại để máy tính xách tay của chúng tôi. Bây giờ tất cả còn lại đó là lấy nội dung của biến số nguyên của chúng tôi tạm thời và lưu trữ chúng vào biến sống tại địa chỉ mà b đang nắm giữ. Vì vậy, chúng ta sẽ để b dereference hiệu quả để có được quyền truy cập vào biến đó là tại địa chỉ mà b nắm giữ trong nó, và chúng tôi sẽ công cụ giá trị tmp đang nắm giữ vào nó. Lật lại để iPad một lần nữa. Tôi có thể xóa giá trị này ở đây, 2, và thay vào đó chúng tôi sẽ sao chép các quyền 1 vào nó. Sau đó, các dòng tiếp theo, được thực hiện, tất nhiên - nếu chúng ta lật trở lại cho máy tính xách tay - là điểm 6, đó là điểm mà tại đó, chúng tôi muốn có sơ đồ của chúng tôi điền đầy đủ. Vì vậy, lật trở lại với iPad một lần nữa, chỉ cần như vậy bạn có thể xem sơ đồ hoàn thành, bạn có thể thấy rằng chúng tôi có 10 trong một, 14 in b, 1 trong tmp, a 2 trong x, và 1 trong y. Có bất kỳ câu hỏi nào về điều này? Điều này có ý nghĩa hơn, sau khi đã đi qua nó? Ít có ý nghĩa hơn? Hy vọng rằng không. Okay. Con trỏ là một chủ đề rất khó khăn. Một trong những kẻ chúng ta làm việc với có một câu nói rất phổ biến: "Để hiểu được con trỏ, trước tiên bạn phải hiểu con trỏ." Mà tôi nghĩ là rất đúng. Nó có phải mất một thời gian để làm quen với nó. Vẽ rất nhiều hình ảnh, bản vẽ rất nhiều sơ đồ bộ nhớ như thế này rất hữu ích, và sau khi bạn đi bộ thông qua ví dụ sau ví dụ sau ví dụ, nó sẽ bắt đầu có ý nghĩa nhiều hơn một chút và ý thức hơn một chút và một ít ý nghĩa hơn. Cuối cùng, một ngày, bạn sẽ có tất cả hoàn toàn làm chủ. Bất kỳ câu hỏi trước khi chúng ta chuyển sang vấn đề tiếp theo? Được rồi. Vì vậy, lật trở lại cho máy tính xách tay. Vấn đề tiếp theo chúng ta có là số 33 vấn đề trên tập tin I / O. Phóng to chút này một chút. Vấn đề 33 -? [Daniel] Tôi chỉ có một câu hỏi nhanh chóng. Ngôi sao này, hoặc dấu hoa thị, nó được gọi là dereferencing khi bạn sử dụng một dấu hoa thị trước. Đó là những gì được gọi là khi bạn sử dụng dấu "và" trước? >> Dấu "và" trước khi là địa chỉ của nhà điều hành. Vì vậy, hãy di chuyển trở lại. Rất tiếc. Tôi đang ở chế độ phóng to để tôi có thể không thực sự di chuyển. Nếu chúng ta nhìn vào mã này thực sự nhanh chóng ngay tại đây, một lần nữa, cùng một điều xảy ra. Nếu chúng ta nhìn vào mã này ngay tại đây, trên đường dây này, nơi chúng tôi thực hiện cuộc gọi để trao đổi, dấu và chỉ nói "có được địa chỉ mà ở đó cuộc sống của biến x." Khi trình biên dịch của bạn biên dịch mã của bạn, nó có thể chất thực sự đánh dấu một vị trí trong bộ nhớ cho tất cả các biến của bạn để sinh sống. Và vì vậy những gì các trình biên dịch sau đó có thể làm một khi nó được biên dịch tất cả mọi thứ, nó biết, "Ồ, tôi đặt x tại địa chỉ 10 tôi đặt y tại địa chỉ 14." Sau đó nó có thể điền vào các giá trị cho bạn. Vì vậy, bạn có thể sau đó - sau đó nó có thể vượt qua điều này và vượt qua & y cũng. Những anh chàng này có được địa chỉ, nhưng họ cũng có, khi bạn vượt qua chúng vào các chức năng trao đổi, loại thông tin này, int * ngay tại đây, cho trình biên dịch, "Được rồi, chúng ta sẽ được giải thích địa chỉ này như là một địa chỉ của một biến số nguyên". Như một địa chỉ của một int, mà là khác nhau từ địa chỉ của một biến ký tự bởi vì một int chiếm, trên một máy tính 32-bit, chiếm 4 byte của không gian, trong khi một nhân vật chỉ chiếm 1 byte của không gian. Vì vậy, nó là quan trọng để biết những gì là - những gì cuộc sống, những gì loại có giá trị đang sống tại địa chỉ đã thông qua nhập Hoặc địa chỉ mà bạn đang xử lý. Bằng cách đó, bạn biết có bao nhiêu byte thông tin để thực sự tải của bộ nhớ RAM của bạn. Và sau đó, có, nhà điều hành này dereference, giống như bạn đã được yêu cầu, đi và truy cập thông tin tại một địa chỉ cụ thể. Vì vậy, nó nói, với một biến ở đây, điều trị các nội dung của một như một địa chỉ, đi đến địa chỉ đó, và kéo ra, nạp vào bộ vi xử lý, tải vào đăng ký thực tế các giá trị hoặc các nội dung sống tại địa chỉ đó. Bất kỳ câu hỏi? Đây là những câu hỏi hay. Đó là rất nhiều thuật ngữ mới. Nó cũng loại của funky, nhìn thấy & và * ở những nơi khác nhau. Được rồi. Vì vậy, trở lại vấn đề 33, nộp I / O. Đây là một trong những vấn đề mà tôi nghĩ rằng một vài điều đã xảy ra. Một, nó là một chủ đề khá mới. Nó đã được trình bày khá sớm trước khi bài kiểm tra, và sau đó tôi nghĩ rằng đó là loại giống như một trong những vấn đề từ trong toán học nơi mà họ cung cấp cho bạn rất nhiều thông tin, nhưng bạn thực sự không phải sử dụng một tấn của nó. Phần đầu tiên của vấn đề này được mô tả một tập tin CSV. Bây giờ, một tập tin CSV, theo mô tả, là một giá trị được phân cách bằng dấu phẩy tập tin. Lý do đây là ở tất cả các thú vị, và lý do bạn đã bao giờ sử dụng chúng, , bởi vì, có bao nhiêu bạn đã từng sử dụng các công cụ như Excel? Hình hầu hết các bạn có, có lẽ, hoặc sẽ sử dụng tại một số điểm trong cuộc sống của bạn. Bạn sẽ sử dụng một cái gì đó giống như Excel. Để có được các dữ liệu của một bảng tính Excel hoặc làm bất kỳ loại chế biến với nó, nếu bạn muốn viết một chương trình C hoặc chương trình Python, Java chương trình, để đối phó với các số liệu đã được lưu trữ trong đó, một trong những cách phổ biến nhất để có được nó trong một tập tin CSV. Và bạn có thể mở Excel và khi bạn đi đến 'Save as' đối thoại, bạn có thể nhận ra một tập tin CSV thực tế. Tiện dụng để biết làm thế nào để đối phó với những điều này. Cách nó hoạt động là nó tương tự như - Ý tôi là, nó chủ yếu bắt chước một bảng tính, ở đâu, như chúng ta thấy ở đây, trong phần rất trái nhất, chúng tôi có tất cả các tên cuối cùng. Vì vậy, chúng tôi có Malan, sau đó hardison, và sau đó Bowden, MacWilliam, và sau đó Chan. Cuối cùng tên. Và sau đó một dấu phẩy tách tên cuối cùng từ cái tên đầu tiên. David, Nate, Rob, Tommy, và Zamyla. Tôi luôn luôn pha trộn lên Robby và Tom. Và sau đó, cuối cùng, cột thứ ba là các địa chỉ email. Khi bạn hiểu rằng, phần còn lại của chương trình là khá đơn giản để thực hiện. Những gì chúng tôi đã làm để bắt chước cấu trúc này tương tự trong chương trình C của chúng tôi là chúng tôi đã sử dụng một cấu trúc. Chúng tôi sẽ bắt đầu chơi với những nhiều hơn một chút là tốt. Chúng tôi nhìn thấy chút đầu tiên trong 3 bộ vấn đề, khi chúng tôi đang đối phó với các từ điển. Nhưng điều này struct nhân viên lưu trữ một tên cuối cùng, một tên đầu tiên, và một email. Cũng giống như tập tin CSV của chúng tôi đã được lưu trữ. Vì vậy, đây chỉ là chuyển đổi từ một định dạng khác. Chúng tôi phải chuyển đổi, trong trường hợp này, một cấu trúc nhân viên thành một dòng, một dòng được phân cách bằng dấu phẩy, chỉ như thế. Điều đó làm cho tinh thần? Tất cả các bạn đã thực hiện các bài kiểm tra, vì vậy tôi tưởng tượng bạn đã ít nhất đã có một thời gian để nghĩ về điều này. Trong các chức năng cho thuê, vấn đề đòi hỏi chúng ta phải thực hiện trong - zoom we'll chút này một chút - trong một cấu trúc nhân viên, một cấu trúc nhân viên, tên, và thêm nội dung của nó tập tin staff.csv của chúng tôi. Nó chỉ ra rằng điều này là khá đơn giản để sử dụng. Chúng tôi loại sẽ chơi xung quanh với các chức năng hiện nay hơn một chút. Tuy nhiên, trong trường hợp này, hàm fprintf thực sự là chìa khóa. Vì vậy, với fprintf, chúng tôi có thể in, giống như các bạn đã được sử dụng printf cả nhiệm kỳ này. Bạn có thể printf một dòng vào một tập tin. Vì vậy, thay vì chỉ làm cho các cuộc gọi thông thường printf nơi bạn cung cấp cho nó các chuỗi định dạng và sau đó bạn thay thế tất cả các biến với các đối số sau đây, với fprintf, lập luận của bạn đầu tiên là thay vì tập tin bạn muốn viết thư cho. Nếu chúng ta xem xét điều này trong thiết bị, ví dụ, người đàn ông fprintf, chúng ta có thể thấy sự khác biệt giữa printf và fprintf. Tôi sẽ phóng to ở đây một chút. Vì vậy, với printf, chúng tôi cung cấp cho nó một chuỗi định dạng, và sau đó các đối số tiếp theo là tất cả các biến để thay thế hoặc thay thế vào chuỗi định dạng của chúng tôi. Trong khi với fprintf, tham số đầu tiên thực sự là tập tin * này được gọi là một dòng suối. Di chuyển trở lại trên đây cho thuê của chúng tôi, chúng tôi đã có dòng * tập tin của chúng tôi mở ra cho ta. Đó là những dòng đầu tiên này, nó mở tập tin staff.csv, mở nó trong chế độ phụ thêm, và tất cả những gì còn lại cho chúng ta làm là viết cấu trúc nhân viên vào tập tin. Và, chúng ta hãy xem, tôi muốn sử dụng iPad? Tôi sẽ sử dụng iPad. Chúng tôi có void - cho là đặt trên bàn để tôi có thể viết tốt hơn một chút - làm mất hiệu lực thuê và phải mất một đối số, cơ cấu cán bộ gọi là s. Niềng răng của chúng tôi, chúng tôi đã có tập tin * của chúng tôi tập tin gọi là, chúng tôi có dòng fopen của chúng tôi ban cho chúng ta, và tôi chỉ sẽ viết nó như một dấu chấm vì nó đã có trong các Pedia. Và sau đó trên dòng tiếp theo của chúng tôi, chúng tôi sẽ làm cho một cuộc gọi đến fprintf và chúng ta sẽ phải vượt qua trong tập tin mà chúng ta muốn in, và sau đó định dạng chuỗi của chúng tôi, trong đó - Tôi sẽ cho các bạn cho tôi biết những gì nó trông giống như. Làm thế nào về bạn, Stella? Bạn có biết những gì phần đầu tiên của chuỗi định dạng trông giống như? Stella] Tôi không chắc chắn. >> Hãy hỏi Jimmy. Bạn có biết, Jimmy? [Jimmy] có nó chỉ là cuối cùng? Tôi không biết. Tôi không hoàn toàn chắc chắn. >> Okay. Làm thế nào về, không ai có được điều này đúng vào kỳ thi? Số Tất cả các quyền. Nó chỉ ra rằng ở đây tất cả chúng ta phải làm là chúng tôi muốn mỗi một phần của cấu trúc nhân viên của chúng tôi được in ra như là một chuỗi vào tập tin của chúng tôi. Chúng tôi chỉ cần sử dụng chuỗi ký tự thay thế ba lần khác nhau, vì chúng ta có một tên cuối cùng theo sau dấu phẩy, sau đó một tên đầu tiên sau dấu phẩy, và sau đó cuối cùng là địa chỉ email mà được theo sau - đó là không phù hợp trên màn hình của tôi, nhưng nó tiếp theo ký tự xuống dòng. Vì vậy, tôi sẽ viết nó xuống đó. Và sau đó sau chuỗi định dạng của chúng tôi, chúng tôi chỉ có thay thế, mà chúng ta truy cập bằng cách sử dụng các ký hiệu dấu chấm mà chúng ta thấy trong 3 bộ vấn đề. Chúng tôi có thể sử dụng s.last, s.first, và s.email để thay thế trong ba giá trị vào chuỗi định dạng của chúng tôi. Vậy làm thế nào mà đi? Có ý nghĩa? Vâng? Không? Có thể? Okay. Điều cuối cùng mà chúng ta làm sau khi chúng tôi đã in và sau khi chúng tôi đã mở tập tin của chúng tôi: bất cứ khi nào chúng tôi đã mở một tập tin, chúng tôi luôn luôn phải nhớ để đóng nó. Bởi vì nếu không chúng tôi sẽ kết thúc rò rỉ bộ nhớ, sử dụng mô tả tập tin. Vì vậy, để đóng nó, chúng tôi sử dụng có chức năng nào? Daniel? [Daniel] fclose? >> Fclose, chính xác. Vì vậy, phần cuối cùng của vấn đề này là đúng đóng tập tin, bằng cách sử dụng các chức năng fclose, mà chỉ trông như thế. Không quá điên rồ. Cool. Vì vậy, đó là vấn đề 33 trên quiz. Chúng tôi sẽ có tập tin chắc chắn hơn I / O đến. Chúng tôi sẽ làm hơn một chút trong bài giảng ngày hôm nay, hoặc trong phần ngày hôm nay, bởi vì đó là những gì đang xảy ra để tạo thành phần lớn này pset sắp tới. Chúng ta hãy chuyển từ các bài kiểm tra vào thời điểm này. Vâng? [Charlotte]] Tại sao fclose (file) thay vì fclose (staff.csv)? >> Ah. Bởi vì nó chỉ ra đó - vì vậy câu hỏi, mà là một tuyệt vời, là lý do tại sao, khi chúng tôi viết fclose, chúng ta viết sao biến fclose (file) như trái ngược với tên tập tin, staff.csv? Là đúng? Yeah. Vì vậy, chúng ta hãy có một cái nhìn. Nếu tôi chuyển về máy tính xách tay của tôi, và chúng ta hãy nhìn vào các chức năng fclose. Vì vậy, các chức năng fclose đóng một dòng suối và phải mất trong con trỏ vào dòng mà chúng tôi muốn đóng, như trái ngược với tên tập tin thực tế mà chúng tôi muốn đóng. Và điều này là bởi vì đằng sau hậu trường, khi bạn thực hiện một cuộc gọi đến fopen, khi bạn mở một tập tin, bạn đang thực sự cấp phát bộ nhớ để lưu trữ thông tin về tập tin. Vì vậy, bạn có con trỏ tập tin có thông tin về tập tin, như nó mở, kích thước của nó, nơi mà bạn đang xem trong tập tin, để bạn có thể làm cho việc đọc và viết các cuộc gọi đến mà địa điểm cụ thể trong tập tin. Bạn kết thúc đóng con trỏ thay vì đóng tên tập tin. Vâng? [Daniel] Vì vậy, để sử dụng cho thuê, bạn sẽ nói - như thế nào có được những người sử dụng đầu vào? Fprintf hành động như GetString trong ý nghĩa rằng nó sẽ chỉ chờ đợi cho người sử dụng đầu vào và yêu cầu bạn gõ này - hoặc chờ đợi để bạn có thể gõ ba điều này? Hoặc bạn có cần phải sử dụng một cái gì đó để thực hiện cho thuê? >> Yeah. Vì vậy, chúng tôi không câu hỏi, làm thế nào để chúng ta có được những người sử dụng đầu vào để thực hiện cho thuê? Và những gì chúng tôi có ở đây là người gọi của thuê, được thông qua trong cấu trúc nhân viên với tất cả các dữ liệu được lưu trữ trong một cấu trúc đã. Vì vậy, fprintf là có thể chỉ cần viết rằng dữ liệu trực tiếp vào tập tin. Không phải chờ đợi cho đầu vào của người sử dụng. Người sử dụng đã được đưa ra đầu vào bằng đúng cách đặt nó trong cấu trúc nhân viên này. Và những thứ, tất nhiên, sẽ phá vỡ nếu có của những người con trỏ là vô giá trị, vì vậy chúng tôi di chuyển trở lại lên ở đây và chúng ta nhìn vào cấu trúc của chúng tôi. Chúng tôi có chuỗi cuối cùng, chuỗi đầu tiên, chuỗi email. Bây giờ chúng ta biết rằng tất cả những người thực sự, dưới mui xe, là các biến char *. Có thể có hoặc có thể không được chỉ để null. Họ có thể được trỏ đến bộ nhớ trên heap, có thể bộ nhớ trên stack. Chúng tôi không thực sự biết, nhưng nếu bất kỳ của các con trỏ là null, hoặc không hợp lệ, mà chắc chắn sẽ sụp đổ chức năng cho thuê của chúng tôi. Đó là một cái gì đó đã được loại vượt ra ngoài phạm vi của kỳ thi. Chúng tôi không lo lắng về điều đó. Lớn. Okay. Vì vậy, chuyển từ quiz. Hãy đóng anh chàng này, và chúng ta sẽ nhìn vào pset 4. Vì vậy, nếu bạn nhìn vào spec pset, một khi bạn có thể truy cập vào nó, cs50.net/quizzes, chúng ta sẽ đi qua một vài trong những vấn đề phần hôm nay. Tôi đang di chuyển xuống phần các câu hỏi bắt đầu trên trang thứ ba của spec pset. Và phần đầu tiên sẽ yêu cầu bạn đi và xem ngắn chuyển hướng và ống dẫn. Đó là loại một ngăn mát, cho bạn thấy một số người, thủ đoạn dòng lệnh mát mẻ mà bạn có thể sử dụng. Và sau đó chúng tôi đã có một số câu hỏi cho bạn là tốt. Câu hỏi này đầu tiên về dòng suối, mà printf viết theo mặc định, chúng ta đề cập đến một chút ít một chút thời gian trước đây. Này fprintf rằng chúng tôi chỉ thảo luận về mất trong một dòng tập tin * như là đối số của nó. fclose mất trong một dòng * tập tin là tốt, và giá trị trả lại fopen cung cấp cho bạn một dòng * tập tin là tốt. Lý do chúng tôi đã không nhìn thấy trước khi những người khi chúng tôi đã xử lý với printf là bởi vì printf có một dòng suối mặc định. Và dòng mặc định mà nó viết bạn sẽ tìm ra trong ngắn. Vì vậy, chắc chắn có một cái nhìn vào nó. Trong phần ngày nay, chúng ta sẽ nói một chút về GDB, kể từ khi bạn đang quen thuộc hơn với nó, càng thực hành nhiều, bạn nhận được với nó, có khả năng tốt hơn, bạn sẽ có để thực sự săn lùng lỗi trong mã của riêng bạn. Điều này tốc độ quá trình gỡ lỗi lên rất nhiều. Vì vậy, bằng cách sử dụng printf, mỗi khi bạn làm điều đó bạn phải biên dịch lại mã của bạn, bạn phải chạy nó một lần nữa, đôi khi bạn phải di chuyển các cuộc gọi printf xung quanh, nhận xét ra mã, nó chỉ mất một thời gian. Mục tiêu của chúng tôi là để thử và thuyết phục bạn rằng với GDB, bạn có thể cơ bản printf bất cứ điều gì tại bất kỳ điểm nào trong mã của bạn và bạn không bao giờ phải biên dịch lại nó. Bạn không bao giờ có bắt đầu và tiếp tục đoán nơi printf tiếp theo. Điều đầu tiên cần làm là copy dòng này và nhận được các mã phần của trang web. Tôi là sao chép dòng mã này nói rằng, "wget ​​http://cdn.cs50.net". Tôi sẽ để sao chép nó. Tôi sẽ đi qua vào thiết bị của tôi, thu nhỏ để bạn có thể nhìn thấy những gì tôi đang làm, dán trong đó, và khi tôi nhấn Enter, lệnh wget này theo nghĩa đen là một trang web có được. Nó sẽ để kéo xuống tập tin này tắt của Internet, và nó sẽ để lưu nó vào thư mục hiện hành. Bây giờ nếu tôi liệt kê thư mục hiện tại của tôi, bạn có thể thấy rằng tôi đã có tập tin này section5.zip ngay trong đó. Cách để đối phó với anh chàng đó là để giải nén nó, mà bạn có thể làm trong dòng lệnh, chỉ cần như thế này. Section5.zip. Điều đó sẽ giải nén nó, tạo ra các thư mục cho tôi, thổi phồng tất cả các nội dung, đặt chúng ở đó. Vì vậy, bây giờ tôi có thể đi vào 5 thư mục phần của tôi bằng cách sử dụng lệnh cd. Xóa màn hình bằng cách sử dụng rõ ràng. Vì vậy, xóa màn hình. Bây giờ tôi đã có một thiết bị đầu cuối sạch đẹp để đối phó với. Bây giờ nếu tôi liệt kê tất cả các tập tin mà tôi nhìn thấy trong thư mục này, bạn thấy rằng tôi đã có bốn tập tin: buggy1, buggy2, buggy3, và buggy4. Tôi cũng có tương ứng. C tập tin của họ. Chúng tôi sẽ không nhìn vào các tập tin c. Bây giờ. Thay vào đó, chúng ta sẽ sử dụng chúng khi chúng ta mở ra GDB. Chúng tôi đã giữ chúng xung quanh để chúng tôi có thể truy cập vào mã nguồn thực tế khi chúng ta đang sử dụng GDB, nhưng mục tiêu này là một phần của phần này là để tinker xung quanh với GDB và xem làm thế nào chúng ta có thể sử dụng nó để tìm ra những gì đang xảy ra sai với mỗi người trong số bốn các chương trình lỗi. Vì vậy, chúng tôi chỉ cần đi quanh phòng thực sự nhanh chóng, và tôi sẽ hỏi ai đó để chạy một trong những chương trình lỗi, và sau đó chúng tôi sẽ đi như là một nhóm thông qua GDB, và chúng ta sẽ thấy những gì chúng ta có thể làm gì để sửa chữa các chương trình này, hoặc ít nhất là xác định những gì đang xảy ra sai trong mỗi người trong số họ. Hãy bắt đầu với Daniel. Bạn sẽ chạy buggy1? Hãy xem những gì xảy ra. Daniel nói rằng có một lỗi ứng dụng. >> Yeah. Chính xác. Vì vậy, nếu tôi chạy buggy1, tôi nhận được một lỗi seg. Tại thời điểm này, tôi có thể đi và mở buggy1.c, cố gắng tìm ra những gì đang xảy ra sai, nhưng một trong những điều khó chịu nhất về lỗi này lỗi seg là nó không cho bạn biết những gì trong những điều chương trình thực sự đã đi sai và đã phá vỡ. Bạn loại phải nhìn vào mã và tìm ra bằng cách sử dụng đoán và kiểm tra hoặc printf để xem những gì đang xảy ra sai. Một trong những điều thú vị nhất về GDB là nó thực sự, thực sự dễ dàng để tìm ra các dòng của bạn bị treo chương trình. Nó hoàn toàn giá trị nó để sử dụng nó, ngay cả khi chỉ cho điều đó. Vì vậy, để khởi động GDB, tôi gõ GDB, và sau đó tôi cung cấp cho nó đường dẫn đến thực thi mà tôi muốn chạy. Ở đây tôi đang gõ gdb ./buggy1. Nhấn Enter. Mang lại cho tôi tất cả thông tin bản quyền này, và xuống ở đây bạn sẽ nhìn thấy dòng này mà nói, "biểu tượng Đọc từ / home / jharvard/section5/buggy1 ". Và nếu mọi việc suôn sẻ, bạn sẽ thấy nó in ra một thông điệp trông như thế này. Nó sẽ đọc các ký hiệu, nó sẽ nói "Tôi đang đọc biểu tượng từ tập tin thực thi của bạn," và sau đó nó sẽ có điều này "thực hiện" tin nhắn ở đây. Nếu bạn thấy một số biến thể khác của điều này, hoặc bạn nhìn thấy nó không thể tìm thấy các biểu tượng hoặc một cái gì đó như thế, điều đó có nghĩa rằng bạn chỉ không được biên dịch thực thi của bạn đúng cách. Khi chúng tôi biên dịch chương trình để sử dụng với GDB, chúng ta phải sử dụng lá cờ đặc biệt-g, và đó là thực hiện theo mặc định nếu bạn biên dịch chương trình của bạn, chỉ bằng cách gõ làm hoặc lỗi hoặc phục hồi, bất kỳ của những người. Tuy nhiên, nếu bạn đang biên soạn bằng tay với Clang, sau đó bạn sẽ phải đi vào và bao gồm rằng-g cờ. Tại thời điểm này, bây giờ mà chúng tôi có nhắc GDB của chúng tôi, nó khá đơn giản để chạy chương trình. Chúng ta có thể gõ chạy, hoặc chúng tôi có thể chỉ cần gõ r. Hầu hết các lệnh GDB có thể được viết tắt. Thông thường để chỉ một hoặc một vài chữ, mà là khá tốt đẹp. Saad Vì vậy, nếu bạn gõ r và nhấn Enter, những gì xảy ra? Saad SIGSEGV, lỗi phân khúc, và sau đó tất cả các gobbledygook này. >> Yeah. Giống như chúng ta đang thấy trên màn hình ngay bây giờ, và giống như Saad cho biết, khi chúng tôi loại chạy hoặc r và nhấn Enter, chúng tôi vẫn nhận được cùng một lỗi seg. Vì vậy, bằng cách sử dụng GDB không giải quyết vấn đề của chúng tôi. Nhưng nó mang lại cho chúng tôi một số gobbledygook, và nó quay ra rằng gobbledygook thực sự cho chúng ta biết nơi mà nó đang xảy ra. Để phân tích một chút, bit đầu tiên là chức năng, trong đó tất cả mọi thứ đang xảy ra sai. Có __ strcmp_sse4_2 này, và nó cho chúng ta biết rằng nó đang diễn ra trong tập tin này gọi là sysdeps/i386, tất cả những điều này, một lần nữa, loại của một mess - nhưng dòng 254. Đó là loại khó để phân tích. Thông thường khi bạn nhìn thấy các công cụ như thế này, điều đó có nghĩa rằng nó seg đứt gãy trong một trong những hệ thống thư viện. Vì vậy, một cái gì đó để làm với strcmp. Các bạn đã thấy strcmp trước đây. Không quá điên rồ, nhưng thực hiện điều này có nghĩa là strcmp là bị hỏng hoặc rằng có một vấn đề với strcmp? Bạn nghĩ gì, Alexander? Alexander - là 254 dòng? Và không phải là nhị phân, nhưng nó không phải là trần, và sau đó có một ngôn ngữ khác cho từng chức năng. Là 254 trong chức năng đó, hoặc -? >> Dòng 254. Nó trông giống như trong tập tin này., Vì vậy nó là lắp ráp mã có thể. Nhưng, tôi đoán điều cấp bách hơn, bởi vì chúng tôi đã nhận được một lỗi seg, và có vẻ như nó đến từ strcmp chức năng, Điều này hàm ý, sau đó, strcmp mà là bị hỏng? Nó không nên, hy vọng. Vì vậy, chỉ vì bạn có một lỗi phân khúc trong một trong các chức năng hệ thống, thường có nghĩa mà bạn chỉ cần không được gọi một cách chính xác. Điều nhanh nhất để làm để tìm hiểu những gì đang thực sự xảy ra khi bạn nhìn thấy một chuyện điên rồ như thế này, bất cứ khi nào bạn thấy một lỗi seg, đặc biệt là nếu bạn có một chương trình bằng cách sử dụng nhiều hơn là chỉ chính, là sử dụng một backtrace. Tôi viết tắt backtrace bằng cách viết bt, như trái ngược với từ backtrace đầy đủ. Nhưng Charlotte, điều gì sẽ xảy ra khi bạn gõ bt và nhấn Enter? Charlotte Nó cho thấy hai dòng, dòng 0 và dòng 1. >> Yeah. Vì vậy, dòng 0 và dòng 1. Đây là những khung stack thực tế hiện khi chương trình của bạn bị rơi. Bắt đầu từ khung trên cùng, khung 0, và dưới cùng nhất, đó là frame 1. Khung trên cùng của chúng tôi là khung strcmp. Bạn có thể nghĩ về điều này tương tự như vấn đề đó chúng ta chỉ cần làm bài kiểm tra với các con trỏ, nơi mà chúng tôi đã trao đổi stack frame trên stack frame chính, và chúng tôi đã có các biến rằng trao đổi đã được sử dụng trên các biến mà chính đã được sử dụng. Đây vụ tai nạn xảy ra trong chức năng strcmp của chúng tôi, được gọi là chức năng chính của chúng tôi, và backtrace là cho chúng ta không chỉ các chức năng trong đó mọi thứ không, nhưng nó cũng nói với chúng tôi, nơi tất cả mọi thứ được gọi là từ. Vì vậy, nếu tôi di chuyển trên nhiều hơn một chút về bên phải, chúng ta có thể thấy rằng, chúng ta trên đường dây 254 trong tập tin này strcmp-sse4.s. Tuy nhiên, cuộc gọi đã được thực hiện tại buggy1.c, dòng 6. Vì vậy, điều đó có nghĩa là chúng ta có thể làm là chúng ta chỉ có thể đi kiểm tra và xem những gì đang xảy ra tại buggy1.c, dòng 6. Một lần nữa, có một vài cách để làm điều này. Một là để thoát ra khỏi GDB hoặc có mã của bạn mở trong một cửa sổ và tham chiếu chéo. Rằng, trong và của chính nó, là khá tiện dụng bởi vì bây giờ nếu bạn đang ở giờ hành chính và bạn đã có một lỗi seg và TF của bạn đang tự hỏi, nơi tất cả mọi thứ đã được phá vỡ, bạn chỉ có thể nói rằng, "Ồ, dòng 6. Tôi không biết những gì đang xảy ra, nhưng một cái gì đó về dòng 6 gây ra chương trình của tôi để phá vỡ. " Một cách khác để làm điều đó là bạn có thể sử dụng lệnh này danh sách gọi là trong GDB. Bạn cũng có thể viết tắt với l. Vì vậy, nếu chúng ta nhấn l, chúng tôi làm những gì có được ở đây? Chúng tôi nhận được một bó toàn bộ các thứ lạ. Đây là mã lắp ráp thực tế đó là vào strcmp_sse4_2. Điều này có vẻ loại của funky, và lý do chúng tôi đang nhận được điều này là bởi vì hiện tại GDB chúng tôi trong khung 0. Vì vậy, bất cứ lúc nào chúng ta nhìn vào các biến, bất cứ lúc nào chúng ta nhìn vào mã nguồn, chúng tôi đang tìm kiếm mã nguồn liên quan đến stack frame chúng tôi hiện đang. Vì vậy, để có được bất cứ điều gì có ý nghĩa, chúng ta phải di chuyển đến một khung stack mà làm cho ý nghĩa hơn. Trong trường hợp này, khung chính stack sẽ có ý nghĩa nhiều hơn một chút, bởi vì đó là thực sự là mã mà chúng tôi đã viết. Không phải là mã strcmp. Cách bạn có thể di chuyển giữa các khung hình, trong trường hợp này, bởi vì chúng tôi có hai, chúng tôi có 0 và 1, bạn làm điều đó với lên và lệnh xuống. Nếu tôi di chuyển một khung hình, bây giờ tôi đang trong khung chính stack. Tôi có thể di chuyển xuống để trở lại nơi mà tôi đã, tăng trở lại, đi xuống một lần nữa, và đi lên một lần nữa. Nếu bạn đã từng làm chương trình của bạn trong GDB, bạn sẽ có được một vụ tai nạn, bạn sẽ có được backtrace, và bạn thấy rằng nó ở một số tập tin mà bạn không biết những gì đang xảy ra. Bạn hãy thử danh sách, các mã này không nhìn quen thuộc với bạn, nhìn vào khung hình của bạn và tìm ra nơi bạn đang. Có lẽ bạn đang trong khung ngăn xếp sai. Hoặc ít nhất bạn đang ở trong một khung stack không phải là một mà bạn thực sự có thể gỡ lỗi. Bây giờ chúng ta đang ở trong stack frame thích hợp, chúng tôi đang ở trong chính, bây giờ chúng ta có thể sử dụng lệnh danh sách để tìm ra dòng là gì. Và bạn có thể nhìn thấy nó, nó in nó cho chúng tôi tại đây. Nhưng chúng ta có thể nhấn liệt kê tất cả như nhau, và danh sách này cho chúng ta bản in đẹp mã nguồn thực tế đang diễn ra ở đây. Đặc biệt, chúng tôi có thể nhìn vào dòng 6. Chúng ta có thể xem những gì đang xảy ra ở đây. Và có vẻ như chúng tôi đang làm một so sánh chuỗi giữa chuỗi "CS50 đá" và argv [1]. Một cái gì đó về việc này đã bị rơi. Vì vậy, Missy, làm bạn có bất kỳ suy nghĩ về những gì có thể xảy ra ở đây? [Missy] Tôi không biết tại sao nó bị rơi. >> Bạn không biết tại sao nó bị rơi? Jimmy, bất kỳ suy nghĩ? [Jimmy] Tôi không hoàn toàn chắc chắn, nhưng thời gian qua chúng tôi sử dụng chuỗi so sánh, hoặc strcmp, chúng tôi đã có ba trường hợp khác nhau theo nó. Chúng tôi không có một ==, tôi không nghĩ rằng, ngay trong dòng đầu tiên. Thay vào đó, nó đã được tách thành ba, và một là == 0, một là <0, tôi nghĩ, và một là> 0. Vì vậy, có thể một cái gì đó như thế? >> Yeah. Vì vậy, có vấn đề này chúng ta làm sự so sánh chính xác? Stella? Bất kỳ suy nghĩ? Stella] Tôi không chắc chắn. >> Không chắc chắn. Daniel? Suy nghĩ? Okay. Hóa ra những gì đang xảy ra ngay ở đây là khi chúng ta chạy chương trình và chúng tôi đã lỗi seg, khi bạn chạy chương trình lần đầu tiên, Daniel, bạn cho nó bất kỳ đối số dòng lệnh? [Daniel] số >> số Trong trường hợp đó, những gì là giá trị của argv [1]? >> Không có là không có giá trị. >> Right. Vâng, đó là không có giá trị chuỗi thích hợp. Nhưng có một số giá trị. Giá trị được lưu trữ trong đó là gì? >> Một giá trị rác? >> Nó là giá trị rác hoặc, trong trường hợp này, cuối của mảng argv luôn luôn chấm dứt với null. Vì vậy, những gì thực sự đã được lưu trữ trong có là null. Một cách khác để giải quyết vấn đề này, thay vì nghĩ nó thông qua, là để thử in nó ra. Đây là nơi tôi đã nói rằng bằng cách sử dụng GDB là rất tốt, bởi vì bạn có thể in ra tất cả các biến, tất cả các giá trị mà bạn muốn bằng cách sử dụng này tiện dụng-dandy p lệnh. Vì vậy, nếu tôi gõ p và sau đó tôi gõ giá trị của một biến hoặc tên của một biến, nói, argc, tôi thấy rằng argc là 1. Nếu tôi muốn in ra argv [0], tôi có thể làm như vậy chỉ như thế. Và cũng giống như chúng ta đã thấy, argv [0] luôn luôn là tên của chương trình của bạn, luôn luôn là tên của các thực thi. Ở đây bạn thấy nó có tên đường dẫn đầy đủ. Tôi cũng có thể in ra argv [1] và xem những gì sẽ xảy ra. Ở đây chúng tôi có loại có giá trị thần bí. Chúng tôi đã nhận 0x0 này. Ghi vào đầu của thuật ngữ này khi chúng tôi nói chuyện về những con số thập lục phân? Hoặc là câu hỏi ở phần cuối của pset 0 về làm thế nào để đại diện cho 50 trong hex? Cách chúng ta ghi mã số hex trong CS, chỉ để không nhầm lẫn giữa bản thân với các số thập phân, chúng tôi luôn luôn tiền tố với 0x. Vì vậy, tiền tố 0x này luôn luôn chỉ có nghĩa là giải thích các số sau đây là một số thập lục phân, không phải là một chuỗi, không phải là một số thập phân, không phải là một số nhị phân. Kể từ khi số 5-0 là một số hợp lệ trong hệ thập lục phân. Và đó là một số trong số thập phân, 50. Vì vậy, đây chỉ là cách chúng tôi disambiguate. Vì vậy, 0x0 có nghĩa là hệ thập lục phân 0, đó cũng là số thập phân 0, nhị phân 0. Nó chỉ là giá trị 0. Nó chỉ ra rằng đây là những gì null là, trên thực tế, trong bộ nhớ. Null chỉ là 0. Ở đây, các phần tử được lưu trữ tại argv [1] là null. Vì vậy, chúng tôi đang cố gắng để so sánh "CS50 đá" chuỗi một chuỗi null. Vì vậy, dereferencing null, cố gắng để truy cập mọi thứ tại vô giá trị, những người thường sẽ gây ra một số loại lỗi phân khúc hoặc những điều xấu xảy ra. Và nó chỉ ra rằng strcmp không kiểm tra xem có hoặc không bạn đã được thông qua trong một giá trị đó là vô giá trị. Thay vào đó, nó chỉ cần đi về phía trước, cố gắng để làm điều này, và nếu nó seg lỗi, seg lỗi lầm, và đó là vấn đề của bạn. Bạn phải đi sửa chữa nó. Thực sự nhanh chóng, làm thế nào chúng ta có thể khắc phục vấn đề này? Charlotte? Charlotte] Bạn có thể kiểm tra sử dụng nếu. Vì vậy, nếu argv [1] là null, == 0, sau đó trở về 1, hoặc một cái gì đó khó hiểu. >> Yeah. Vì vậy, đó là một cách tuyệt vời để làm điều đó, như chúng ta có thể kiểm tra xem, giá trị chúng tôi đang về để đi vào strcmp, argv [1], là nó vô giá trị? Nếu đó là vô giá trị, sau đó chúng tôi có thể nói không sao, hủy bỏ. Một cách phổ biến hơn để làm điều này là sử dụng giá trị argc. Bạn có thể thấy ngay tại đây vào đầu của chính, chúng ta bỏ qua đó thử nghiệm đầu tiên mà chúng ta thường làm khi chúng ta sử dụng các đối số dòng lệnh, đó là để kiểm tra hay không giá trị argc của chúng tôi là những gì chúng tôi mong đợi. Trong trường hợp này, chúng tôi hy vọng ít nhất hai đối số, tên của chương trình cộng với một người khác. Bởi vì chúng ta đang sử dụng đối số thứ hai ngay tại đây. Vì vậy, có một số loại thử nghiệm trước, trước khi cuộc gọi strcmp của chúng tôi rằng các xét nghiệm hay không argv ít nhất là 2, cũng sẽ làm cùng một loại điều. Chúng ta có thể thấy rằng nếu các hoạt động bằng cách chạy chương trình một lần nữa. Bạn luôn có thể khởi động lại chương trình của bạn trong GDB, mà thực sự là tốt đẹp. Bạn có thể chạy, và khi bạn vượt qua trong đối số cho chương trình của bạn, bạn vượt qua chúng trong khi bạn gọi chạy, không phải khi bạn khởi động GDB. Bằng cách đó bạn có thể gọi chương trình của bạn với các đối số khác nhau mỗi lần. Vì vậy, chạy, hay một lần nữa, tôi có thể loại r, và hãy xem những gì sẽ xảy ra nếu chúng ta gõ "hello". Nó sẽ luôn luôn hỏi bạn nếu bạn muốn bắt đầu từ đầu một lần nữa. Thông thường, bạn muốn bắt đầu nó từ đầu một lần nữa. Và tại thời điểm này, nó khởi động lại nó một lần nữa, nó in ra chương trình mà chúng tôi đang chạy, buggy1, với các đối số xin chào, và nó in này ra tiêu chuẩn, nó nói, "Bạn nhận được một D," khuôn mặt buồn. Nhưng chúng tôi đã không seg lỗi. Nói rằng quá trình đã thoát bình thường. Vì vậy, đó có vẻ khá tốt. Lỗi Không seg, chúng tôi đã thực hiện nó trong quá khứ, vậy có vẻ như đó là thực sự là lỗi lỗi seg mà chúng tôi đã nhận được. Thật không may, nó cho chúng ta biết rằng chúng tôi đang nhận được một D. Chúng ta có thể quay trở lại và nhìn vào mã và xem những gì đang xảy ra ở đó tìm ra những gì là lý do tại sao nó đã nói với chúng tôi rằng chúng tôi đã nhận một D. Hãy xem, ở đây đã được printf nói rằng bạn có một D. Nếu chúng tôi loại danh sách, như bạn giữ danh sách gõ, nó giữ iterating thông qua các chương trình của bạn, do đó, nó sẽ chỉ cho bạn vài dòng đầu tiên của chương trình của bạn. Sau đó, nó sẽ cho bạn thấy một vài dòng tiếp theo, và đoạn tiếp theo và đoạn tiếp theo. Và nó sẽ tiếp tục cố gắng để đi xuống. Và bây giờ chúng tôi sẽ nhận được để "xếp hàng số 16 ra khỏi phạm vi." Bởi vì nó chỉ có 15 dòng. Nếu bạn nhận được đến thời điểm này và tự hỏi: "Tôi phải làm gì?" bạn có thể sử dụng lệnh trợ giúp. Sử dụng giúp đỡ và sau đó cho nó cái tên của một lệnh. Và bạn thấy GDB ban cho chúng ta tất cả các loại công cụ này. Nó nói, "không có đối số, liệt kê hơn mười dòng sau hoặc xung quanh danh sách trước đó. - Danh sách liệt kê mười dòng trước " Vì vậy, hãy thử sử dụng trừ danh sách. Và đó liệt kê 10 dòng trước đó, bạn có thể chơi xung quanh với một danh sách ít. Bạn có thể làm danh sách danh sách, bạn thậm chí có thể cung cấp cho danh sách một số, như danh sách 8, và nó sẽ liệt kê 10 dòng trên dòng 8. Và bạn có thể xem những gì đang xảy ra ở đây là bạn đã có một đơn giản, nếu người nào khác. Nếu bạn gõ trong CS50 đá, nó in ra "Bạn nhận được một A." Nếu không thì nó in ra "Bạn nhận được một D." Bummer thị trấn. Được rồi. Vâng? [Daniel] Vì vậy, khi tôi đã cố gắng làm CS50 đá không có dấu ngoặc kép, nó nói "Bạn nhận được một D." Tôi cần có dấu ngoặc kép để có được nó để làm việc, tại sao vậy? >> Yeah. Nó chỉ ra rằng khi đây là một miếng ngon ít niềm vui - khi bạn chạy chương trình, nếu chúng ta chạy nó và chúng tôi gõ CS50 đá, giống như Daniel đã nói ông đã làm, và bạn nhấn Enter, nó vẫn nói chúng tôi nhận được một D. Và câu hỏi là, tại sao điều này? Và nó quay ra rằng cả hai thiết bị đầu cuối của chúng tôi và GDB phân tích này như là hai đối số riêng biệt. Bởi vì khi có một không gian, đó là ngụ ý là đối số đầu tiên kết thúc, các đối số tiếp theo là về để bắt đầu. Cách để kết hợp những người thành hai, hay xin lỗi, vào một đối số, là sử dụng dấu ngoặc kép. Vì vậy, bây giờ, nếu chúng ta đặt nó trong dấu ngoặc kép và chạy nó một lần nữa, chúng tôi nhận được một A. Vì vậy, chỉ cần để recap, không có dấu ngoặc kép, CS50 và đá được phân tích như hai đối số riêng biệt. Với dấu ngoặc kép, nó phân tích cú pháp như là một đối số hoàn toàn. Chúng tôi có thể thấy điều này với một breakpoint. Vì vậy, đến nay chúng tôi đã chạy chương trình của chúng tôi, và nó được chạy cho đến khi nào nó seg lỗi hoặc hits một lỗi hoặc cho đến khi nó đã thoát và tất cả đã được hoàn toàn tốt. Đây không phải là nhất thiết phải là điều hữu ích nhất, bởi vì đôi khi bạn có một lỗi trong chương trình của bạn, nhưng nó không gây ra một lỗi phân khúc. Nó không gây ra chương trình của bạn để ngăn chặn hoặc bất cứ điều gì như thế. Cách để có được GDB tạm dừng chương trình của bạn tại một điểm cụ là để thiết lập một breakpoint. Bạn có thể làm điều này bằng cách thiết lập một breakpoint trên một tên chức năng hoặc bạn có thể thiết lập một breakpoint trên một dòng cụ thể của mã. Tôi thích đặt breakpoint về tên chức năng, bởi vì - dễ nhớ, và nếu bạn thực sự đi vào và thay đổi mã nguồn của bạn lên một chút, sau đó breakpoint của bạn sẽ thực sự ở tại cùng một vị trí trong mã của bạn. Trong khi đó, nếu bạn đang sử dụng số dòng, và các số dòng thay đổi bởi vì bạn thêm hoặc xóa một số mã, sau đó breakpoint của bạn là tất cả hoàn toàn hơi say lên. Một trong những điều phổ biến nhất tôi làm là thiết lập một breakpoint trên các chức năng chính. Thường thì tôi sẽ khởi động GDB, tôi sẽ gõ b chính, nhấn Enter, và đó sẽ thiết lập một breakpoint các chức năng chính mà chỉ nói, "Tạm dừng chương trình ngay sau khi bạn bắt đầu chạy", và theo cách đó, khi tôi chạy chương trình của tôi với, nói, CS50 đá như hai đối số và nhấn Enter, nó được các chức năng chính và nó dừng lại ngay ở dòng đầu tiên, ngay trước khi nó đánh giá chức năng strcmp. Kể từ khi tôi đang bị tạm dừng, bây giờ tôi có thể bắt đầu mucking xung quanh và nhìn thấy những gì đang xảy với tất cả các biến khác nhau được thông qua vào chương trình của tôi. Ở đây tôi có thể in ra argc và xem những gì đang xảy ra. Xem argc là 3, bởi vì nó có 3 giá trị khác nhau trong đó. Nó có tên của chương trình, nó có tham số đầu tiên và đối số thứ hai. Chúng tôi có thể in ra những bằng cách nhìn vào argv [0], argv [1], và argv [2]. Vì vậy, bây giờ bạn cũng có thể thấy lý do tại sao điều này gọi strcmp là thất bại, bởi vì bạn thấy rằng nó đã chia tay CS50 và đá vào hai đối số riêng biệt. Tại thời điểm này, một khi bạn đã trúng một breakpoint, bạn có thể tiếp tục bước qua chương trình của bạn từng dòng một, như trái ngược với bắt đầu chương trình của bạn một lần nữa. Vì vậy, nếu bạn không muốn bắt đầu chương trình của bạn một lần nữa và chỉ cần tiếp tục từ đây, bạn có thể sử dụng lệnh tiếp tục và tiếp tục sẽ chạy chương trình để kết thúc. Cũng giống như nó đã làm ở đây. Tuy nhiên, nếu tôi khởi động chương trình, CS50 đá, nó cập breakpoint của tôi một lần nữa, và lần này, nếu tôi không muốn chỉ cần đi tất cả các cách thức thông qua phần còn lại của chương trình, Tôi có thể sử dụng lệnh kế tiếp, mà tôi cũng viết tắt với n. Và điều này sẽ bước qua các đường dây chương trình bằng dòng. Vì vậy, bạn có thể xem như là những thứ thực hiện, như là các biến thay đổi, như là những thứ được cập nhật. Đó là khá tốt đẹp. Điều thú vị khác là thay vì lặp đi lặp lại cùng một lệnh hơn và hơn và hơn một lần nữa, nếu bạn chỉ cần nhấn Enter - ở đây bạn thấy tôi đã không gõ vào bất cứ điều gì - nếu tôi chỉ cần nhấn Enter, nó sẽ lặp lại các lệnh trước đó, hoặc lệnh GDB trước đó mà tôi chỉ cần đặt. Tôi có thể giữ nhấn Enter và nó sẽ tiếp tục bước qua dòng mã của tôi dòng. Tôi khuyến khích các bạn đi kiểm tra các chương trình lỗi khác như là tốt. Chúng tôi không có thời gian để có được qua tất cả chúng ngày hôm nay trong phần. Mã nguồn là có, vì vậy bạn có thể loại xem những gì đang xảy ra đằng sau hậu trường nếu bạn nhận được thực sự khó khăn, nhưng ít nhất, chỉ cần thực hành khởi động GDB, chạy chương trình cho đến khi nó phá vỡ vào bạn, nhận được backtrace, tìm ra những gì hoạt động trí sự cố, dòng nó, in ra một số giá trị biến, chỉ để bạn có được một cảm giác về nó, bởi vì đó thực sự sẽ giúp bạn đi về phía trước. Tại thời điểm này, chúng ta sẽ bỏ ra của GDB, mà bạn sử dụng bỏ thuốc lá hoặc chỉ q. Nếu chương trình của bạn là ở giữa chạy vẫn còn, và nó đã không thoát, nó sẽ luôn luôn hỏi bạn, "Bạn có chắc chắn bạn thực sự muốn bỏ thuốc lá?" Bạn chỉ có thể đạt. Bây giờ chúng ta sẽ nhìn vào vấn đề tiếp theo chúng ta, đó là chương trình con mèo. Nếu bạn xem ngắn chuyển hướng và ống dẫn, bạn sẽ thấy rằng Tommy sử dụng chương trình này rằng về cơ bản in tất cả các đầu ra của một tập tin vào màn hình. Vì vậy, nếu tôi chạy cat, điều này thực sự là một chương trình được xây dựng trong thiết bị, và nếu bạn có máy Mac, bạn có thể làm điều này trên máy Mac của bạn, nếu bạn mở thiết bị đầu cuối. Và chúng tôi - mèo, hãy nói, cp.c, và nhấn Enter. Điều này đã làm, nếu chúng ta di chuyển lên một chút và nhìn thấy nơi chúng tôi chạy dòng, hoặc trong trường hợp chúng tôi chạy lệnh cat, nghĩa đen chỉ in ra nội dung của cp.c màn hình của chúng tôi. Chúng tôi có thể chạy nó một lần nữa và bạn có thể đặt trong nhiều tập tin với nhau. Vì vậy, bạn có thể làm cp.c mèo, và sau đó chúng ta cũng có thể ghép các tập tin cat.c, đó là chương trình chúng tôi đang viết, và nó sẽ in cả hai tập tin trở lại trở lại màn hình của chúng tôi. Vì vậy, nếu chúng ta di chuyển lên một chút, chúng ta thấy rằng khi chúng ta chạy cp.c mèo, cat.c, đầu tiên nó in ra các tập tin cp, và sau đó dưới nó, nó được in ra các tập tin cat.c phải xuống ở đây. Chúng ta sẽ sử dụng điều này để chỉ nhận được chân của chúng tôi ướt. Chơi xung quanh với việc in ấn đơn giản để thiết bị đầu cuối, xem làm thế nào mà làm việc. Nếu bạn mở with gedit cat.c, nhấn Enter, bạn có thể xem chương trình mà chúng tôi đang về để viết. Chúng tôi đã bao gồm đĩa này nồi hơi tốt đẹp, vì vậy chúng tôi không cần phải dành nhiều thời gian đánh máy tất cả mà ra. Chúng tôi cũng kiểm tra số đối số thông qua nhập Chúng tôi in ra một thông điệp sử dụng tốt đẹp. Đây là loại điều đó, một lần nữa, như chúng ta đã nói về, nó gần giống như bộ nhớ cơ bắp. Chỉ cần nhớ để tiếp tục làm cùng một loại công cụ và luôn luôn in ra một số loại thông điệp hữu ích để mọi người biết làm thế nào để chạy chương trình của bạn. Với con mèo, nó khá đơn giản, chúng ta sẽ đi qua tất cả các đối số khác nhau đã được thông qua chương trình của chúng tôi, và chúng tôi sẽ in nội dung ra màn hình tại một thời điểm. Để in các tập tin vào màn hình, chúng ta sẽ làm một cái gì đó rất giống nhau những gì chúng ta đã làm ở phần cuối của bài kiểm tra. Vào cuối của các bài kiểm tra, thuê chương trình, chúng tôi đã mở một tập tin, và sau đó chúng tôi đã in nó. Trong trường hợp này, chúng tôi sẽ mở một tập tin, và chúng ta sẽ đọc từ nó thay vì. Sau đó, chúng ta sẽ để in, thay vì vào một tập tin, chúng tôi sẽ in ra màn hình. Vì vậy, in ấn màn hình tất cả các bạn đã thực hiện trước khi với printf. Vì vậy, đó không phải là quá điên rồ. Tuy nhiên, đọc một tập tin là loại lạ. Chúng ta sẽ đi qua một chút ít tại một thời điểm. Nếu bạn quay trở lại với vấn đề cuối cùng trên quiz của bạn, vấn đề 33, dòng đầu tiên mà chúng tôi đang làm ở đây, mở các tập tin, rất giống với những gì chúng tôi đã làm ở đó. Vì vậy, Stella, những gì mà nhìn dòng như thế, khi chúng ta mở một tập tin? [Stella] Capital FILE *, tập tin - >> Được rồi. >> - Bằng fopen. >> Yup. Trong trường hợp này? Đó là trong các bình luận. >> Đó là trong các bình luận? argv [i] và r? >> Chính xác. Ngay trên. Vì vậy, Stella là hoàn toàn đúng. Đây là những dòng trông giống như. Chúng tôi đang đi để có được một biến dòng tập tin, lưu trữ nó trong một FILE *, do đó, tất cả các mũ, FILE, *, và tên của biến này sẽ được tập tin. Chúng ta có thể gọi nó là bất cứ điều gì chúng tôi muốn. Chúng ta có thể gọi nó first_file, hoặc file_i, bất cứ điều gì chúng tôi muốn. Và sau đó là tên của tập tin đã được thông qua vào dòng lệnh để chương trình này. Vì vậy, nó được lưu trữ trong argv [i] và sau đó chúng tôi đang đi để mở tập tin này trong chế độ đọc. Bây giờ chúng ta đã mở các tập tin, điều mà chúng ta luôn luôn phải nhớ để làm gì bất cứ khi nào chúng tôi đã mở một tập tin? Đóng nó lại. Vì vậy, Missy, làm thế nào để chúng ta đóng một tập tin? [Missy] fclose (file) >> fclose (file). Chính xác. Lớn. Okay. Nếu chúng ta nhìn vào điều này để làm bình luận ngay tại đây, nó nói, "Mở argv [i] và in nội dung của nó stdout." Tiêu chuẩn ra là một tên lạ. Thiết bị xuất chuẩn chỉ là cách nói của chúng tôi chúng ta muốn in nó đến thiết bị đầu cuối, chúng tôi muốn in nó vào dòng đầu ra tiêu chuẩn. Chúng tôi thực sự có thể nhận được thoát khỏi nhận xét này ngay tại đây. Tôi sẽ để sao chép và dán nó vì đó là những gì chúng tôi đã làm. Tại thời điểm này, bây giờ chúng ta phải đọc các bit tập tin bằng cách bit. Chúng tôi đã thảo luận một vài cách của các tập tin đọc. Mà những người ưa thích của bạn cho đến nay? Những cách đã nhìn thấy hoặc làm bạn nhớ, để đọc các tập tin? [Daniel] fread? >> Fread? Vì vậy, fread là một trong những. Jimmy, bạn có biết bất kỳ những người khác? [Jimmy] số >> Okay. Nope. Charlotte? Alexander? Bất cứ người khác? Okay. Vì vậy, những người khác fgetc, rằng chúng tôi sẽ sử dụng rất nhiều. Ngoài ra còn có fscanf, bạn thấy một mô hình ở đây? Tất cả họ đều bắt đầu với f. Bất cứ điều gì để làm với một tập tin. Có fread, fgetc, fscanf. Đây là tất cả các chức năng đọc. Đối với văn bản chúng tôi có fwrite, chúng tôi có fputc thay vì fgetc. Chúng tôi cũng đã fprintf như chúng ta đã thấy trên các bài kiểm tra. Vì đây là một vấn đề liên quan đến việc đọc từ một tập tin, chúng ta sẽ sử dụng một trong ba chức năng. Chúng tôi sẽ không sử dụng các chức năng này ở đây. Các chức năng này được tìm thấy trong thư viện I / O tiêu chuẩn. Vì vậy, nếu bạn nhìn ở phía trên cùng của chương trình này, bạn có thể thấy rằng chúng tôi đã bao gồm các tập tin tiêu đề cho thư viện I / O tiêu chuẩn. Nếu chúng ta muốn tìm ra cái nào chúng ta muốn sử dụng, chúng tôi luôn luôn có thể mở các trang người đàn ông. Vì vậy, chúng ta có thể gõ stdio người đàn ông và đọc tất cả về đầu vào stdio và chức năng đầu ra trong C. Và chúng tôi đã có thể nhìn thấy oh, nhìn. Nó đề cập đến fgetc, nó đề cập đến fputc. Vì vậy, bạn có thể đi sâu xuống một chút và nhìn vào, nói, fgetc và nhìn vào trang người đàn ông của mình. Bạn có thể thấy là nó đi cùng với một bó toàn bộ các chức năng khác: fgetc, fgets, getc, getchar, được, ungetc, và đầu vào của các ký tự và chuỗi. Vì vậy, đây là làm thế nào chúng ta đọc trong các ký tự và chuỗi từ các tập tin từ đầu vào tiêu chuẩn, mà chủ yếu là từ người dùng. Và đây là cách chúng tôi làm điều đó trong thực tế C. Vì vậy, điều này là không sử dụng GetString và các chức năng getchar mà chúng ta đã sử dụng từ thư viện CS50. Chúng tôi sẽ làm vấn đề này trong một vài cách để bạn có thể thấy hai cách khác nhau để làm việc đó. Cả hai chức năng fread rằng Daniel đã đề cập và fgetc là những cách tốt để làm điều đó. Tôi nghĩ rằng fgetc là một chút dễ dàng hơn, bởi vì nó chỉ có, như bạn thấy, một đối số, FILE * mà chúng tôi đang cố gắng để đọc các ký tự từ, và giá trị trả về của nó là một int. Và đây là một chút bối rối, phải không? Bởi vì chúng tôi đang nhận được một nhân vật, vậy tại sao không trở lại này là một char? Các bạn có bất kỳ ý tưởng về lý do tại sao điều này có thể không trả về một char? [Missy câu trả lời, không thể hiểu] >> Vâng. Vì vậy, Missy là hoàn toàn đúng. Nếu đó là ASCII, sau đó số nguyên này có thể được ánh xạ đến một char thực tế. Có thể là một ký tự ASCII, và đó là đúng. Đó là chính xác những gì đang xảy ra. Chúng tôi đang sử dụng một int chỉ đơn giản là bởi vì nó có nhiều bit hơn. Nó lớn hơn một char, char của chúng tôi chỉ có 8 bit, 1 byte trên máy 32-bit của chúng tôi. Và một int có giá trị tất cả 4 byte của không gian. Và nó chỉ ra rằng cách fgetc hoạt động, nếu chúng ta di chuyển xuống trong tóm tắt của chúng tôi trong trang người đàn ông này một chút, di chuyển tất cả các con đường xuống. Nó chỉ ra rằng họ sử dụng giá trị này đặc biệt được gọi là EOF. Đó là một hằng số đặc biệt như là giá trị trả về của hàm fgetc bất cứ khi nào bạn nhấn vào cuối của tập tin hoặc nếu bạn nhận được một lỗi. Và nó chỉ ra rằng để làm những so sánh với kết thúc tập tin đúng, bạn muốn có thêm số tiền đó thông tin mà bạn có trong một int như trái ngược với sử dụng một biến char. Mặc dù fgetc hiệu quả nhận được một nhân vật từ một tập tin, bạn muốn ghi nhớ rằng nó được trả lại một cái gì đó là kiểu int cho bạn. Điều đó nói rằng, nó khá dễ dàng để sử dụng. Nó sẽ cung cấp cho chúng ta một nhân vật, vì vậy tất cả chúng ta phải làm là tiếp tục yêu cầu các tập tin, "Hãy cho tôi ký tự tiếp theo, cung cấp cho tôi những nhân vật tiếp theo, cung cấp cho tôi những nhân vật tiếp theo," cho đến khi chúng tôi nhận được để kết thúc của tập tin. Và đó sẽ kéo trong một ký tự tại một thời gian từ tập tin của chúng tôi, và sau đó chúng ta có thể làm bất cứ điều gì chúng ta thích với nó. Chúng ta có thể lưu trữ nó, chúng ta có thể thêm nó vào một chuỗi, chúng ta có thể in nó ra. Làm được điều đó. Phóng to thu nhỏ lại và sẽ trở lại chương trình cat.c của chúng tôi, nếu chúng ta sử dụng fgetc, làm thế nào chúng ta có thể tiếp cận dòng tiếp theo của mã này? Chúng ta sẽ sử dụng - fread sẽ làm một cái gì đó hơi khác nhau. Và lần này, chúng ta chỉ cần sử dụng fgetc để có được một trong những nhân vật tại một thời điểm. Để xử lý một tập tin toàn bộ, những gì chúng ta có thể phải làm gì? Có bao nhiêu ký tự trong một tập tin? Hiện có rất nhiều. Vì vậy, bạn có thể muốn để có được một và sau đó nhận được một và nhận được một và nhận được một. Loại thuật toán bạn có nghĩ rằng chúng ta có thể phải sử dụng ở đây? Loại? [Alexander] A cho vòng lặp? >> Chính xác. Một số loại vòng lặp. A cho vòng lặp là thực sự tuyệt vời, trong trường hợp này. Và cũng giống như bạn đã nói, nó có vẻ như bạn muốn có một vòng lặp trên toàn bộ tập tin, nhận được một nhân vật tại một thời điểm. Bất kỳ đề xuất về những gì có thể trông như thế? [Alexander, khó hiểu] >> Được rồi, chỉ nói với tôi bằng tiếng Anh những gì bạn đang cố gắng để làm? [Alexander, khó hiểu] Vì vậy, trong trường hợp này, có vẻ như chúng tôi chỉ cố gắng để lặp trên toàn bộ tập tin. [Alexander] Vì vậy, i > Kích thước của? Tôi đoán kích thước của tập tin, phải không? Các kích thước - we'll chỉ cần viết nó như thế này. Kích thước của tập tin trong thời gian này, i + +. Vì vậy, nó chỉ ra rằng cách bạn làm điều này bằng cách sử dụng fgetc, và điều này là mới, là không có cách nào dễ dàng để có được kích thước của một tập tin với loại hình này "sizeof" xây dựng mà bạn đã thấy trước. Khi chúng tôi sử dụng chức năng fgetc, chúng tôi giới thiệu một số loại mới, lý thú, cú pháp này cho vòng lặp, thay vì chỉ sử dụng một truy cập cơ bản đi nhân vật bằng cách nhân vật, chúng tôi sẽ kéo một trong những nhân vật tại một thời điểm, một ký tự tại một thời điểm, và cách chúng ta biết chúng ta đang ở cuối không khi chúng tôi đã tính một số ký tự nhất định, nhưng khi nhân vật chúng tôi kéo ra là kết thúc đặc biệt của nhân vật tập tin. Vì vậy, chúng ta có thể làm điều này - Tôi gọi đây là ch, và chúng ta sẽ khởi tạo nó với cuộc gọi đầu tiên của chúng tôi để có được những ký tự đầu tiên trong số các tập tin. Vì vậy, phần này ngay tại đây, điều này là có được một ký tự của tập tin và lưu nó vào biến ch. Chúng tôi sẽ tiếp tục làm điều này cho đến khi chúng tôi nhận được để kết thúc của tập tin, mà chúng ta làm bằng cách thử nghiệm cho các nhân vật không phải là bằng với ký tự EOF đặc biệt. Và sau đó, thay vì làm ch + +, sẽ chỉ tăng giá trị, vì vậy nếu chúng ta đọc một out của tập tin, vốn, nói, ch + + sẽ cung cấp cho chúng tôi b, và sau đó chúng tôi nhận được c và sau đó d. Đó là rõ ràng không phải những gì chúng ta muốn. Những gì chúng tôi muốn ở đây trong này bit cuối cùng chúng tôi muốn để có được những nhân vật tiếp theo từ tập tin. Vì vậy, làm thế nào chúng ta có thể nhận được nhân vật tiếp theo từ tập tin? Làm thế nào để chúng ta được những nhân vật đầu tiên từ tập tin? [Sinh viên] fgetfile? >> Fgetc, hoặc xin lỗi, bạn đã hoàn toàn đúng. Tôi sai chính tả ngay tại đây. Vì vậy, yeah. Ở đây, thay vì làm ch + +, chúng tôi sẽ gọi fgetc (file) một lần nữa và lưu trữ kết quả trong biến ch cùng của chúng tôi. [Sinh viên câu hỏi, không thể hiểu] >> Đây là nơi mà những kẻ * FILE là đặc biệt. Cách họ làm việc là họ - khi bạn lần đầu tiên mở - khi lần đầu tiên thực hiện cuộc gọi fopen, * FILE hiệu quả phục vụ như là một con trỏ đến đầu của tập tin. Và sau đó mỗi khi bạn gọi fgetc, nó di chuyển một trong những nhân vật qua các tập tin. Vì vậy, bất cứ khi nào bạn gọi này, bạn đang incrementing con trỏ tập tin của một nhân vật. Và khi bạn fgetc một lần nữa, bạn di chuyển nó một nhân vật khác và một nhân vật khác và một nhân vật khác và một nhân vật khác. [Sinh viên câu hỏi, không thể hiểu] >> Đó - yeah. Nó là loại ma thuật này dưới mui xe. Bạn chỉ cần giữ incrementing qua. Tại thời điểm này, bạn có thể thực sự làm việc với một nhân vật. Vì vậy, làm thế nào chúng ta có thể in này ra đến màn hình, bây giờ không? Chúng tôi có thể sử dụng cùng một điều printf mà chúng tôi đã sử dụng trước. Mà chúng tôi đã sử dụng tất cả các học kỳ. Chúng ta có thể gọi printf, và chúng ta có thể vượt qua trong nhân vật như thế. Một cách khác để làm điều đó là thay vì sử dụng printf và phải làm điều này chuỗi định dạng, chúng tôi cũng có thể sử dụng một trong các chức năng khác. Chúng tôi có thể sử dụng fputc, in một ký tự lên màn hình, trừ khi chúng ta nhìn vào fputc - hãy để tôi thu nhỏ một chút. Chúng tôi nhìn thấy những gì tốt đẹp là nó có trong nhân vật mà chúng ta đọc ra bằng cách sử dụng fgetc, nhưng sau đó chúng ta phải cung cấp cho nó một dòng suối để in. Chúng tôi cũng có thể sử dụng chức năng putchar, mà sẽ đặt trực tiếp để ra tiêu chuẩn. Vì vậy, có một bó toàn bộ các tùy chọn khác nhau mà chúng ta có thể sử dụng cho việc in ấn. Họ đang tất cả trong thư viện I / O tiêu chuẩn. Bất cứ khi nào bạn muốn in - printf, theo mặc định, sẽ in với tiêu chuẩn đặc biệt ra khỏi dòng, là stdout đó. Vì vậy, chúng tôi chỉ có thể đề cập đến nó như là loại giá trị này ma thuật, thiết bị xuất chuẩn ở đây. Rất tiếc. Đặt dấu chấm phẩy bên ngoài. Này là rất nhiều thông tin mới funky, ở đây. Rất nhiều trong số này là rất thành ngữ, cảm giác rằng đây là mã được viết theo cách này chỉ vì nó sạch sẽ để đọc, dễ đọc. Có nhiều cách khác nhau để làm điều đó, nhiều chức năng khác nhau mà bạn có thể sử dụng, nhưng chúng ta có xu hướng chỉ cần làm theo các mô hình tương tự hơn và hơn. Vì vậy, không ngạc nhiên nếu bạn thấy mã như thế này đến một lần nữa và một lần nữa. Được rồi. Tại thời điểm này, chúng ta cần để phá vỡ trong ngày. Cảm ơn vì đã đến. Cảm ơn bạn đã cho xem nếu bạn đang trực tuyến. Và chúng ta sẽ thấy bạn vào tuần tới. [CS50.TV]