[Powered by Google Translate] [ნაწილი 5 - უფრო კომფორტული] [Rob Bowden - ჰარვარდის უნივერსიტეტი] [ეს არის CS50. - CS50.TV] მომწონს განაცხადა ჩემი ელ, არის ბევრი რამ შეგიძლიათ გამოიყენოთ გარდა ელექტრო რეალურად გავაკეთოთ პრობლემა კომპლექტი. ჩვენ გირჩევთ ამას ელექტრო მოწყობილობების მხოლოდ იმიტომ, რომ მაშინ ჩვენ შეგვიძლია უფრო მარტივად დაგეხმაროთ და ჩვენ ვიცით, როგორ ყველაფერი იმუშავებს. თუმცა, როგორც ერთი მაგალითი, სადაც შეგიძლიათ გააკეთოთ რამ, თუ, ვთქვათ, თქვენ არ გაქვთ უნდა ელექტრო მოწყობილობების ან გსურთ მუშაობა მეცნიერების ცენტრი სარდაფი - რაც რეალურად აქვთ ელექტრო ძალიან - თუ გსურთ მუშაობა სადმე. ერთი მაგალითი არ გინახავთ / მსმენია SSH? SSH ძირითადად ისევე ვუკავშირდები რაღაც. სინამდვილეში, სწორედ ახლა მე SSHed შევიდა ელექტრო მოწყობილობების. მე არასოდეს მუშაობა პირდაპირ ელექტრო. აქ არის ელექტრო და, თუ გადავხედავთ ქვემოთ აქ ხედავთ ამ IP მისამართზე. მე არასოდეს მუშაობა ელექტრო თვით; მე ყოველთვის მეტი iTerm2 ფანჯარა / ტერმინალის ფანჯარაში. შეგიძლია SSH რომ IP მისამართი, SSH jharvard@192.168.129.128. მახსოვს, რომ ნომერი ძალიან მარტივად იმიტომ რომ ასეთი ლამაზი ნიმუში. მაგრამ ეს იქნება შემეკითხებით ჩემი პაროლი, და ახლა მე ელექტრო მოწყობილობების. ძირითადად, ამ ეტაპზე, თუ გახსნა ტერმინალის შიგნით ელექტრო თვით, ამ ინტერფეისით, თუმცა თქვენ რომ მისი გამოყენება, არის ზუსტად იგივე როგორც ინტერფეისის მე გამოყენებით მეტი აქ, მაგრამ ახლა თქვენ SSHed. თქვენ არ SSH რომ ელექტრო მოწყობილობების. ერთი მაგალითი სხვა ადგილას შეგიძლიათ SSH რომ არის მე საკმაოდ დარწმუნებული გაქვთ იყოს - Oh. Bigger. ყველა თქვენგანს უნდა ჰქონდეს სტანდარტულად FAS ანგარიშების შესახებ FAS სერვერები. ჩემთვის, მინდა SSH to rbowden@nice.fas.harvard.edu. იგი აპირებს გთხოვოთ, რომ პირველად, და თქვენი პასუხები დადებითია. ჩემი დაგავიწყდათ უბრალოდ იქნება ჩემი FAS დაგავიწყდათ. და ახლა, მე SSHed to ლამაზი სერვერებზე და არაფერზე უკან არ დავიხევ მინდა აქ. ბევრი კლასების თქვენ შესაძლოა, ისევე როგორც 124, ვაპირებთ გაქვთ ატვირთეთ პერსონალის აქ რეალურად თქვენი პრობლემა კომპლექტი. მაგრამ ამბობენ თქვენ არ ხელმისაწვდომობის თქვენი მოწყობილობის. შემდეგ შეგიძლიათ გააკეთოთ რამ, როგორიცაა აქ იგი იტყვის - ეს არის მხოლოდ ჩვენი მონაკვეთის კითხვები. იგი მოგთხოვთ ამის გაკეთება წელს ელექტრო მოწყობილობების. ამის ნაცვლად მე მხოლოდ ამის შესახებ სერვერზე. მე ვაპირებ unzip რომ. პრობლემა იქნება, რომ თქვენ გამოიყენება გამოყენებით რაღაც gedit ან რასაც შიგნით ელექტრო მოწყობილობების. თქვენ არ გვექნება, რომ FAS სერვერზე. ეს ყველაფერი უბრალოდ იქნება ეს ტექსტური ინტერფეისით. ასე, რომ თქვენ შეიძლება არც ერთი, ვცდილობთ ვისწავლოთ ტექსტური რედაქტორი, რომელიც მათ აქვთ. მათ აქვთ ნანო. ნანო ჩვეულებრივ საკმაოდ მარტივი. თქვენ შეგიძლიათ გამოიყენოთ თქვენი ისრებით და ტიპის ნორმალურად. ასე რომ არ არის ძნელი. თუ გსურთ მიიღოთ მართლაც ლამაზი შეგიძლიათ გამოიყენოთ Emacs, რომელიც მე ალბათ არ უნდა გახსნა, რადგან ისიც კი არ ვიცით, როგორ დახურვა Emacs. კონტროლის X, საკონტროლო C? Yeah. ან შეგიძლიათ გამოიყენოთ Vim, რაც გამოვიყენო. და ა.შ. ეს ის თქვენი პარამეტრები. თუ არ გსურთ, რომ, ასევე, შეგიძლიათ, თუ გადავხედავთ manual.cs50.net-- Oh. On PC, შეგიძლიათ SSH გამოყენებით საბაღე, რაც თქვენ ვაპირებთ უნდა ჩამოტვირთოთ ცალკე. On Mac, შეგიძლიათ უბრალოდ იყოს გამოყენების ტერმინალის ან შეგიძლიათ ჩამოტვირთოთ iTerm2, რაც მოსწონს ლამაზი, ლამაზი ტერმინალი. თუ წასვლა manual.cs50.net დაინახავთ ბმული ჩასაწერი + +, რაც შეგიძლიათ გამოიყენოთ on PC. იგი საშუალებას გაძლევთ SFTP საწყისი ჩასაწერი + +, რომელიც ძირითადად SSH. რა ამ შევძლებთ თქვენ გააკეთოთ შეასწოროთ თქვენი ფაილი ადგილობრივად, და მაშინ, როცა მოისურვებთ მათი შენახვა, ის შენახვა nice.fas, სადაც შეგიძლიათ შემდეგ აწარმოებს მათ. და ექვივალენტი on Mac იქნება TextWrangler. ასე რომ გაძლევთ გავაკეთოთ იგივე. იგი საშუალებას გაძლევთ რედაქტირების ფაილი ადგილობრივად და მათი შენახვა nice.fas, სადაც შეგიძლიათ შემდეგ აწარმოებს მათ. ასე რომ, თუ თქვენ ოდესმე დავრჩებოდით გარეშე ელექტრო მოწყობილობების, თქვენ გაქვთ ეს პარამეტრები კიდევ თქვენი პრობლემა კომპლექტი. ერთი პრობლემა იქნება, რომ თქვენ არ აპირებს CS50 ბიბლიოთეკა რადგან nice.fas არ იყოს აქვს, რომ. თქვენ შეგიძლიათ ან ჩამოტვირთოთ CS50 ბიბლიოთეკა - არა მგონია, მე უნდა, რომ ამ ეტაპზე. თქვენ შეგიძლიათ ან ჩამოტვირთოთ CS50 ბიბლიოთეკა და კოპირება მეტი nice.fas, ან მე ვფიქრობ, ამ ეტაპზე ჩვენ არ ვიყენებთ მას აღარ ჩათვალა. ან თუ ჩვენ გავაკეთებთ, შეგიძლიათ ამ დროისათვის შეცვალოს იგი განსახორციელებლად ფუნქციებს CS50 ბიბლიოთეკა მაინც. ასე რომ არ უნდა იყოს, რომ ბევრი შეზღუდვა. სწორედ რომ. მე დაბრუნდებით ელექტრო ახლა, ჩვენ გავაკეთებთ ყველაფერს ელექტრო მოწყობილობების. ეძებს ჩვენს განყოფილებაში კითხვები, დასაწყისში, ისევე როგორც მე ვთქვი ჩემი ელ, ჩვენ უნდა ვილაპარაკოთ ერთი მოკლე თქვენ უნდა უყუროთ. ჩვენ გვყავს გადამისამართება & მილები და ეს სამი კითხვები. რომლის ნაკადი არ ფუნქციების მსგავსად printf წერენ იყოს? ამიტომ ნაკადი. რა არის ნაკადი? ნაკადი ძირითადად მოსწონს ეს მხოლოდ რამდენიმე - ეს კი არ წყაროს 1s და 0S. ნაკადი ის ითხოვს აქ არის სტანდარტული გარეთ. და ასე სტანდარტული გარეთ არის ნაკადი, რომ როდესაც წერთ კი როგორც ჩანს ეკრანზე. სტანდარტული გარეთ, რომელსაც ნაკადი, ეს იმას ნიშნავს, თქვენ უბრალოდ დაწერეთ 1s და 0S კი და სხვა ბოლოს სტანდარტი მხოლოდ ნათქვამია, რომ ნაკადი. უბრალოდ string of 1s და 0S. შეგიძლიათ მიწეროთ ნაკადს ან შეგიძლიათ წაკითხვის ნაკადს დამოკიდებულია რა ნაკადი რეალურად არის. დანარჩენი ორი წევრი ნაკადს არის სტანდარტული და სტანდარტული შეცდომა. სტანდარტი არის როდესაც თქვენ ჩვენგან GetString, ეს გელოდებათ შესაყვანად პერსონალი. ასე რომ გელით, სინამდვილეში ელოდება სტანდარტული წელს, რაც რეალურად რა თქვენ, როდესაც თქვენ აკრიფეთ კლავიატურაზე. თქვენ აკრეფით შევიდა სტანდარტული სისტემაში სტანდარტული შეცდომა ძირითადად ეკვივალენტი სტანდარტის out, მაგრამ სპეციალიზებული, რომ როდესაც თქვენ ბეჭდვა სტანდარტული შეცდომა, თქვენ უნდა მხოლოდ ბეჭდვა შეცდომის შეტყობინებები, რომ ასე რომ თქვენ შეგიძლიათ დიფერენცირება შორის რეგულარული შეტყობინებები დაბეჭდილი რომ ეკრანზე წინააღმდეგ შეცდომის შეტყობინებები დამოკიდებულია თუ არა ისინი წავიდნენ სტანდარტული გამოსვლა ან სტანდარტული შეცდომა. ფაილები ძალიან. სტანდარტული out, სტანდარტების, და სტანდარტული შეცდომა მხოლოდ სპეციალური ნაკადს, მაგრამ ნამდვილად ნებისმიერი ფაილი, როდესაც თქვენ გახსნა ფაილი, ის ხდება ნაკადი ბაიტი სადაც შეგიძლიათ მხოლოდ წაკითხვის, რომ ნაკადი. თქვენ, ამისთვის დიდი ნაწილი, უბრალოდ ვფიქრობ ფაილი, როგორც ნაკადი bytes. მერე რა ნაკადს ვერ ვწერ იყოს? სტანდარტული გარეთ. რა სხვაობაა> და >>? ხომ არავის უყუროთ ვიდეო წინასწარ? Okay. > იქნება თუ როგორ გადამისამართება შევიდა ფაილი და >> ასევე აპირებს გადამისამართება გამომავალი შევიდა ფაილი მაგრამ ნაცვლად აპირებს დამატება ფაილი. მაგალითად, ვთქვათ მე ემართება აქვს dict უფლება აქ, და მხოლოდ პერსონალის შიგნით dict არის კატა, კატა, ძაღლი, თევზი, ძაღლი. ერთი ბრძანება, რომ თქვენ გაქვთ ბრძანებათა ზოლი არის კატა, რომელიც მხოლოდ აპირებს ბეჭდვა რა ფაილი. ამიტომ როდესაც ვამბობ, რომ CAT dict, ის აპირებს ბეჭდვა კატა, კატა, ძაღლი, თევზი, ძაღლი. ეს იყო კატა აკეთებს. ეს იმას ნიშნავს, რომ დაბეჭდილი სტანდარტული გარეთ კატა, კატა, ძაღლი, თევზი, ძაღლი. თუ მე მინდა ნაცვლად გადამისამართება, რომ ფაილი, შემიძლია> და გადამისამართება მას რასაც ფაილი. მე მოვუწოდებ ფაილი ფაილის. ახლა თუ ls, მე ვხედავ მე ახალი ფაილი სახელად ფაილი. და თუ გავხსნა ეს, ის აპირებს ზუსტად რა cat დააყენა ბრძანებათა ზოლს. ახლა, თუ რომ ერთხელ, მაშინ იგი ხდება გადამისამართება გამომავალი შევიდა ფაილი, და მე ვაპირებ აქვს იგივე ზუსტი რამ. ასე რომ ტექნიკურად, იგი მთლიანად overrode, რაც ჩვენ გვქონდა. ჩვენ დავინახავთ, თუ შევცვალო dict, მე ამოიღეს ძაღლი. ახლა თუ ჩვენ cat dict შევიდა ფაილის ერთხელ, ჩვენ ვაპირებთ აქვს ახალი ვერსია ძაღლით ამოიღეს. ამიტომ იგი მთლიანად overrides იგი. სამაგიეროდ, თუ ჩვენ ვიყენებთ >>, ის აპირებს დამატება ფაილი. ახლა გახსნის ფაილი, ჩვენ ვხედავთ ჩვენ ცოტა ხნის წინ იგივე დაბეჭდილი ორჯერ რადგან ეს იყო იქ ერთხელ, მაშინ ჩვენ დაემატება ორიგინალური. ასე რომ რა> და >> გავაკეთოთ. ამჯამად შემდეგი ერთი კითხვა - ეს არ ეკითხება ამის შესახებ. მეორე, რომ ჩვენ გვაქვს არის <, რომელიც თუ> გადამისამართებების სტანდარტული out, <იქნება გადამისამართება სტანდარტული სისტემაში ვნახოთ, თუ ჩვენ გვაქვს მაგალითი. მე შეგიძლიათ დაწეროთ ერთი რეალური სწრაფი. ავიღოთ ნებისმიერი ფაილი, hello.c. შედარებით მარტივია ფაილი. მე უბრალოდ მიღების სიმებიანი და შემდეგ ბეჭდვა "Hello" რასაც სიმებიანი უბრალოდ შევიდა იყო. ასე რომ მიესალმები და შემდეგ. / Hello. ახლა კი რითაც ჩემთვის შესვლის რაღაც, რაც იმას ნიშნავს, რომ ის ელოდება on რამ უნდა შევიდა სტანდარტული სისტემაში ასე რომ შევა რასაც მინდა შევიდა სტანდარტული შემოსული ჩვენ უბრალოდ აპირებს მიესალმები, რობ! მაშინ ის დაბეჭდვის სტანდარტული გარეთ Hello, რობ! თუ. / მიესალმები და შემდეგ გადამისამართება, ახლა თქვენ შეგიძლიათ მხოლოდ გადამისამართება ფაილიდან. ასე რომ, თუ მე ზუსტად ზოგიერთ ფაილი, TXT, და მე ზუსტად რობ, თუ აწარმოებს მიესალმები და შემდეგ გადამისამართება ფაილი txt შევიდა. / Hello, ის აპირებს მიესალმები, რობ! დაუყოვნებლივ. როდესაც იგი პირველი იღებს GetString და ის ელოდება სტანდარტული წელს, სტანდარტი აღარ ელოდება ხელს კლავიატურაზე მონაცემთა მისაღებად შევიდა. სამაგიეროდ, ჩვენ გადამისამართებულ სტანდარტების წაკითხვის ფაილი txt. და ამიტომ აპირებს წაკითხვის ფაილი txt, რომელიც მხოლოდ ხაზის რობ, და მაშინ იგი აპირებს ბეჭდვა Hello, რობ! და თუ მინდოდა, მე ვერ გააკეთოს. / მიესალმები ხაზვის 2>, რომ გადამისამართება სტანდარტული შეცდომა. ასე რომ, თუ რამე წავიდა სტანდარტული შეცდომა, ის არ მიიღოთ ამოქმედებული txt2. მაგრამ შეამჩნევს თუ 2>, მაშინ ეს ჯერ კიდევ ბეჭდვის Hello, რობ! ბრძანების ხაზი რადგან მე მხოლოდ გადამისამართება სტანდარტული შეცდომა, მე არ გადამისამართება სტანდარტული გარეთ. სტანდარტული შეცდომა და სტანდარტული გარეთ განსხვავებულია. თუ უნდოდა რეალურად ჩაწერის სტანდარტული შეცდომა, მაშინ მე ვერ შეცვლის ეს უნდა იყოს fprintf to stderr. ამიტომ printf, ჩვეულებრივ, ბეჭდავს სტანდარტული გარეთ. თუკი მინდა ბეჭდვა სტანდარტული შეცდომა ხელით, მაშინ მე უნდა გამოვიყენოთ fprintf და დააკონკრეტა, თუ რა მინდა ბეჭდვა. თუ ნაცვლად მე fprintf stdout, მაშინ ეს ძირითადად ექვივალენტი printf. მაგრამ fprintf სტანდარტული შეცდომა. ახლა, თუ გადამისამართება ამ შევიდა txt2, Hello, რობ! კვლავ მიღების დაბეჭდილი ბრძანებათა ზოლს რადგან არც დაბეჭდილი სტანდარტული შეცდომა და მე მხოლოდ გადამისამართება სტანდარტული გარეთ. თუ მე ახლა გადამისამართება სტანდარტული შეცდომა, ახლა კი ვერ დაბეჭდილი და txt2 იქნება Hello, რობ! ახლა, თქვენ შეგიძლიათ ამობეჭდოთ თქვენი ფაქტობრივი შეცდომების სტანდარტული შეცდომა და ბეჭდვა თქვენი რეგულარული შეტყობინებები სტანდარტული გარეთ. და ამრიგად, როდესაც თქვენ აწარმოებს თქვენი პროგრამის, შეგიძლიათ გაუშვათ როგორც. / მიესალმები ამ ტიპის 2> ისე, რომ თქვენი პროგრამის მიღებას აპირებს ნორმალურად, მაგრამ ნებისმიერი შეცდომის შეტყობინებები, რომ თქვენ შეგიძლიათ შეამოწმოთ მოგვიანებით თქვენს შეცდომების ლოგი, ასე შეცდომები, და შემდეგ შეხედეთ მოგვიანებით და თქვენი შეცდომები ფაილი ექნება ნებისმიერი შეცდომები, რაც მოხდა. კითხვები? ბოლო ერთი მილსადენი, რომელიც შეგიძლიათ წარმოიდგინოთ, რომ როგორც აღების სტანდარტული აქედან ერთი ბრძანება და რაც სტანდარტი მომდევნო ბრძანება. მაგალითად აქ არის გამოძახილი არის command line რამ რომ მხოლოდ აპირებს echo რასაც მე, როგორც მისი არგუმენტი. მე არ დააყენოს შეთავაზებები. ეხო blah, blah, blah მხოლოდ აპირებს ბეჭდვა blah, blah, blah. მანამდე, როდესაც მე ვუთხარი, დააყენოს რობ შევიდა txt ფაილი რადგან მე შემიძლია მხოლოდ გადამისამართება txt ფაილი, ნაცვლად, / თუ echo რობ და მაშინ მილის იგი. / Hello, რომელიც ასევე იგივე ტიპის რამ. ეს ხდება გამოშვებულ ამ ბრძანების ეხო რობ, და იყენებს მას, როგორც შეყვანის მიზნით. / hello. თქვენ შეგიძლიათ ვფიქრობ, რომ ეს პირველი გადამისამართება ეხო რობ შევიდა ფაილი და შემდეგ წვლილის შეტანა. / მიესალმები რომ ფაილი, რომელიც იყო მხოლოდ outputted. მაგრამ ეს ხდება დროებითი ფაილის გარეთ Picture. კითხვები რომ? შემდეგი შეკითხვა აპირებს ჩაერთოს ამ. რა მილსადენის იქნებ გამოიყენოთ მოძიების პუნქტების უნიკალური სახელების ფაილი სახელად names.txt? ბრძანებები ჩვენ ვაპირებთ გინდათ გამოიყენოთ აქ არის უნიკალური, ასე რომ uniq და შემდეგ WC. ამის გაკეთება შეგიძლიათ კაცს uniq რეალურად შევხედოთ რა, რომ ასეა, და ეს მხოლოდ აპირებს გავფილტროთ მიმდებარე შესატყვისი ხაზები საწყისი შეყვანის. და კაცი WC აპირებს ბეჭდვა სტრიქონების გადატანით, სიტყვა, და ბიტიანი ითვლის თითოეული ფაილი. და ბოლოს ერთი ჩვენ ვაპირებთ გინდათ გამოიყენოთ არის დახარისხების, რომელიც აპირებს მხოლოდ დასალაგებლად ხაზების txt ფაილი. თუ მე რაღაც txt ფაილი, names.txt და ეს რობ, ტომი, იოსები, Tommy, იოსები, RJ, რობ, რა მინდა აქ არის იპოვოს პუნქტების უნიკალური სახელები ამ ფაილის. მერე რა უნდა იყოს პასუხი? >> [სტუდენტი] 4. >> Yeah. ეს უნდა იყოს 4 წლიდან რობ, ტომი, იოსები, RJ ერთადერთი უნიკალური სახელები ამ ფაილის. პირველი ნაბიჯი, თუ უბრალოდ სიტყვის იმედი names.txt, ამ ფაქტობრივად მეუბნებოდა ყველაფერი. ეს არის რეალურად ბეჭდვის - ვნახოთ, კაცი WC - newlines, სიტყვა, და ბიტიანი რაოდენობა. თუ მე მხოლოდ აინტერესებს ხაზები, მაშინ მე შემიძლია უბრალოდ WC-მ names.txt. ასე რომ ნაბიჯი 1. მაგრამ მე არ მინდა, რომ WC-მ names.txt რადგან names.txt უბრალოდ შეიცავს ყველა სახელები, და მინდა გავფილტროთ ნებისმიერი არასამთავრობო უნიკალური მიიჩნიეს. ასე რომ, თუ uniq names.txt, რომ არ საკმაოდ მომეცი რა მინდა რადგან დუბლირებული სახელები დღესაც არსებობს. რატომ არის, რომ? რატომ uniq არ აკეთებს რაც მე მინდა? [სტუდენტი] დუბლიკატები არ არის [inaudible] >> Yeah. დამახსოვრება man გვერდი uniq ამბობს ფილტრაციის მიმდებარე დამთხვევა ხაზები. ისინი არ მიმდებარე, ასე რომ არ გავფილტროთ მათ. თუ მე დასალაგებლად მათ პირველი, დალაგება names.txt გეგმავს ყველა დუბლიკატი ხაზები ერთად. ახლა დალაგების names.txt არის, რომ. მე ვაპირებ გინდათ გამოიყენოთ, რომ როგორც შეყვანის to uniq, რომელიც | uniq. რომელიც მაძლევს ჯოზეფ, RJ, რობ, ტომი, და მინდა, რომ როგორც შეყვანის to WC-მ, რომელიც აპირებს მომეცი 4. როგორც ეს ამბობს აქ, რა მილსადენის იქნებ გამოვიყენოთ? შეგიძლიათ ბევრი რამ, როგორიცაა გამოყენებით სერია ბრძანებები სადაც თქვენ გამოიყენოს გამომავალი ერთი ბრძანება, როგორც შეყვანის შემდეგ ბრძანება. შეგიძლიათ ბევრი რამ, ბევრი ჭკვიანი რამ. კითხვები? Okay. სწორედ ეს მილები და გადამისამართება. ახლა ჩვენ რა იქნება ნამდვილი პერსონალის, კოდირების პერსონალი. შიგნით ამ PDF, თქვენ ნახავთ ამ ბრძანების და თქვენ სურთ ამ ბრძანების თქვენს ელექტრო მოწყობილობების. wget არის ბრძანება მხოლოდ მიღების რაიმე ინტერნეტი, ძირითადად, ასე wget და ამ URL. თუ წავიდა ამ URL თქვენს ბრაუზერში, ეს იქნებოდა ჩამოტვირთოთ რომ ფაილი. მე უბრალოდ დაწკაპავთ მას, ასე რომ გადმოწერილი ფაილი ჩემთვის. მაგრამ წერილობით wget რომ რამ შიგნით ტერმინალში უბრალოდ აპირებს ჩამოტვირთოთ იგი თქვენი ტერმინალში. მაქვს section5.zip, და თქვენ გსურთ unzip section5.zip, რომელიც აპირებს მოგცემთ საქაღალდეში მოუწოდა section5, რომელიც აპირებს ყველა ფაილი ჩვენ ვაპირებთ იყოს გამოყენებით დღეს შიგნით მას. როგორც ამ პროგრამების 'ფაილის სახელები ვარაუდობენ, ისინი ცოტა buggy, ასე რომ თქვენი მისიაა გაერკვნენ, თუ რატომ იყენებს GDB. ამჯამად ყველას არ მათ გადმოწერილი / ვიცით თუ როგორ უნდა მათ გადმოწერილი თავიანთ ელექტრო? Okay. Running ./buggy1, ის იტყვის სეგმენტაცია ბრალია (ბირთვი dumped), რომელიც ნებისმიერ დროს თქვენ მიიღებთ segfault, ეს ცუდი რამ. რა გარემოებებში იღებთ segfault? [სტუდენტი] Dereferencing null მაჩვენებელი. >> Yeah. ასე რომ არის ერთი მაგალითი. Dereferencing null კურსორი თქვენ აპირებს მიიღოს segfault. რა segfault ნიშნავს, თქვენ ეხება მეხსიერების თქვენ არ უნდა ეხება. ამიტომ dereferencing null მაჩვენებელი არის ეხება მისამართი 0, და ძირითადად, ყველა კომპიუტერი დღესდღეობით ამბობენ, რომ მისამართი არის 0 მეხსიერების თქვენ არ უნდა ეხება. ასე ამიტომ dereferencing null მაჩვენებელი შედეგების segfault. როდესაც თქვენ ემართება არ ვრთავ კურსორი, მაშინ მას აქვს ნაგვის ღირებულება, და ამრიგად, როდესაც თქვენ ცდილობენ dereference იგი, ყველა ალბათობა თქვენ ეხება მეხსიერება რომ შუა არსად. თუ მოხდება მისაღებად გაუმართლა და ნაგვის ღირებულება მოხდა აღვნიშნო, რომ სადმე დასტის ან რაღაც, მაშინ, როდესაც თქვენ dereference რომ მომცეთ, რომელიც თქვენ არ ინიციალიზდება, არაფერი წავა არასწორია. მაგრამ თუ ეს მიუთითებს, ვთქვათ, სადღაც შორის დასტის და ბევრი, ან ის მიუთითებს მხოლოდ სადღაც, რომ არ იყო გამოყენებული თქვენი პროგრამა არ არის, მაშინ თქვენ ეხება მეხსიერების თქვენ არ უნდა ეხება და თქვენ segfault. როდესაც ვწერთ რეკურსიული ფუნქცია და იგი recurses ძალიან ბევრი ჯერ და თქვენი დასტის იზრდება ძალიან დიდია და დასტის collides შევიდა რამ რომ იგი არ უნდა colliding ერთად, თქვენ ეხება მეხსიერების თქვენ არ უნდა ეხება, ასე რომ თქვენ segfault. სწორედ ეს არის segfault. ასევე ამავე მიზეზით, რომ თუ თქვენ გაქვთ სიმებიანი მოსწონს - მოდით დავუბრუნდეთ წინა პროგრამა. In hello.c--I'm just ვაპირებთ რაღაც. char * s = "Hello world!"; თუ გამოვიყენო * s = რაღაც ან s [0] = 'X'; ასე რომ Hello,. / Hello, რატომ, რომ segfault? რატომ ამ segfault? რას ველოდოთ მოხდეს? თუ წავიდოდი printf ("% s \ n", S); რას ველოდოთ უნდა დაიბეჭდოს? [სტუდენტი] X hello. >> Yeah. პრობლემა ისაა, რომ როდესაც თქვენ გამოაცხადოს სიმებიანი მოსწონს, s არის მაჩვენებელი, აპირებს გააგრძელოს დასტის, და რა არის მიუთითებს ეს ტექსტი, რომელიც შეიცავს წაუკითხავი მეხსიერება. ასე რომ მხოლოდ სახელი, წაუკითხავი მეხსიერება, თქვენ უნდა მიიღოს იდეა რომ თუ თქვენ ცდილობენ შეცვლის რა წაუკითხავი მეხსიერება, თქვენ აკეთებთ რაღაც არ უნდა აკეთებს მეხსიერების და თქვენ segfault. ეს არის რეალურად დიდი სხვაობა char * s და char s []. ასე რომ char s [], ახლა ეს კონტექსტი იქნება ჩაიცვი დასტის, და დასტის არ არის წაუკითხავი, რაც იმას ნიშნავს, რომ ეს უნდა იმუშაოს შესანიშნავად ჯარიმა. ეს სულაც. გახსოვდეთ, რომ როდესაც გავაკეთო char * s = "Hello World!", S თავად არის დასტის მაგრამ ჯერ ქულები სადმე სხვაგან, და რომ სხვაგან ხდება უნდა წაიკითხოთ მხოლოდ. მაგრამ char s [] არის მხოლოდ რაღაც Stack. ასე რომ კიდევ ერთი მაგალითი segfault ხდება. ჩვენ ვნახეთ, რომ ./buggy1 შედეგად segfault. თეორიულად, თქვენ არ უნდა შევხედოთ buggy1.c დაუყოვნებლივ. სამაგიეროდ, ჩვენ შევხედოთ ის მეშვეობით GDB. გაითვალისწინეთ, რომ როდესაც თქვენ სეგმენტაცია ბრალია (ბირთვი dumped), თქვენ ამ ფაილის აქ მოუწოდა core. თუ ჩვენ ls-l, ვნახავთ, რომ ძირითადი ჩვეულებრივ საკმაოდ დიდი ფაილი. ეს არის ბაიტების რაოდენობას of ფაილი, ასე რომ ჰგავს ეს 250-რაღაც kilobytes. მიზეზი არის ის, რომ რაც core ნაგავსაყრელი რეალურად არის როდესაც თქვენი პროგრამის დამსხვრევაზე, სახელმწიფოს მეხსიერებაში პროგრამა მხოლოდ იღებს გადაწერა და pasted შევიდა ამ ფაილის. იგი იღებს dumped შევიდა, რომ ფაილი. ეს პროგრამა, ხოლო ეს იყო გაშვებული, მოხდა აქვს მეხსიერების გამოყენების დაახლოებით 250 kilobytes, და ისე, რომ ის, რაც მიიღო dumped ამ ფაილის. ახლა თქვენ შეგიძლიათ შეხედოთ რომ ფაილი თუ ჩვენ GDB buggy1 core. ჩვენ შეგვიძლია უბრალოდ GDB buggy1, და რომელიც უბრალოდ დავიწყოთ GDB რეგულარულად, გამოყენებით buggy1 როგორც მისი შეყვანის ფაილი. მაგრამ თუ GDB buggy1 Core, მაშინ ეს კონკრეტულად აპირებს დავიწყოთ GDB მიერ ეძებს, რომ ძირითადი ფაილი. და თქვენ ამბობდა buggy1 საშუალებით GDB იცის, რომ ძირითადი ფაილის მოდის buggy1 პროგრამა. ამიტომ GDB buggy1 ძირითადი აპირებს დაუყოვნებლივ მიგვიყვანს იქ, სადაც პროგრამის მოხდა შეწყვიტოს. ჩვენ ვხედავთ, აქ პროგრამის წყდება ერთად სიგნალი 11, სეგმენტირება ბრალია. ჩვენ არ უნდა დაინახოს ხაზი ასამბლეის, რაც ალბათ არ არის ძალიან გამოსადეგი. მაგრამ თუ თქვენ აკრიფოთ BT ან backtrace, რომ იქნება ფუნქცია რომ გვაძლევს სიაში ჩვენი დღევანდელი დასტის ფარგლებში. ამიტომ backtrace. როგორც ჩანს ჩვენ მხოლოდ ორი დასტის ფარგლებში. პირველი არის ჩვენი მთავარი დასტის ჩარჩო, და მეორე არის დასტის ჩარჩო ამ ფუნქციას, რომ ჩვენ არ უნდა იყოს, რომელიც ჰგავს ჩვენ მხოლოდ ასამბლეის კოდი. მოდით დავუბრუნდეთ ჩვენს ძირითად ფუნქციას, და ამისათვის ჩვენ შეგვიძლია გავაკეთოთ ჩარჩოს 1, და მე ვფიქრობ, ჩვენ შეგვიძლია გავაკეთოთ ასევე ქვემოთ, მაგრამ მე თითქმის არასდროს არ Down - ან up. Yeah. ზემოთ და ქვემოთ. Up მოაქვს თქვენ ერთი დასტის ჩარჩო, ქვემოთ მოაქვს თქვენ ქვემოთ დასტის ჩარჩო. მე ტენდენცია არასდროს არ გამოიყენოთ რომ. მე მხოლოდ კონკრეტულად ამბობენ ჩარჩოს 1, რომელიც წასვლა ჩარჩო შეაფასა 1. კარკასი 1 აპირებს მიგვიყვანს შევიდა ძირითადი დასტის ჩარჩო, და ეს ამბობს უფლება აქ ხაზი კოდი ჩვენ მოხდეს იყოს. თუ გვინდოდა რამდენიმე ხაზი კოდი, შეიძლება ითქვას სია, და რომ აპირებს მოგვცეს ყველა ხაზი კოდი გარშემო. ხაზი ჩვენ segfaulted ზე იყო 6: თუ (strcmp ("CS50 კლდეები", argv [1]) == 0). თუ ეს არ არის აშკარა არ არის, თქვენ უკვე შეგიძლიად პირდაპირ აქ მხოლოდ ფიქრობს, თუ რატომ segfaulted. მაგრამ ჩვენ შეგვიძლია მას ერთი ნაბიჯით შემდგომი და აცხადებენ, "რატომ argv [1] segfault?" მოდით ბეჭდვითი argv [1], და როგორც ჩანს ეს 0x0, რომელიც null მაჩვენებელი. ჩვენ strcmping CS50 კლდეები და null, და ისე, რომ აპირებს segfault. და რატომ არის argv [1] null? [სტუდენტი] იმიტომ, რომ ჩვენ არ მისცა მას ნებისმიერი ბრძანების ხაზი არგუმენტები. Yeah. ჩვენ არ მისცეს მას ნებისმიერი ბრძანების ხაზი არგუმენტები. ამიტომ ./buggy1 მხოლოდ აპირებს argv [0] იყოს ./buggy1. ეს არ აპირებს argv [1], ისე, რომ აპირებს segfault. მაგრამ თუ, ნაცვლად, მე უბრალოდ CS50, იგი აპირებს ამბობენ თქვენ D იმიტომ, რომ ის, რაც მას უნდა გავაკეთოთ. ეძებს buggy1.c, ის უნდა ბეჭდვა "თქვენ მიიღეთ D" - თუ argv [1] არ არის "CS50 კლდეები", "თქვენ D", სხვაგან "თქვენ!" ასე რომ, თუ ჩვენ გვინდა, ჩვენ გვჭირდება ამ შედარების როგორც ჭეშმარიტი, რაც იმას ნიშნავს, რომ ადარებს, რათა 0. ამიტომ argv [1] უნდა იყოს "CS50 კლდეები". თუ გსურთ, რომ ბრძანების სტრიქონში, თქვენ უნდა გამოვიყენოთ \ გაქცევა სივრცეში. ამიტომ CS50 \ კლდეები და თქვენ მიიღებთ? თუ არ გააკეთებს backslash, რატომ ამ არ იმუშავებს? [სტუდენტი] ეს ორი განსხვავებული არგუმენტები. >> Yeah. Argv [1] იქნება CS50 და argv [2] იქნება კლდეები. Okay. ახლა ./buggy2 აპირებს segfault ერთხელ. იმის ნაცვლად, რომ გახსნის ეს მისი ძირითადი ფაილი, ჩვენ უბრალოდ გახსენით buggy2 პირდაპირ, ასე GDB buggy2. ახლა თუ ჩვენ მხოლოდ აწარმოებს ჩვენი პროგრამა, მაშინ იგი აპირებს ამბობენ პროგრამა მიღებულია სიგნალი SIGSEGV, რაც segfault სიგნალი, და ეს არის, სადაც ეს მოხდა მოხდეს. ეძებს ჩვენს backtrace, ჩვენ ვხედავთ, რომ ერთმანეთი ფუნქცია oh_no, რომელიც იწვევს ფუნქციის Dinky, რომელიც იწვევს ფუნქციის binky, რომელსაც სხვადასხვა დროს ძირითადი. ჩვენ შეგვიძლია აგრეთვე არგუმენტები ამ ფუნქციების. არგუმენტი Dinky და binky იყო 1. თუ ჩვენ სიაში ფუნქცია oh_no, ჩვენ ვხედავთ, რომ oh_no უბრალოდ აკეთებს char ** s = NULL; * S = "BOOM"; რატომ უნდა, რომ ვერ? [სტუდენტი] თქვენ არ შეგიძლიათ dereference null მაჩვენებელი? >> Yeah. ეს მხოლოდ ამბობდა s არის NULL, მიუხედავად, თუ ეს მოხდება, რომ იყოს char **, რომელიც, იმის მიხედვით, თუ როგორ ინტერპრეტაცია, ეს შეიძლება იყოს მომცეთ მომცეთ სიმებიანი ან მასივი სტრიქონები. ეს s არის NULL, ამიტომ * s არის dereferencing null მაჩვენებელი, და ა.შ. ამ აპირებს მისაწოდებლად. ეს არის ერთ სწრაფი გზები შეგიძლიათ შესაძლოა segfault. უბრალოდ გამოცხადების null კურსორი და დაუყოვნებლივ segfaulting. რაც oh_no აკეთებს. თუ ჩვენ ახვიდეთ ერთ ჩარჩოში, მაშინ ჩვენ ვაპირებთ შეღწევას ფუნქცია მოუწოდა oh_no. მე უნდა გავაკეთოთ, რომ ქვემოთ. თუ არ შევა ბრძანება და თქვენ უბრალოდ დააჭირეთ ერთხელ, ის უბრალოდ ვიმეორებ წინა ბრძანება რომ თქვენ გაიქცა. ჩვენ ჩარჩოში 1. ლისტინგ ამ ჩარჩოს, ჩვენ ვხედავთ აქ არის ჩვენი ფუნქცია. შეგიძლიათ მოხვდა სიაში თავიდან, ან შეგიძლიათ გააკეთოთ სიაში 20 და მას სიაში მეტი. ფუნქციის Dinky ამბობს თუ არის 1, შემდეგ კი oh_no ფუნქცია, სხვაგან წასვლა slinky ფუნქცია. და ვიცით, მე კი 1 რადგან ჩვენ არ უნდა დაინახოს აქ რომ Dinky დაურეკეს არგუმენტი 1. ან შეგიძლიათ უბრალოდ ამობეჭდოთ მე და ის იტყვის მე არის 1. ჩვენ ამჟამად Dinky და, თუ ჩვენ კიდევ ერთ ჩარჩოში, ჩვენ ვიცით, ჩვენ დასრულდება მდე binky. Up. ახლა ჩვენ წელს binky. ლისტინგ ამ ფუნქციის - სიის ადრე ნახევარი მოჭრილი me off - დაიწყო off თითქოს მე არის 0, მაშინ ჩვენ ვაპირებთ ეძახით oh_no, სხვას მოვუწოდებ Dinky. ჩვენ ვიცით, მე ვიყავი 1, ასე რომ მოუწოდა Dinky. და ახლა ჩვენ უკან მთავარ და ძირითად მხოლოდ იქნება int i = RAND ()% 3; რომ მხოლოდ აპირებს მოგცემთ შემთხვევითი ნომერი, რომელიც არის ან 0, 1, ან 2. ეს ვაპირებ მოვუწოდო binky რომ ნომერი, და ეს დაბრუნდება 0. ეძებს ამ, უბრალოდ გავლით პროგრამა ხელით გარეშე გაშვებული მაშინვე, თქვენ მითითებული შესვენების ადგილამდე მთავარი, რაც იმას ნიშნავს, რომ როდესაც ჩვენ აწარმოებს პროგრამა თქვენი პროგრამა ეშვება მდე სანამ ჰიტები შესვენების წერტილი. ასე რომ გაშვებული პროგრამა, იგი აწარმოებს და მაშინ მოხვდა მთავარი ფუნქცია და შეწყვიტოს გაშვებული. ახლა ჩვენ შიგნით ძირითადი და ნაბიჯი ან მომდევნო აპირებს მიგვიყვანს შემდეგი ხაზი კოდი. ამის გაკეთება შეგიძლიათ ნაბიჯი ან მომდევნო. Hitting მომდევნო, მე ახლა უკვე მითითებული RAND ()% 3, ასე რომ ჩვენ შეგვიძლია ბეჭდვა ღირებულება i, და ეს იტყვის მე არის 1. ახლა კი არ აქვს მნიშვნელობა, თუ არა ჩვენ ვიყენებთ შემდეგი ან ნაბიჯი. ვფიქრობ ეს მნიშვნელოვანი წელს ადრე, მაგრამ ჩვენ გვინდა გამოვიყენოთ შემდეგი. თუ ჩვენ ვიყენებთ ნაბიჯი, ჩვენ დახევას შევიდა ფუნქცია, რაც იმას ნიშნავს, შევხედოთ რეალურ რამ რომ ხდება შიგნით binky. თუ ჩვენ ვიყენებთ შემდეგი, მაშინ ეს იმას ნიშნავს, წავიდეს მეტი ფუნქცია და უბრალოდ წასვლა შემდეგი ხაზი კოდი ჩვენი მთავარი ფუნქცია. სწორედ აქ, ამ ხაზის ვიყავი, სადაც ეს განაცხადა RAND ()% 3; თუ წავიდოდი ნაბიჯი, ეს იქნებოდა წასვლას განხორციელების RAND და შეხედეთ, რა ხდება იქ, და მე ვერ დაიხევს მეშვეობით RAND ფუნქცია. მაგრამ მე არ აინტერესებს RAND ფუნქცია. მინდა წასვლა შემდეგი ხაზი კოდი მთავარ, ისე გამოიყენოს შემდეგი. მაგრამ ახლა მე ზრუნავენ binky ფუნქცია, ასე რომ მინდა დახევას შევიდა, რომ. ახლა მე binky. პირველი ხაზი კოდი თქმას თუ (i == 0), მე ნაბიჯი, ჩვენ ვხედავთ ჩვენ დასრულდება მდე საათზე Dinky. თუ ჩვენ სიაში რამ, ჩვენ ვხედავთ, რომ ეს არის გადამოწმებული i = 0. მე არ ტოლია 0, ასე რომ წავიდა სხვას მდგომარეობა, რომელიც ვაპირებ მოვუწოდო Dinky (I). შესაძლოა დაბნეული. თუ თქვენ უბრალოდ შეხედეთ ამ ხაზების პირდაპირ, თქვენ ალბათ ფიქრობთ, თუ (i == 0), okay, მაშინ მე მივიღე ნაბიჯი და ახლა მე ზე Dinky (I), თქვენ ალბათ ფიქრობთ, რომ უნდა ნიშნავდეს i = 0 ან რაღაც. პოსტები უბრალოდ იმას ნიშნავს, რომ იგი დარწმუნებულია, მას შეუძლია გამყარებაში უშუალოდ ხაზის Dinky (I). იმიტომ, რომ მე არ 0, შემდეგი ნაბიჯი არ აპირებს დასრულდება სხვაგან. Else არ არის ხაზზე ის აპირებს შეჩერება. უბრალოდ აპირებს მისვლას შემდეგი ხაზი მას შეუძლია რეალურად შეასრულოს, რომელიც Dinky (I). Stepping შევიდა Dinky (I), ჩვენ ვხედავთ, თუ (i == 1). ჩვენ ვიცით i = 1, ასე რომ, როდესაც ჩვენ ნაბიჯი, ჩვენ ვიცით ჩვენ ვაპირებთ დასრულდება up in oh_no იმიტომ, რომ მე = 1 მოუწოდებს ფუნქცია oh_no, რომელიც შეგიძლიათ დახევას შევიდა, რომელიც აპირებს მითითებული char ** s = to null და დაუყოვნებლივ "BOOM". და მაშინ რეალურად შევხედავთ განხორციელების buggy2, ამ, მე მხოლოდ მიღების შემთხვევითი ხმების - 0, 1, ან 2 - დარეკვის binky, რომელიც თუ არის 0 ის მოუწოდებს oh_no, სხვას ის მოუწოდებს Dinky, რომელიც მოდის აქ. თუ მე არის 1, Call oh_no, სხვას მოვუწოდებ slinky, რომელიც მალე აქ, თუ არის 2, მოვუწოდებთ oh_no. ისიც კი არ ფიქრობს, რომ ეს გზა - ვინმეს ვხედავთ გზას მიღების ამ პროგრამა, რომელიც არ segfault? იმის გამო, რომ მანამ, სანამ მე გავიგე რამე, თუ არის 0, თქვენ მაშინვე segfault, სხვაგან მიდიხარ ფუნქცია რომელიც თუ არის 1 თქვენ segfault, სხვაგან მიდიხარ ფუნქცია აქ თუ არის 2 თქვენ segfault. ასე რომ არ აქვს მნიშვნელობა, თუ რას აკეთებთ, თქვენ segfault. ვფიქრობ ერთი გზა აფიქსირებს იქნებოდა ნაცვლად აკეთებს char ** s = NULL, თქვენ შეიძლება malloc ფართი რომ სიმებიანი. ჩვენ შეიძლება არ malloc (sizeof) - sizeof რა? [სტუდენტი] (char) * 5? >> საერთოდ ჩანს უფლება? მე თუ ვთქვათ ამ იმუშავებს თუ რეალურად გაიქცა, მაგრამ ეს არ რა მე ეძებს. შეხედეთ გაცნობის s. მოდით დაამატოთ int *, ასე int * x. მე ყველაფერს გააკეთებს malloc (sizeof (int)). ან თუ მინდოდა მასივი 5, მე ყველაფერს გააკეთებს (sizeof (int) * 5); თუ აქვს int **? რა შეიძლება malloc? [სტუდენტი] ზომა კურსორის. >> Yeah. (Sizeof (int *)); იგივე ქვემოთ აქ. მინდა (sizeof (char *)); ეს აპირებს გამოყოს ფართი მაჩვენებელი, რომელიც მიუთითებს "BOOM". მე არ უნდა გამოყოს ფართი "BOOM" თავად რადგან ეს არის ძირითადად ექვივალენტი რა ვთქვი of char * x = "BOOM". "BOOM" უკვე არსებობს. ეს ხდება არსებობა წაუკითხავი რეგიონში მეხსიერება. მაგრამ ეს უკვე არსებობს, რაც იმას ნიშნავს, ამ ხაზი კოდი, თუ არის char **, მაშინ * s არის char * და თქვენ დააყენოთ ეს char * აღვნიშნო, რომ "BOOM". თუ მინდოდა ასლი "BOOM" შევიდა s, მაშინ მე უნდა გამოყოს ფართი s. მე გავაკეთებ * s = malloc (sizeof (char) * 5); რატომ 5? რატომ არ 4? როგორც ჩანს "BOOM" არის 4 სიმბოლო. >> [სტუდენტი] null ხასიათი. Yeah. ყველა თქვენი სტრიქონები ვაპირებთ გვჭირდება null ხასიათი. ახლა შემიძლია რაღაც strcat - რა არის ფუნქცია კოპირება სიმებიანი? [სტუდენტი] cpy? >> Strcpy. კაცი strcpy. ამიტომ strcpy ან strncpy. strncpy ოდნავ უსაფრთხო რადგან თქვენ შეგიძლიათ მიუთითოთ ზუსტად რამდენი გმირები, მაგრამ აქ არა აქვს მნიშვნელობა, რადგან ჩვენ ვიცით. ამიტომ strcpy და მოუთმენლად წელს არგუმენტები. პირველი არგუმენტი არის ჩვენი დანიშნულების. მეორე არგუმენტი არის ჩვენი წყარო. ჩვენ ვაპირებთ კოპირება ჩვენს დანიშნულების * s კურსორის "BOOM". რატომ შეიძლება გსურთ ამ strcpy ნაცვლად მხოლოდ, რაც ჩვენ გვქონდა ადრე of * s = "BOOM"? არსებობს მიზეზი, დაგვჭირდება ამის გაკეთება, მაგრამ რა არის ის, რომ ამის მიზეზი? [სტუდენტი] თუ თქვენ გსურთ შეცვალოთ რაღაც "BOOM". >> Yeah. ახლა შემიძლია რაღაც s [0] = 'X'; რადგან s მიუთითებს ბევრი და რომ სივრცე ბევრი რომ არის მიუთითებს არის მომცეთ მეტი სივრცე ბევრი, რომელიც შენახვის "BOOM". ასე რომ, ეს ასლი "BOOM" მიმდინარეობს ინახება ბევრი. არსებობს ტექნიკურად ორი ასლი "BOOM" ჩვენი პროგრამა. იქ პირველი ეს მხოლოდ მიერ ამ "BOOM" სიმებიანი მუდმივი, და მეორე ასლი "BOOM", strcpy შექმნილი ასლი "BOOM". მაგრამ ასლი "BOOM" მიმდინარეობს ინახება ბევრი და ბევრი თქვენ მისი შეცვლა. ბევრი არ არის წაუკითხავი, ისე, რომ ნიშნავს, რომ [0] აპირებს მოგცემთ შეცვალოთ ღირებულების "BOOM". იგი აპირებს მოგცემთ შეცვალოთ იმ სიმბოლოებს. კითხვები? Okay. მოძრავი to buggy3, მოდით GDB buggy3. ჩვენ უბრალოდ გაუშვით და ჩვენ ვხედავთ მივიღებთ segfault. თუ ჩვენ backtrace, არის მხოლოდ ორი ფუნქცია. თუ ჩვენ ახვიდეთ შევიდა ჩვენი მთავარი ფუნქცია, ჩვენ ვხედავთ, რომ ჩვენ segfaulted ამ ხაზის. ასე რომ მხოლოდ შევხედავთ ამ ხაზის, ამისთვის (int ხაზი = 0; fgets ამ პერსონალის არ თანაბარი NULL; ხაზი + +). ჩვენი წინა ჩარჩო ეწოდა _IO_fgets. თქვენ ნახავთ, რომ ბევრი ჩაშენებული C ფუნქციები, რომ როდესაც თქვენ segfault, იქნება მართლაც cryptic ფუნქცია სახელები მსგავსი _IO_fgets. მაგრამ ეს აპირებს ეხება ამ fgets ზარი. სადღაც შიგნით აქ, ჩვენ segfaulting. თუ დავაკვირდებით არგუმენტები fgets, ჩვენ შეგვიძლია ბეჭდვა ბუფერული. მოდით ბეჭდვა როგორც - ო, არა. ბეჭდვის არ აპირებს იმუშაოს ზუსტად როგორც მე მინდა მას. მოდით შევხედოთ რეალურ პროგრამა. ბუფერული არის ხასიათი მასივი. ეს ხასიათი მასივი 128 სიმბოლო. ამიტომ როდესაც ვამბობ, რომ ბეჭდვითი ბუფერული, ის აპირებს ბეჭდვა იმ 128 გმირები, რაც ვფიქრობ, არის ის, რაც მოსალოდნელი იყო. რა ეძებდა არის ბეჭდვის მისამართი ბუფერული, მაგრამ, რომ ნამდვილად არ მითხრათ ბევრად. ასე რომ, როდესაც მე მოხდეს ვთქვა აქ x ბუფერული, იგი აჩვენებს ჩემთან 0xbffff090, რომელიც, თუ გახსოვთ საწყისი ადრე თუ რაღაც მომენტში, Oxbffff tends იყოს Stack-ish რეგიონში. დასტის tends უნდა დაიწყოს სადღაც მხოლოდ ქვეშ 0xc000. მხოლოდ ვხედავთ ამ მისამართზე, ვიცი, რომ ბუფერული ხდება Stack. ხელმეორედ ჩემი პროგრამა, გაუშვით, up, ბუფერის დავინახეთ იყო ამ თანმიმდევრობა გმირები რომ არის საკმაოდ ბევრი უაზრო. მაშინ დაბეჭდვის ფაილი, რას ფაილი ჰგავს? [სტუდენტი] null. >> Yeah. ფაილი არის ტიპის ფაილ *, ასე რომ მომცეთ, და ღირებულება, რომ კურსორი არის null. ამიტომ fgets აპირებს ცდილობენ წაკითხვის რომ მაჩვენებელი წელს არაპირდაპირი გზით, მაგრამ იმისათვის, რათა შეამოწმონ, რომ მაჩვენებელი, ის dereference იგი. ან, რათა შედიხართ რა უნდა მივუთითოთ, ეს dereferences იგი. ამიტომ dereferencing null მაჩვენებელი და ეს segfaults. შემეძლო კვლავ დაიწყო მას იქ. თუ ჩვენ შესვენება ჩვენს მთავარია და აწარმოებს, პირველი ხაზი კოდი არის char * ფაილის სახელი = "nonexistent.txt"; რომ უნდა მისცეს საკმაოდ დიდი მინიშნება, თუ რატომ ეს პროგრამა ვერ. Typing შემდეგი გამოიტანს მიბოძეთ შემდეგი ხაზი, სადაც მე ამ ფაილის გახსნის, და შემდეგ მაშინვე შეღწევას ჩვენი ხაზი, სადაც კიდევ ერთხელ მე მოხვდა შემდეგი, ეს აპირებს segfault. ვინმეს გსურთ ჩააგდე მიზეზი, რის გამოც ჩვენ შეიძლება segfaulting? [სტუდენტი] ფაილი არ არსებობს. >> Yeah. ეს უნდა იყოს მინიშნება რომ როდესაც თქვენ გახსნის ფაილი თქვენ უნდა დარწმუნდეთ რომ ფაილი ნამდვილად არსებობს. ასე რომ აქ, "nonexistent.txt"; როდესაც ჩვენ fopen ფაილის წასაკითხად, ჩვენ მაშინ უნდა ითქვას, თუ (ფაილი == NULL) და ვთქვათ printf ("ფაილი არ არსებობს!" ან - კიდევ უკეთესი - ფაილის სახელი); დაბრუნების 1; ახლა ჩვენ შეამოწმეთ თუ NULL სანამ რეალურად გრძელდება და ცდილობს წაკითხვის რომ ფაილი. ჩვენ შეგვიძლია რიმეიკი უბრალოდ დაინახოს, რომ სამუშაოები. მე აპირებდა მოიცავს ახალი ხაზი. ახლა nonexistent.txt არ არსებობს. თქვენ ყოველთვის უნდა შეამოწმოთ ამ სახის რამ. თქვენ ყოველთვის უნდა შეამოწმოთ თუ fopen ბრუნდება null. თქვენ ყოველთვის უნდა შეამოწმოთ რომ დავრწმუნდეთ, რომ malloc არ დააბრუნებს NULL, ანდა თქვენ segfault. ახლა buggy4.c. გაშვებული. მე გამოცნობა ამ ელოდება შეყვანის ან შესაძლოა უსასრულო looping. დიახ, ეს უსასრულო looping. ამიტომ buggy4. როგორც ჩანს ჩვენ უსასრულო looping. ჩვენ შეგვიძლია შესვენება დროს ძირითადი, აწარმოებს ჩვენი პროგრამა. In GDB, რადგან აბრევიატურა თქვენ იყენებთ არის ცალსახა ან სპეციალური აბრევიატურების რომ ისინი უზრუნველყოფენ თქვენთვის, მაშინ შეგიძლიათ გამოიყენოთ N გამოიყენოს შემდეგი ნაცვლად, რომელმაც უნდა აკრიფოთ out შემდეგი ყველა გზა. და ახლა რომ მე მოხვდა n ერთხელ, მე შემიძლია უბრალოდ დააჭიროთ შენარჩუნება აპირებს შემდეგი ნაცვლად, რომელმაც მოხვდა n შეიყვანეთ, n შეიყვანეთ, n შეიყვანეთ. როგორც ჩანს მე რაღაც ამისთვის loop რომ შექმნის array [i] 0. როგორც ჩანს მე არასოდეს არღვევს ამ for loop. თუ მე ბეჭდვა მე ვარ, ამიტომ არის 2, მაშინ მე წასვლა შემდეგი. მე ბეჭდვა i, მე არის 3, მაშინ მე წასვლა შემდეგი. მე ბეჭდვა I და მე არის 3. შემდეგი, ბეჭდვა i, მე არის 4. სინამდვილეში, ბეჭდვითი sizeof (მასივი), რათა ზომის მასივი 20. მაგრამ ეს ჰგავს არსებობს ზოგიერთი სპეციალური GDB შემქმნელი აპირებს მანამ, სანამ რამე მოხდება. ეს მოსწონს შექმნის მდგომარეობის ღირებულება ცვლადი. მაგრამ არ მახსოვს რა არის. ასე რომ, თუ ჩვენ ვაპირებთ შენარჩუნება - რის ამბობდა? რა ზრდიან? [სტუდენტი] არ არიან დავამატო - >> Yeah. ასე არაა მე შეიძლება დაეხმაროს. თუ ჩვენ მხოლოდ ცარიელია i, იგი შეეგუება აქ რა ღირებულება მე არის ასე რომ არ უნდა ამობეჭდოთ ყოველ ჯერზე. თუ ჩვენ უბრალოდ შეინახოს აპირებს მომდევნო, ჩვენ ვხედავთ 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5. რაღაც მიდის არასწორი საშინლად, და მე მიმდინარეობს დაიყვანება 0. ეძებს buggy4.c, ჩვენ ვხედავთ, რომ ყველა ხდება int array [5]; ამისთვის (i = 0; i <= sizeof (მასივი), მე + +) array [i] = 0; რა ჩვენ ვხედავთ, რომ არასწორი აქ? როგორც მინიშნება, როდესაც აკეთებს GDB buggy4 - მოდით შესვენება მთავარ, პერსპექტივაში - მე ბეჭდვითი sizeof (Array) უბრალოდ რა მდგომარეობა არის, სადაც მე უნდა საბოლოოდ შესვენება out. სად ვარ მე? არ ვამბობ, აწარმოებს? მე არ ვაცხადებ, არავის გაუკეთებია. ამიტომ ბეჭდვა sizeof (Array) და ეს 20, რაც მოსალოდნელია, რადგან ჩემი array არის ზომა 5 და ეს სულ 5 რიცხვებით, ასე მთელი რამ უნდა იყოს 5 * sizeof (int) ბაიტი, სადაც sizeof (int) tends უნდა იყოს 4. ამიტომ sizeof (Array) არის 20. რა უნდა იყოს ეს? [სტუდენტი] დაყოფილი sizeof (int). >> Yeah, / sizeof (int). როგორც ჩანს, იქ მაინც პრობლემა აქ. მე ვფიქრობ, ეს უნდა იყოს მხოლოდ < რადგან საკმაოდ ბევრი ყოველთვის <და არასოდეს <=. ახლა მოდით ვიფიქროთ, ამიტომ ეს იყო რეალურად გატეხილი. ვინმეს არ მიხვდება რატომ მე დაიყვანება 0 მეშვეობით თითოეულ iteration of loop? ერთადერთი, რაც შიგნით აქ რომ ხდება ის არის, რომ მასივი [i] იქმნება, რომ 0. ასე რომ როგორღაც, ამ ხაზი კოდი რამ გამოიწვია ჩვენი int მე უნდა მითითებული 0. [სტუდენტი] შეიძლება, რადგან ის უმთავრესი მეხსიერების ამ ნაწილის მე როდესაც იგი მიიჩნევს, რომ ეს მორიგი ელემენტს მასივი? >> [Bowden] დიახ. როდესაც ჩვენ ვაპირებთ მიღმა ბოლოს ჩვენი მასივი, რატომღაც, რომ სივრცეში, რომ ჩვენ მნიშვნელოვანი არის უმთავრესი ღირებულება მე. და ასე თუ გადავხედავთ შევიდა buggy4, შესვენება მთავარ, პერსპექტივაში, მოდით ბეჭდვა მისამართი მე. როგორც ჩანს ეს bffff124. ახლა მოდით ბეჭდვა მისამართი array [0]. 110. რაც შეეხება [1]? 114. [2], 118. 11C, 120. array [5] არის bfff124. ამიტომ array [5] აქვს იგივე მიმართვა როგორც მე, რაც იმას ნიშნავს, რომ მასივი [5] არის მე. თუ აქვთ იგივე მისამართზე, ისინი იგივე. ასე რომ, როდესაც ჩვენ დავსახეთ array [5] 0, ჩვენ ვქმნით მე რომ 0. და თუ ფიქრობთ, რომ ამ თვალსაზრისით დასტის, int მე ცხადდება პირველი, რაც იმას ნიშნავს, მე იღებს ცოტა ადგილის Stack. მაშინ array [5] გამოიყოფა, ასე შემდეგ 20 ბაიტი გამოიყოფა on Stack. ასე რომ იღებს გამოყოფილი პირველი, მაშინ ამ 20 ბაიტი მისაღებად გამოყოფილი. ასე რომ ხდება უფლება ადრე მასივი, და ამის გამო გზა, როგორიც მე გასულ კვირას განაცხადა, სადაც ტექნიკურად დასტის იზრდება down, როდესაც თქვენ ინდექსი შევიდა მასივი, ჩვენ გარანტირებული რომ 0th პოზიცია მასივი ყოველთვის ხდება ადრე პირველ პოზიციას მასივი. ეს არის ერთგვარი როგორ მიიპყრო იგი გასულ კვირას. გაითვალისწინეთ, რომ ბოლოში ჩვენ გვაქვს მისამართი 0 და ზედა გვაქვს მისამართი მაქს. დასტის ყოველთვის მზარდი ქვემოთ. ვთქვათ ჩვენ გამოყოფს მე. ჩვენ გამოყოფს რიცხვი i, რაც იმას ნიშნავს, მოდით უბრალოდ, ვამბობთ აქ მთელი მე იღებს გამოყოფილი. მაშინ ჩვენ გამოყოფს ჩვენი მასივი 5 რიცხვებით, რაც იმას ნიშნავს, რომ ქვევმოთ რომ, რადგან დასტის იზრდება ქვევით, იმ 5 რიცხვებით მისაღებად გამოყოფილი. მაგრამ როგორ კოლექტორები მუშაობა, ჩვენ გარანტირებულია, რომ პირველ პოზიციას მასივი ყოველთვის აქვს მისამართი ნაკლები მეორე რამ მასივი. ამიტომ მასივი თანამდებობა 0 ყოველთვის უნდა მოხდეს პირველი მეხსიერება, ხოლო მასივი პოზიცია 1 უნდა მოხდეს ამის შემდეგ და array პოზიცია 2 უნდა მოხდეს ამის შემდეგ, რაც იმას ნიშნავს, რომ მასივი თანამდებობა 0 მოხდებოდა სადღაც ქვევით აქ, array პოზიცია 1 მოხდებოდა ზემოთ რომ რადგან მოძრავი up ნიშნავს უმაღლესი მისამართები წლიდან მაქსიმალური მისამართი აქ. ამიტომ array [0] ქვევით აქ, array [1] აქ, array [2] აქ, array [3] აქ. შეამჩნევთ, თუ როგორ სანამ ჩვენ გამოყოფილი მთელი მე ყველა გზა აქ, როგორც ჩვენ გადაადგილება შემდგომი და შემდგომი ჩვენს მასივი, ჩვენ უახლოვდება და უფრო ახლოს ჩვენი რიცხვი მე. ეს უბრალოდ ისე ხდება, რომ მასივი [5], რომელიც არის ერთი პოზიცია მიღმა ჩვენი მასივი, სწორედ აქ მთელი მე მოხდა უნდა გამოიყოს. ასე რომ წერტილში, სადაც ჩვენ არ უნდა იყოს hitting სივრცე დასტის რომ გამოყოფილი მთელი მე და ჩვენ მიიღწევა, რომ 0. ასე რომ მუშაობს. კითხვები? Yeah. [სტუდენტი] არასოდეს გონება. Okay. [სტუდენტი] როგორ თავიდან ასაცილებლად ამ სახის შეცდომები? ეს ერთგვარი შეცდომები? არ გამოიყენოთ C როგორც თქვენი პროგრამირების ენა. გამოიყენეთ ენა რომ აქვს მასივი ფარგლებს შემოწმების. სანამ შენ ფრთხილად, თქვენ უბრალოდ უნდა თავიდან ავიცილოთ მიმდინარეობს წარსულის ფარგლებში თქვენი მასივი. [სტუდენტი] ასე აქ როდესაც წავედით წარსულში ფარგლებში თქვენი მასივი - [Bowden] სწორედ აქ რამ დაიწყება აპირებს არასწორია. >> [სტუდენტი] Oh, okay. როგორც თქვენ დარჩება ფარგლებში მეხსიერების გამოყოფილი თქვენი მასივი, თქვენ ჯარიმა. მაგრამ C არ დაუტოვებიათ შეცდომა შემოწმებისას. თუ array [1000], ის სიამოვნებით უბრალოდ ცვლილებები რაც არ უნდა მოხდეს - ეს ღებულობენ დასაწყისში მასივი, მაშინ იგი მიდის 1000 პოზიციები შემდეგ და ადგენს მას 0. იგი ამას არ გააკეთებს ნებისმიერი შემოწმება, რომ ოჰ, ეს ფაქტობრივად არ აქვს 1000 რამ იგი. 1000 არის გზა მიღმა რა უნდა შეცვლა, ხოლო Java ან რამე წაიკითხონ მასივი ფარგლებს გარეთ ინდექსი ან ინდექსი ფარგლებს გარეთ გამონაკლისი. ამიტომ ბევრი უმაღლესი დონის ენებზე აქვს ეს ყველაფერი აქ თუ გასცდება ფარგლებში მასივი, თქვენ ვერ ასე რომ თქვენ ვერ შეცვლის ნივთები ქვევმოთ თქვენ და შემდეგ რამ წასვლა გაცილებით უარესი, ვიდრე უბრალოდ მიღების გამონაკლისი ვამბობთ, რომ თქვენ გასცდა ბოლოს მასივი. [სტუდენტი] და ასე უნდა ჩვენ ცოტა ხნის წინ შეიცვალა <= უბრალოდ > [Bowden] Yeah. ეს უნდა იყოს > [სტუდენტი] მარჯვენა. სხვა კითხვები? Okay. [სტუდენტი] მე მაქვს შეკითხვა. >> Yeah. [სტუდენტი] რა არის ფაქტობრივი მასივი ცვლადი? [Bowden] Like რა არის მასივი? Array თავისთავად სიმბოლოა. უბრალოდ მისამართი დაწყების 20 ბაიტი, რომ ჩვენ referencing. თქვენ შეგიძლიათ ვფიქრობ, რომ ეს მაჩვენებელი, მაგრამ ეს მუდმივი მაჩვენებელი. როგორც კი რამ მისაღებად შედგენილი, ცვლადი მასივი აღარ არსებობს. [სტუდენტი] ასე როგორ მოვძებნოთ ზომა მასივი? ზომა მასივი ეხება ზომა, რომ ბლოკი, რომ სიმბოლო ეხება. როდესაც მე რაღაც მოსწონს printf ("% p \ n", array); მოდით გაუშვით. რა მე უბრალოდ არასწორად? Array 'array' განაცხადა აქ. ოჰ, აქ. Clang არის ჭკვიანი, და ეს მოხდება აღნიშვნა, რომ მე განაცხადა წყობის 5 ელემენტები მაგრამ მე ინდექსირებას შევიდა პოზიცია 1000. ეს შეგვიძლია გავაკეთოთ, რომ რადგან ეს უბრალოდ მუდმივები. ეს შეიძლება მხოლოდ იქ დღემდე დაენახა, რომ მე ვაპირებ მიღმა ფარგლებში მასივი. მაგრამ შეამჩნია ადრე, როდესაც ჩვენ გვქონდა მე იყოს არასწორი, მას არ შეუძლია შესაძლოა განსაზღვროს რამდენი ღირებულებების შემეძლო იღებს, ასე რომ ვერ განსაზღვრავს, რომ მე სცდება ბოლოს მასივი. ეს მხოლოდ Clang მყოფი ჭკვიანი. მაგრამ ახლა გააკეთოს buggy4. ასე რომ რა ვარ მე აკეთებს არასწორი? მინიშნებით გამოცხადების ბიბლიოთეკის ფუნქცია 'printf ". მე ვაპირებ გვინდა # მოიცავს . Okay. კოალიციაში buggy4. პოლიგრაფიული ღირებულება მასივი მოსწონს მე აქ, ბეჭდვას, როგორც კურსორი ანაბეჭდები, რომ რაღაც ასე გამოიყურება - bfb8805c - რომელიც რამდენიმე მისამართი რომ წელს Stack-ish რეგიონში. Array თავისთავად მოსწონს მაჩვენებელი, მაგრამ ეს არ არის ფაქტობრივი მაჩვენებელი, რადგან რეგულარული მაჩვენებელი შეგვიძლია შევცვალოთ. Array არის რამოდენიმე მუდმივი. 20 ბლოკები მეხსიერების იწყება მისამართი 0xbfb8805c. ამიტომ bfb8805c მეშვეობით ამ მისამართზე +20- ან ვფიქრობ -20 - არის ყველა მეხსიერების გამოყოფილი ამ მასივი. Array, ცვლადი თავად არ ინახება არსად. როდესაც თქვენ შედგენის, შემდგენელი - ხელის ტალღა მას - მაგრამ შემდგენელი მხოლოდ გამოიყენოთ, სადაც ეს იცის მასივი იყოს. იგი დარწმუნებულია, სადაც ეს მასივი იწყება, ამიტომ ყოველთვის შეგიძლიათ უბრალოდ რამ თვალსაზრისით ჩათვლის, რომ დასაწყისია. მას არ დასჭირდება ცვლადი თავს წარმოადგენენ მასივი. მაგრამ როდესაც რაღაც მოსწონს int * p = array, ახლა P არის მაჩვენებელი, რომელიც მიუთითებს, რომ მასივი, და ახლა P რეალურად არ არსებობს Stack. მე თავისუფლად შეცვალოს გვ. შემიძლია p = malloc. ასე რომ თავდაპირველად აღნიშნა, რომ მასივი, ახლა ეს მიუთითებს ცოტა ადგილის ბევრი. მე ვერ array = malloc. თუ Clang არის ჭკვიანი, ის დაწეროთ at me უფლება off bat. სინამდვილეში, მე საკმაოდ დარწმუნებული gcc ყველაფერს გააკეთებს ამას. ამიტომ array ტიპის 'int [5] "არ არის assignable. თქვენ არ შეგიძლიათ დაავალოს რაღაც array ტიპის რადგან მასივი მხოლოდ მუდმივი. ეს არის სიმბოლო, რომელიც ცნობას იმ 20 ბაიტი. მე ვერ შეცვლის. [სტუდენტი] და სად არის ზომა მასივი ინახება? [Bowden] ეს არ ინახება არსად. ეს მაშინ, როდესაც ის შედგენა. ისე სად არის ზომა მასივი ინახება? თქვენ შეგიძლიათ გამოიყენოთ მხოლოდ sizeof (Array) შიგნით ფუნქცია მასივი გამოცხადებისთანავე. ასე რომ, თუ რაღაც ფუნქცია, foo, და გავაკეთე (int array []) printf ("% d \ n", sizeof (Array)); და შემდეგ ქვევით აქ მოვუწოდებ foo (მასივი); შიგნით ამ ფუნქციის - მოდით გაუშვით. ეს არის Clang მყოფი ჭკვიანი ერთხელ. ის მეუბნებოდა, რომ sizeof on მასივი ფუნქციის პარამეტრი დაბრუნდება ზომა 'int *'. ეს იქნებოდა შეცდომა, თუ ის არ არის რაც მინდოდა მომხდარიყო. მოდით რეალურად გამორთეთ Werror. გაფრთხილება. გაფრთხილებები არის ჯარიმა. ის მაინც შეადგინოს სანამ მას გაფრთხილება. . / A.out აპირებს ბეჭდვა 4. გაფრთხილება, რომელიც გენერირდება არის ნათელი მაჩვენებელია, თუ რა წავიდა არასწორად. ეს int array მხოლოდ აპირებს ბეჭდვა sizeof (int *). მაშინაც კი, თუ მე ზუსტად array [5] აქ, მაინც უბრალოდ აპირებს ბეჭდვა sizeof (int *). ამიტომ, როგორც კი თქვენ გაივლის ის ფუნქცია, განსხვავება შორის კოლექტორები და მითითებები არის არარსებული. ეს ხდება იყოს მასივი, რომელიც გამოცხადებული დასტის, მაგრამ როგორც კი ჩვენ გაიაროს, რომ ღირებულება, რომ 0xbf blah, blah, blah ამ ფუნქციას, მაშინ ეს მაჩვენებელი მიუთითებს, რომ მასივი on Stack. ასე რომ, რაც იმას ნიშნავს, რომ sizeof მხოლოდ ეხება ფუნქცია მასივი გამოცხადდა, რაც იმას ნიშნავს, რომ როდესაც თქვენ შედგენის ამ ფუნქციის, როდესაც Clang გადის ამ ფუნქციის, ის ხედავს მასივი int მასივი ზომა 5. ასე რომ მაშინ ხედავს sizeof (მასივი). ისე, რომ 20. სწორედ პრაქტიკულად როგორ sizeof ძირითადად მუშაობს თითქმის ყველა შემთხვევაში. Sizeof არ არის ფუნქციის ის ოპერატორი. თქვენ არ მოვუწოდებთ sizeof ფუნქცია. Sizeof (int), შემდგენელი მხოლოდ თარგმნოს, რომ 4. Got it? Okay. [სტუდენტი] რა არის განსხვავება sizeof (Array) მთავარ და foo? ეს იმიტომ რომ ჩვენ ვამბობთ, sizeof (მასივი), რომელიც ტიპის int *, ხოლო მასივი ქვემოთ აქ არ არის ტიპის int *, ეს int მასივი. [სტუდენტი] ასე რომ, თუ თქვენ გქონდათ პარამეტრი array [] ნაცვლად int * array, იქნებოდა, რომ ნიშნავს, რომ თქვენ შეიძლება მაინც შეიცვალოს მასივი, ვინაიდან, ახლა ეს მაჩვენებელი? [Bowden] ასე? >> [სტუდენტი] Yeah. შეგიძლიათ შეცვალოთ მასივი ფარგლებში ფუნქცია არის? [Bowden] თქვენ შეიძლება შეიცვალოს მასივი ორივე შემთხვევაში. ორივე შემთხვევაში თქვენ თავისუფლად ვთქვა array [4] = 0. [სტუდენტი] მაგრამ შეგიძლიათ მასივი წერტილი რაღაც? [Bowden] Oh. Yeah. ორივე შემთხვევაში - >> [სტუდენტი] Yeah. [Bowden] განსხვავება შორის array [] და int * array, არსებობს არცერთი. ასევე შეგიძლიათ ზოგიერთი მრავალგანზომილებიანი მასივი აქ ზოგიერთი მოსახერხებელი სინტაქსი, მაგრამ მაინც მხოლოდ კურსორი. ეს ნიშნავს, რომ მე ვარ თავისუფალი გავაკეთოთ array = malloc (sizeof (int)) და ახლა აღვნიშნო სხვაგან. მაგრამ ისევე როგორც ეს მუშაობს სამუდამოდ და ყოველთვის, იცვლება ამ მასივი მიერ მიღების იგი აღვნიშნო, რომ რაღაც არ იცვლება ამ მასივი ქვემოთ აქ იმიტომ რომ ასლი არგუმენტი, ეს არ მომცეთ ეს არგუმენტი. და ფაქტობრივად, ისევე როგორც უფრო იმაზე მიანიშნებს, რომ ეს ზუსტად იგივე - ჩვენ უკვე ვნახეთ, რა ბეჭდვის მასივი ანაბეჭდები - რა თუ ჩვენ ბეჭდვა მისამართი მასივი ან მისამართი მისამართი მასივი ან იმ? მოდით იგნორირება ამ ერთ. Okay. ეს არის ჯარიმა. ეს არის გაშვებული. / A.out. ბეჭდვის მასივი, მაშინ ბეჭდვა მისამართი მასივი, არის იგივე. Array უბრალოდ არ არსებობს. იგი დარწმუნებულია, როდესაც თქვენ ბეჭდვა მასივი, თქვენ დაბეჭდვის სიმბოლო იმისა, რომ ეხება იმ 20 ბაიტი. პოლიგრაფიული მისამართი მასივი, ისევე, array არ არსებობს. არა აქვს მისამართი, ასე რომ უბრალოდ ბეჭდავს მისამართი იმ 20 ბაიტი. როგორც კი კომპილაციის ქვემოთ, ისევე როგორც თქვენი შედგენილი buggy4. / A.out, array არის არარსებული. პოინტერები არსებობს. მასივები არა. ბლოკები მეხსიერების წარმოადგენს მასივს კიდევ არსებობს, მაგრამ ცვლადი მასივი და ცვლადების ტიპის არ არსებობს. ეს ის მსგავსად ძირითადი განსხვავებები კოლექტორები და მითითებები მათ, როგორც კი თქვენ მიიღოს ფუნქცია მოუწოდებს, არ არსებობს განსხვავება. მაგრამ შიგნით ფუნქცია მასივი თავად განაცხადა, sizeof მუშაობს განსხვავებულად მას შემდეგ, რაც თქვენ დაბეჭდვის ზომის ბლოკები ნაცვლად ზომის ტიპის, და ვერ შეცვლის, რადგან ეს სიმბოლო. პოლიგრაფიული რამ და მისამართი რამ ბეჭდავს იგივე. და ეს საკმაოდ ბევრი იყო. [სტუდენტი] იქნებ ვთქვა, რომ კიდევ ერთხელ? მე შეიძლება გამომრჩა რაღაც. ბეჭდვის array და მისამართი მასივი ბეჭდავს იგივე, ხოლო თუ თქვენ ბეჭდვა მაჩვენებელი წინააღმდეგ მისამართი მაჩვენებელი, ერთი რამ ბეჭდავს მისამართი თუ რას მიუთითებს, სხვა ბეჭდავს მისამართი მაჩვენებელი on Stack. თქვენ შეგიძლიათ შეცვალოთ კურსორი, თქვენ ვერ შეცვლის მასივი სიმბოლო. და sizeof მაჩვენებელი აპირებს ბეჭდვა ზომის რომ მაჩვენებელი ტიპის. ასე int * p sizeof (P) აპირებს ბეჭდვა 4, მაგრამ int array [5] ბეჭდვითი sizeof (Array) აპირებს ბეჭდვა 20. [სტუდენტი] ასე int array [5] იქნება ბეჭდვა 20? >> დიახ. ამიტომ შიგნით buggy4 როდესაც იგი გამოყენებული იქნება sizeof (Array) ამ აკეთებდა მე <20, რომელიც არ არის, რაც გვინდოდა. ჩვენ გვინდა მე <5. >> [სტუდენტი] Okay. [Bowden] და მაშინ, როგორც კი თქვენ დაიწყოს გადადის ფუნქციების თითქოს ჩვენ აქ int * p = array; შიგნით ამ ფუნქციას, ჩვენ შეგვიძლია გამოვიყენოთ ძირითადად P და array ზუსტად იგივე გზა, გარდა sizeof პრობლემა და შეცვლის პრობლემა. მაგრამ P [0] = 1; იგივეა დაყრდნობით array [0] = 1; და როგორც კი ვამბობთ foo (მასივი); ან foo (P); შიგნით foo ფუნქცია, ეს არის იგივე ზარი ორჯერ. არ არსებობს განსხვავება შორის ამ ორი მოუწოდებს. ყველას კარგი რომ? Okay. ჩვენ გვყავს 10 წუთის განმავლობაში. ჩვენ შევეცდებით ვუკავშირდებოდი ამ Hacker Typer პროგრამა, ამ ნახვა, რომელიც გამოვიდა გასულ წელს ან რამე. უბრალოდ უნდა იყოს თქვენნაირი აკრიფოთ შემთხვევით და ეს ბეჭდავს out - როგორიც არ უნდა იყოს ფაილი ეს მოხდება, არ არის დატვირთული, თუ რას ჰგავს თქვენ აკრეფით. როგორც ჩანს რაღაც ოპერაციული სისტემის კოდი. რაც გვინდა, რომ განახორციელონ. თქვენ უნდა ჰქონდეს ორობითი შესრულებადი დაასახელა hacker_typer რომ იღებს ერთი არგუმენტი, ფაილი "Hacker ტიპის." Running შესრულებადი უნდა გარკვევას ეკრანზე და შემდეგ ამობეჭდოთ ერთი ხასიათი გაიარა-ში ფაილი ყოველ ჯერზე მომხმარებლის presses გასაღები. ასე რომ რაც არ უნდა გასაღები დააჭერთ, უნდა გადააგდებს და ნაცვლად ბეჭდვა ხასიათი ფაილი რომ არის არგუმენტი. მე საკმაოდ ბევრი გითხრათ, რა რამ ჩვენ ვაპირებთ უნდა იცოდეთ არიან. მაგრამ ჩვენ გვინდა, რომ შეამოწმეთ termios ბიბლიოთეკაში. მე არასოდეს გამოიყენება ამ ბიბლიოთეკის ჩემი მთელი ცხოვრება, ასე რომ მას აქვს ძალიან მინიმალური მიზნებისათვის. მაგრამ ეს იქნება ბიბლიოთეკის ჩვენ შეგვიძლია გამოვიყენოთ, რათა გადაყარეთ ხასიათი თქვენ მოხვდა როდესაც თქვენ აკრეფით შევიდა სტანდარტული სისტემაში ამიტომ hacker_typer.c, და ჩვენ ვაპირებთ გვინდა # მოიცავს . ეძებს კაცს გვერდი termios - I'm გამოცნობა მისი ტერმინალური OS ან რაღაც - მე არ ვიცი როგორ წაიკითხავს. ეძებს ამ, ნათქვამია, რომ მოიცავს ეს 2 ფაილი, ამიტომ ჩვენ ყველაფერს გავაკეთებთ, რომ. პირველი, რაც პირველ რიგში, ჩვენ გვინდა, რომ მიიღოს ერთ არგუმენტად, რომელიც ფაილი უნდა გახსნა. ასე რომ რა გსურთ? როგორ შემიძლია შეამოწმეთ მაქვს ერთი არგუმენტი? [სტუდენტი] თუ argc შეადგენს იგი. >> [Bowden] Yeah. ასე რომ, თუ (argc = 2) printf ("გამოყენება:% s [ფაილის გასახსნელად]"). ახლა თუ აწარმოებს ამ გარეშე მიწოდების მეორე არგუმენტი - Oh, მჭირდება ახალი ხაზი - დაინახავთ ნათქვამია გამოყენება:. / hacker_typer, და მაშინ მეორე არგუმენტი უნდა იყოს ფაილი მინდა გახსნა. ახლა რა ვქნათ? მინდა წაკითხვის ამ ფაილის. როგორ შემიძლია წაკითხვის ფაილი? [სტუდენტი] ვხსნით მას პირველი. >> Yeah. ამიტომ fopen. რას fopen გამოიყურებოდეს? [სტუდენტი] Filename. >> [Bowden] Filename იქნება argv [1]. [სტუდენტი] და მერე რა გსურთ შუაში იყო, ასე რომ - >> [Bowden] Yeah. ასე რომ, თუ თქვენ არ გახსოვთ, თქვენ შეიძლება უბრალოდ კაცი fopen, სადაც ეს იქნება const char * გეზი, სადაც ბილიკი არის ფაილის სახელი, const char * რეჟიმში. თუ ემართება არ გახსოვთ რა რეჟიმში, მაშინ გადახედეთ რეჟიმში. შიგნით კაცი გვერდებზე, ირიბის ხასიათი არის ის, რაც შეგიძლიათ გამოიყენოთ მოძებნოთ ნივთები. ასე რომ, მე Type / რეჟიმში მოძიების რეჟიმში. N და N არიან რა შეგიძლიათ გამოიყენოთ ციკლის გავლით ძებნა მატჩები. აქ ნათქვამია არგუმენტი რეჟიმში მიუთითებს სიმებიანი დაწყებული ერთი შემდეგი sequences. ამიტომ R, ღია ტექსტი ფაილი მოსმენით. რაც გვინდა, რომ გავაკეთოთ. კითხულობს, და მინდა, რომ შესანახად. რამ იქნება ფაილ *. ახლა რა გსურთ? მომეცი მეორე. Okay. ახლა რა გსურთ? [სტუდენტი] შეამოწმეთ თუ null. >> [Bowden] Yeah. ნებისმიერ დროს გახსნა ფაილი, დარწმუნდით, რომ თქვენ წარმატებით შეუძლიათ გახსნან. ახლა მინდა გავაკეთოთ, რომ termios პერსონალის სადაც მინდა პირველი წაიკითხა ჩემი მიმდინარე პარამეტრების და გადარჩენა იმ შევიდა რაღაც, მაშინ მინდა, რომ შევცვალო ჩემი პარამეტრების to გადაყარეთ ნებისმიერი ხასიათი რომ მე ტიპის, და შემდეგ მინდა განაახლოს იმ პარამეტრების. და შემდეგ დასასრულს პროგრამა, მინდა რომ შეიცვალოს თავში ჩემი ორიგინალური პარამეტრები. ამიტომ struct იქნება ტიპის termios, და მე ვაპირებ მინდა ორი იმ. პირველი იქნება ჩემი current_settings, და მაშინ იქნება ჩემი hacker_settings. პირველი, მე ვაპირებ მინდა გადარჩენა ჩემი მიმდინარე პარამეტრების, მაშინ მე ვაპირებ გსურთ განაახლოთ hacker_settings, და შემდეგ გზა დასასრულს ჩემი პროგრამა, მინდა დაუბრუნდება არსებული პარამეტრები. ამიტომ გადარჩენის მიმდინარე პარამეტრების, ისე, რომ მუშაობს, ჩვენ კაცს termios. ჩვენ ვხედავთ, რომ ჩვენ გვაქვს ეს int tcsetattr, int tcgetattr. მე კორიდორი termios struct მისი მაჩვენებელი. გზა ამ გამოიყურება არის - I've უკვე დაავიწყდათ, რა ფუნქცია ეწოდა. დააკოპირეთ და ჩასვით იგი. ამიტომ tcgetattr, მაშინ მინდა კორიდორი struct რომ მე გადარჩენის ინფორმაციას, რომელიც იქნება current_settings, და პირველი არგუმენტი არის ფაილის descriptor ამისთვის რამ მინდა გადარჩენა ატრიბუტები. რა ფაილი descriptor არის ჰგავს ნებისმიერ დროს გახსნა ფაილი, ის იღებს ფაილს descriptor. როდესაც მე fopen argv [1], იგი იღებს ფაილის descriptor რომელიც თქვენ referencing მაშინ, როცა გნებავთ წაკითხვის ან ჩაწერის იგი. ეს არ არის ფაილის descriptor მინდა აქ. არსებობს სამი ფაილი აღწერებს გაქვთ ჩვეულებრივ, რომლებიც სტანდარტს, სტანდარტული, და სტანდარტული შეცდომა. ჩვეულებრივ, მე ვფიქრობ, სტანდარტი არის 0, სტანდარტული გარეთ არის 1, და სტანდარტული შეცდომა 2. ასე რომ რა გსურთ შეცვალოთ პარამეტრები? მინდა შეიცვალოს პარამეტრების როდესაც მე მოხვდა ხასიათი, მინდა ეს იმისათვის, რომ ხასიათი მოშორებით ნაცვლად დაბეჭდვის მას ეკრანზე. რა ნაკადი - სტანდარტი, სტანდარტული მათგანი, ან სტანდარტული შეცდომა - პასუხობს რამ როცა აკრიფეთ კლავიატურაზე? >> [სტუდენტი] სტანდარტული შემოსული >> Yeah. ასე, რომ შეიძლება არც გააკეთონ 0 ან შემიძლია stdin. მე მიღების current_settings სტანდარტული სისტემაში ახლა მინდა განაახლოს იმ პარამეტრების, ამიტომ პირველ მე კოპირება შევიდა hacker_settings რა ჩემი current_settings არიან. და როგორ structs მუშაობა იქნება გადააკოპირეთ. ეს აკოპირებს ყველა სფეროში, როგორც თქვენ მოელოდა. ახლა მინდა განაახლოთ ზოგიერთი სფეროებში. ეძებს termios, თქვენ უნდა წაიკითხოთ ბევრი რამ ამ მხოლოდ ვხედავ, რაც თქვენ სურს, ვეძებოთ, მაგრამ დროშები თქვენ აპირებს გვინდა ვეძებოთ არიან ეხო, ასე ეხო ეხო შეყვანის სიმბოლო. პირველი მინდა Set - I've უკვე დაავიწყდათ რა დარგები. ეს არის ის, რაც struct ჰგავს. ამიტომ შეყვანის რეჟიმები ვფიქრობ ჩვენ გვინდა, რომ შეიცვალოს. ჩვენ შევხედოთ გადაწყვეტა დავრწმუნდეთ, რომ ის, რაც ჩვენ გვინდა, რომ შეიცვალოს. ჩვენ გვინდა, რომ შეიცვალოს lflag პრევენციის მიზნით სჭირდება გაეცნონ ყველა ამ. ჩვენ გვინდა, რომ შეიცვალოს ადგილობრივი რეჟიმები. თქვენ უნდა წაიკითხოთ მეშვეობით მთელი უნდა გავითვალისწინოთ სადაც ყველაფერი ეკუთვნის რომ ჩვენ გვინდა, რომ შეიცვალოს. მაგრამ ეს შიგნით ადგილობრივი რეჟიმები, სადაც ჩვენ ვაპირებთ გსურთ შეცვალოთ, რომ. ამიტომ hacker_settings.cc_lmode არის რასაც ის მოუწოდა. c_lflag. ეს არის სადაც ჩვენ შეღწევას bitwise ოპერატორები. ჩვენ სახის გარეთ, მაგრამ ჩვენ გავლა ეს რეალური სწრაფი. ეს არის სადაც ჩვენ შეღწევას bitwise ოპერატორები, აქ ვფიქრობ, განაცხადა ერთ დროს დიდი ხნის წინ, რომ როდესაც თქვენ დავიწყოთ საქმე დროშები, თქვენ უნდა გამოყენებით bitwise ოპერატორი ლოტი. თითოეული წვლილი დროშა შეესაბამება გარკვეული ქმედებები. ასე რომ აქ, ამ დროშის bunch სხვადასხვა ნივთები, სადაც ყველა მათგანი ნიშნავს რაიმე განსხვავებული. მაგრამ რა მინდა გააკეთოთ უბრალოდ გამორთეთ ცოტა რაც შეესაბამება ეხო. ასე რომ ჩართოთ, რომ off გავაკეთო და = ¬ ECHO. სინამდვილეში, ვფიქრობ, როგორიცაა tECHO ან რამე. მე უბრალოდ აპირებს შეამოწმოს ერთხელ. შემიძლია termios იგი. უბრალოდ ეხო. ECHO იქნება ერთი ცოტა. ¬ ECHO აპირებს ნიშნავს ყველა ბიტი უეჭველია, რომ 1, რაც ნიშნავს ყველა დროშები მითითებული 'ჭეშმარიტი გარდა ECHO bit. By დამთავრებული ჩემი ადგილობრივი დროშები ამისა, ეს ნიშნავს ყველა დროშები, რომლებიც გაკეთებული მითითებული 'ჭეშმარიტი იქნება მითითებული 'ჭეშმარიტი. თუ ჩემი ECHO დროშა არის მითითებული, რომ ასეა, მაშინ ეს არის აუცილებლად მითითებული ყალბი on ECHO დროშა. ასე რომ, ეს ხაზი კოდი უბრალოდ თიშავს ECHO დროშა. სხვა ხაზების კოდი, მე გადააკოპირეთ მათ ინტერესი დრო და შემდეგ აუხსნას მათ. In გადაწყვეტა, მისი თქმით 0. ალბათ უკეთესი მკაფიოდ ამბობენ stdin. გაითვალისწინეთ, რომ მე ასევე აკეთებს ECHO | ICANON აქ. ICANON ეხება რაღაც ცალკე, რაც იმას ნიშნავს, კანონიკური რეჟიმში. რა კანონიკურ რეჟიმში საშუალებები ჩვეულებრივ, როდესაც თქვენ აკრეფით გარეთ ბრძანება ხაზი, სტანდარტი არ გადაამუშავებს არაფერი სანამ არ მოხვდა სტრიქონების გადატანით. ასე რომ, როდესაც თქვენ ჩვენგან GetString, თქვენ ტიპი bunch რამ, მაშინ მოხვდა სტრიქონების გადატანით. სწორედ მაშინ ის იგზავნება სტანდარტული სისტემაში სწორედ იყოს. როდესაც მე გამორთეთ კანონიკურ რეჟიმში, ახლა თითოეული ხასიათი დააჭერთ არის ის, რაც ხდება დამუშავებული, რაც, როგორც წესი, სახის ცუდი იმიტომ რომ ნელი დავამუშავოთ ეს ყველაფერი, ამიტომ კარგია ბუფერში შესანახი იგი მთელი ხაზები. მაგრამ მე მინდა ყოველ ხასიათის დამუშავდება რადგან არ მინდა ეს ლოდინი ჩემთვის მოხვდა სტრიქონების გადატანით სანამ ამუშავებს ყველა გმირები მე აკრეფით. ეს თიშავს კანონიკურ რეჟიმში. ამ პერსონალის უბრალოდ ნიშნავს, როდესაც ის რეალურად ანხორციელებს სიმბოლო. ეს ნიშნავს, გადაამუშავებს მათ მაშინვე, როგორც კი მე აკრეფით მათ, გადაამუშავებს მათ. და ეს არის ფუნქცია რომელიც განახლებას ჩემი პარამეტრების სტანდარტი, და TCSA საშუალებებით ამის გაკეთება ახლავე. სხვა ოფციები დაველოდოთ ყველაფერი, რაც ამჟამად ნაკადი დამუშავება. რომ ნამდვილად არ აქვს. Just ახლავე შევცვალო ჩემი პარამეტრების უნდა იყოს რაც ამჟამად hacker_typer_settings. ვფიქრობ მე უწოდა hacker_settings, მოდით შეცვლის. შეიცვალოს ყველაფერი hacker_settings. ახლა დასასრულს ჩვენი პროგრამის ჩვენ ვაპირებთ გსურთ გააუქმოთ თუ რა არის გაკეთებული შიგნით normal_settings, რომელიც აპირებს მხოლოდ ჰგავს და normal_settings. გაითვალისწინეთ მე არ შეცვლილა ნებისმიერი ჩემი normal_settings წლიდან თავდაპირველად მისაღებად მას. მაშინ უბრალოდ შეცვალოს ისინი უკან, მე გაივლის მათ უკან დასასრულს. ეს იყო განახლება. Okay. ახლა შიგნით აქ მე მხოლოდ ახსნას კოდი ინტერესი დრო. ეს არ არის, რომ ბევრი რამ კოდი. ჩვენ ვხედავთ, ვკითხულობთ ხასიათი ფაილი. ჩვენ მას ვ. ახლა თქვენ შეგიძლიათ მამაკაცის fgetc, მაგრამ როგორ fgetc იმუშავებს მხოლოდ ის დაბრუნებას აპირებს ხასიათი რომ უბრალოდ წაიკითხა ან EOF, რაც შეესაბამება ფაილის ბოლოში, ან რაიმე შეცდომა ხდება. ჩვენ looping აგრძელებს წაკითხვის ერთჯერადი ხასიათი ფაილი, სანამ ჩვენ ამოიწურა გმირები წაიკითხოს. და ეს მაშინ როდესაც ვაკეთებთ, რომ ველოდებით ერთ ხასიათი სტანდარტული სისტემაში თითოეული დროს თქვენ აკრიფოთ რაღაც ბრძანებათა ზოლს, რომ კითხულობს in ხასიათი სტანდარტული სისტემაში მაშინ putchar უბრალოდ გეგმავს char ვკითხულობთ აქ საწყისი ფაილის სტანდარტულ out. მაშინ კაცი putchar, მაგრამ ეს მხოლოდ აყენებს სტანდარტულ out, ის ბეჭდვას რომ ხასიათი. თქვენ შეიძლება ასევე უბრალოდ printf ("% c", გ); იგივე იდეას. რომ აპირებს ნაყარი ჩვენი მუშაობის. ბოლო რამ ჩვენ ვაპირებთ გსურთ მხოლოდ fclose ჩვენი ფაილი. თუ არ fclose, რომ მეხსიერების გაჟონვის. ჩვენ გვინდა fclose ფაილის ჩვენ თავდაპირველად გაიხსნა, და მე ვფიქრობ, რომ ეს არის ის. თუ ჩვენ გვექნება, რომ, მე უკვე პრობლემები აქვს. ვნახოთ. რა ეს უჩივიან? მოსალოდნელი იყო 'int', მაგრამ არგუმენტი ტიპის 'struct _IO_FILE *'. ჩვენ დავინახავთ, თუ რომ მუშაობს. ნებადართულია მხოლოდ c99. Augh. Okay, მიიღოს hacker_typer. ახლა ჩვენ უფრო სასარგებლო აღწერილობებიდან. ასე რომ გამოიყენოთ გამოუცხადებელი იდენტიფიკატორი 'normal_settings'. მე არ ეძახით normal_settings. მე მას current_settings. მოდით შეცვალოს ყველა რომ. ახლა ავლით არგუმენტი. გავაკეთებ ამ 0 ახლა. Okay. . / Hacker_typer cp.c. მე ასევე არ გარკვევას ეკრანზე დასაწყისში. მაგრამ შეგიძლიათ ვიხსენებთ რომ ბოლო პრობლემა კომპლექტი დაინახოს, თუ როგორ გარკვევა ეკრანზე. უბრალოდ ბეჭდვა ზოგიერთი გმირები ხოლო ეს აკეთებს რაც მე მინდა ამის გაკეთება. Okay. და ფიქრი, ამიტომ ეს საჭირო იქნება 0 ნაცვლად stdin, რაც უნდა განისაზღვროს # 0, ეს პრეტენზიებს, რომ - სანამ, როდესაც ვთქვი, რომ არსებობს ფაილური აღწერებს მაგრამ მაშინ თქვენ ასევე აქვს თქვენი ფაილი *, ფაილი descriptor არის მხოლოდ ერთი რიცხვი, ხოლო ი * აქვს მთელი bunch პერსონალის ასოცირდება იგი. მიზეზი გვჭირდება ვთქვა 0 ნაცვლად stdin არის, რომ stdin არის ფაილის * რაც მიუთითებს, რაც referencing ფაილი descriptor 0. ისე კი აქ როცა გავაკეთო fopen (argv [1], მე მიღების ფაილ * უკან. მაგრამ სადღაც რომ FILE * არის რამ შესაბამისი ფაილის descriptor რომ ფაილი. თუ გადავხედავთ კაცი გვერდზე ღია, ასე ვფიქრობ, თქვენ უნდა გავაკეთოთ Man 3 ღია - nope - კაცი 2 ღია - Yeah. თუ გადავხედავთ გვერდზე ღია, ღია ჰგავს ქვედა დონის fopen, და ეს დაბრუნების ფაქტობრივი ფაილი descriptor. fopen აკეთებს bunch პერსონალის თავზე ღია, რაც დაბრუნების ნაცვლად უბრალოდ რომ ფაილი descriptor ბრუნდება მთელი ფაილის კურსორი * შიგნით რაც არის ჩვენი პატარა ფაილი descriptor. ამიტომ სტანდარტის ეხება ფაილ * რამ, ხოლო 0 ეხება მხოლოდ ფაილის descriptor სტანდარტული თავისთავად. კითხვები? [იცინის] ააფეთქეს მეშვეობით რომ. ყველა უფლება. ჩვენ გავაკეთეთ. [იცინის] [CS50.TV]