610 likes | 771 Views
More Programming Concept. 蔡文能 tsaiwn@csie.nctu.edu.tw 交通大學資訊工程學系. Agenda. Variable and memory Array vs. pointer More about for Loop C++ string I/O and File handling Other topics. Auto 變數不可佔太多 memory. Auto 變數就是沒寫 static 的 Local 變數 Auto 變數 是在 進入函數時 才在 STACK 區 安排記憶體 ,
E N D
More Programming Concept 蔡文能 tsaiwn@csie.nctu.edu.tw 交通大學資訊工程學系
Agenda • Variable and memory • Array vs. pointer • More about for Loop • C++ string • I/O and File handling • Other topics
Auto 變數不可佔太多memory • Auto 變數就是沒寫 static的 Local 變數 • Auto 變數是在進入函數時才在STACK區安排記憶體, 在離開函數(return)時就還掉(改變 Stack Pointer) • STACK區一般不會很大(幾拾 K Bytes) • Auto 變數用STACK區, 所以太大的array不能用 • 叫用函數時, return address 也會被推入STACK • 參數傳遞也是用 STACK區 • C/C++推入參數時是先推入最後一個參數, 這使得第一個參數會在堆疊的最上方, 進入函數時, STACK中return address 之下就是第一個參數 • C/C++離開函數時, 函數不負責拿掉STACK中的參數, 那是叫用函數那個程式的責任! (與其它語言不同)
Auto 變數佔用STACK區memory 系統區 • Auto 變數就是沒寫 static的 Local 變數 Instruction Pointer CPU IP 程式+靜態data SP HEAP堆積 Stack Pointer STACK 系統區
Static變數? • Global 變數都是static的 變數 • Local 變數就是在函數內的變數 • 有補 static 修飾詞則為 static變數 • 沒有補 static 修飾詞則為 Auto 變數 • static的 變數在程式開始 RUN 之前就存在, 且已經設好初值, 程式結束後才會還掉所佔記憶體 • 寫了 extern 表示只是 宣告, 不是定義(define) • Local 變數就只能在該函數內存取 • Global 變數則只要看得見它的任一函數都能存取它 • 宣告之後就看得見, 沒宣告就定義 則看作 同時宣告了 • 注意 main( ) 也是函數, 沒有特別偉大!
Global, Static Local, Auto 變數 #include <stdio.h> extern int x; /* 只有宣告 , 還不知道位置在何處?*/ int fa( ) ; int fb( ) { int ans=0; return ++ans; } int main( ) { int kk=123; cout << "fa( )=" << fa( )<<fa( )<<fa( ) << kk<<endl; cout << "fb( )=" << fb( )<<fb( )<<fb( ) << endl; return 0; /* 0 in main( ) means OK */ } int x, y; /* 真的 x 在這, 也可以寫在另一個 file 中*/ int fa ( ) { /*…* } 寫了 extern 表示只是 宣告, 不是定義(define)
Static Global 變數 參考K&R課本4.6節 #include <stdio.h> #define BUFSIZE 100 static char buf[BUFSIZE]; static int bufp = 0; int getch( ) { /* . . . */ } void ungetch(int c) { /* . . . */ } 也參考stack的push和pop寫在同一獨立 file 中, push和pop共享 data
再談Static Global 變數 參考K&R課本4.6節 #include <stdio.h> #define RAND_MAX 65535 static unsigned long seed=0; /* global */ int rand( ) { seed = seed * 1103515245 + 12345; return seed % (RAND_MAX+1); } void srand(int newseed) { seed = newseed; } Pseudo random number
register 變數 , volatile 變數 #include <stdio.h> enum {BUFSIZE=100, NSTU=60}; register int wrong; /* this is wrong, global不可*/ volatile int haha; void myfun(register int x ) { register int yy, i; /* OK */ int * p; /* . . . */ p = &yy; /* this is wrong */ } 參考K&R課本4.7節
volatile 變數 #include <stdio.h> volatile int haha ; /* tell compiler … */ int main( ) { int k; double ans; for(k=1; k<=99; ++k) { /* . . . */ ans = haha * haha; /* do not optimize*/ printf(" ans=%f\n ", ans); } } 參考K&R課本4.7節
pointer 本身是 一個整數指向別的記憶體 再談Array 與 pointer short int x[ ] = { 0, 1, 2, 3, 4, 5, 6, 7 }; long * p = x; /* 意思是 p = &x[0]; */ long ans; int main( ) { ans = *p; /* 同: ans = p[0]; */ printf("ans=%ld, p2=%ld\n", ans, p[2]); } p[2] 與 *(p+2)完全相同 注意 byte order, big endian vs. little endian
再論 for Loop • for 之中規中矩用法 • 就是明顯在數(count) loop次數 • (若不知要Loop幾次則建議用 while ) • for 與 array 配合使用 • Pascal Triangle • Magic Square • 順便做些事的 for
for 之中規中矩用法 • 強掉 loop 次數 : 以下四例都是做 9 次 for ( i=1; i<= 9; ++i) /* … */ ; for ( i=1; i<= 9; i++) /* … */ ; for( i=1; i<10; ++i) /* … */ ; for( i=1; i<10; i++) /* … */ ; • 參考之前 9x9 乘法表, Pascal 三角形
for 與 array 配合使用 • 仔細看 Pascal triangle例子 • Using Two dimensional array • Using one dimensional array • 仔細看 Magic Square例子 • 注意奇數階魔方陣之做法轉個想法就變成可直接用雙層 for loop • 注意 4 的倍數階魔方陣之重點在如何判斷某格子是否在所謂的對角線上
再看 4k 階的魔方陣 • 4的倍數階 Magic Square 之重點在如何判斷該格子 x[row][col] 是否在對角線上 • 注意畫對角線時是每個 4 x 4 方陣為單位 • 但填入數值時是以整個方陣由左而右由上而下填入 1 到最後一個數 (next slides) • Index 由 0 算起與由 1 算起要如何調整? ( C/C++/Java 語言 index 是由 0 算起)
順便做些事的 for loop (1/ 4) #define EOF (-1) • K&R 1.5.1 檔案複製 int c; c= getchar( ); while( c!= EOF) { putchar(c); c = getchar( ); } • int c; c= getchar( ); for ( ;c!= EOF;) { putchar(c); c = getchar( ); }
順便做些事的 for loop (2/ 4) • int c; for (c= getchar( ) ; c!= EOF ; c = getchar( ) ) { putchar(c); }
順便做些事的 for loop (3/4 ) long nc; nc= 0; while ( getchar()!= EOF) ++nc; /* … * • 1.5.2 Counting characters long nc; nc= 0; for (nc=0; getchar()!= EOF; ++nc) ; /* … *
順便做些事的 for loop (4/4 ) • K&R 1.9 統計 file 中出現各字 • K&R 2.6 • K&R 2.7 atoi • K&R 2.8 squeeze • K&R 3.5 atoi • K&R 3.7 trim • K&R 4.2 atof
C ++ class Library <algorithm> <bitset> <complex> <deque> <exception> <fstream> <functional> <iomanip> <ios> <iosfwd> <iostream> <istream> <iterator> <list> <locate> <limits> <map> <memory> <new> <numeric> <ostream> <queue> <streambuf> <string> <set> <sstream> <stack> <stdexcept> <typeinfo> <utility> <valarray> <vector> <cmath>
The C++ String Class • The C-style strings (arrays of char) that you’ve been using are not the only way of managing character data. • C++ allows you to work with a string class that eases many of the problems you’ve encountered with C-style strings. • In particular, you don’t have to worry about managing memory for the string data.
C++ String Basics • The basic character template class is basic_string<>. • It has two specializations (generated using typedefs), string and wstring. • string corresponds to the C-style string (I.e., const *char). • wstring is an extension for languages that use characters. • You can copy, assign, and compare strings just like you would copy, assign, and compare primitive types (int, double) string a = “Hello”; string b = string(a); string c = a; bool d = (a==b);
using the String types • In the header file <string> • (Note, no .h) • All such functions and other names are in the namespace std. • The basic class name is a template class, basic_string<>. • String constructors string( ) // empty string(string s) // copy of s string(string s, int start) // substring string(string s, int start, int len) // substring string(char* a) // C-string string(int cnt, char c) // one or more chars string(char* beg, char* end) // [beg, end)
Accessing Individual Characters • It’s almost like for a C-string. string s = “Harry”; s[0] is ‘H’ s[1] is ‘a’ … s[5] is undefined!!!! – no ‘\0’ at the end
C++ string Operations • = is used to assign a value (char, C-string, or string) to a string. • += is used to append a string, character, or C-string to a string. • + is used to concatenate two strings or a string with something else • Boolean operations do a dictionary order comparison • << and >> are used for input and output. On input, leading whitespace is skipped, and the input terminates with whitespace or end of file.
Other C++ string Operations swap(a, b); // swap the guts of a with b s.append(s2); // append s2 to s s.c_str( ); // return a C-string s.push_back(c); // append a char s.erase(various); // erases substrings s.insert(various); // inserts substrings s.clear(); // removes all contents s.resize(cnt); // change the size of s to cnt s.replace(various); // replaces characters s.size(); // how many characters? s.length(); // how many characters? s.max_size(); // maximum number of char? s.empty(); // is s empty? s.capacity(); // size without reallocation s.reserve(cnt); // reserves memory
Using c++ string string s = "Harry "; s.data() // returns s as a data array, no '\0' . s.c_str() // returns s as a C-stringwith '\0' int i = atoi(s.c_str()); // conversion char *carray = new char[80]; s.copy(carray, 79); // copies up to 79 char
I/O and File Handling • Using System call • open, read, write, close • Using file pointer • FILE * stdin, *stdout, *stderr, *fp; • Using C++ file object
C/C++ I/O functions • C Library 有關 I/O 的宣告在 <stdio.h> (C++有關 I/O 的宣告在 <iostream> ) • printf(char *, …) 是一個函數(function), 不是特殊 statement ! • scanf(char *, …) 也是 function, 注意要傳變數的 address 給它! • 格式很複雜, 必須小心使用!
再談 I/O (1/6) • Read an integer from keyboard scanf("%d ", &x); /* not good*/ --better approach static char buf[99] gets(buf); /* net safe */ x = atol(buf); /* x=atof(buf); */ -- good approach : use fgets( ) instead of gets( ) fgets(buf, sizeof(buf), stdin); 實數用 atof( ) 參考K&R 課本附錄B 注意fgets 讀入時尾巴比用gets多了new line
再談 I/O (2/6) • 讀入多個資料 int m, n; double x, y; char buf[99]; fgets(buf, sizeof(buf), stdin); n = sscanf(buf, "%d %f %f ", &m, &x, &y); • Other useful library functions • strtol, strtod (類似 atol, atof ) • strtok, strsep (切 token 用) The strsep( ) function is intended as a replacement for the strtok( ) .
再談 I/O (3/6) • Use “f”function to open/read/write file FILE * fp; fp = stdin; /* 從鍵盤 standard input */ fp = fopen("abc.txt", "rt"); /* "rb" for reading binary file */ if(fp==0) { /* error when try to open */ } fscanf(fp, "format_string", … ); /* fread( ) for binary file */ fp = fopen("abc.txt", "wt"); /* "wb" for writing binary file */ fprintf(fp, … ); /* fwrite( ) for binary file */ sprintf(buf, …); /* write into the char array buf */ fseek( FILE* fp, int offset, int fence); fclose(FILE* fp); if( feof(fp) ) { /* end of file */ } if( ferror(fp) ) { /*...*/ clearerr(fp); } /* file error, clear the error flag! */ See"man fopen" 參考K&R 課本附錄B
再談 I/O (4/6) FILE *fopen(const char *path, const char *mode); ''rt'' Open text file for reading. The stream is positioned at the beginning of the file. /* ''rb'' for binary file */ ''r+'' Open for reading and writing. The stream is positioned at the beginning of the file. 用 fread 讀 binary file. 用 fwrite 讀 binary. fread/fwrite 讀寫都不轉換. ''w'' Truncate file to zero length or create text file for writing. The stream is positioned at the beginning of the file. ''wb'' for writing binary file.讀寫不轉換意思是記憶體內外資料相同 ''w+'' Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file. ''a'' Open for writing. The file is created if it does not exist. ''a+'' Open for reading and writing. The file is created if it does no exist. See"man 3 fopen"
再談 I/O (5/6) See next slide • Use system call to open/read/write file int hd; hd = open(" abc.txt ", O_RDONLY); /* 0 */ if(hd== -1) { /* error when try to open */ } n = read(hd, buf, nbytes ); n = write(hd, buf, nbytes); lseek( int hd, int offset, int fence); close(hd); 參考K&R 課本附錄B See"man 2 open"
再談 I/O (6/6) #include <fcntl.h> int hd=open("file.ext", flag); flag for open System call O_RDONLY open for reading only O_WRONLY open for writing only O_RDWR open for reading and writing O_NONBLOCK do not block on open O_APPEND append on each write O_CREAT create file if it does not exist O_TRUNC truncate size to 0 O_EXCL error if create and file exists O_SHLOCK atomically obtain a shared lock O_EXLOCK atomically obtain an exclusive lock O_DIRECT eliminate or reduce cache effects O_FSYNC synchronous writes O_NOFOLLOW do not follow symbolic links See"man 2 open"
C++ I/O facility • C++ usestype safe I/O • Each I/O operation is automatically performed in a manner sensitive to the data type (operator overloading, actually) • In C, what about this: printf("%d", float_data); • Standard I/O streams as Objects: • In C: stdin, stdout, stderr (#include<stdio.h>) • In C++: cin, cout, cerr ( #include <iostream> )
Iostream Library Header Files • <iostream.h>: Containscin, cout, cerr, and clog objects (新版用 <iostream> ) • <iomanip.h>: Contains parameterized stream manipulators (新版用 <iomanip> ) • <fstream.h>:Contains information important to user-controlled file processing operations (新版用 <fstream> )
C++ I/O classes and objects • ios: • istream and ostream inherit from ios • iostream inherits from istream and ostream. • istream: input streams cin >> someVariable; • cin knows what type of data is to be assigned to someVariable (based on the type of someVariable). • ostream: output streams • cout<< someVariable; • cerr<< “Something wrong: “ << haha << endl;
Stream Input/Output Classes and Objects (1/2) • ios: • istream and ostream inherit from ios • iostream inherits from istream and ostream. • << (left-shift operator) • Overloaded as stream insertion operator • >> (right-shift operator) • Overloaded as stream extraction operator • Both operators used with cin, cout, cerr, clog, and with user-defined stream objects
Stream Input/Output Classes and Objects (2/2) • istream: input streams cin >> someVariable; • cin knows what type of data is to be assigned to someVariable (based on the type of someVariable). • ostream: output streams • cout<< someVariable; • cout knows the type of data to output • cerr<< someString; • Unbuffered - prints someString immediately. • clog<< someString; • Buffered - prints someString as soon as output buffer is full or flushed
Stream Output • ostream: performs formatted and unformatted output • Uses put for characters and write for unformatted characters • Output of numbers in decimal, octal and hexadecimal • Varying precision for floating points • Formatted text outputs
Stream-Insertion Operator • << is overloaded to output built-in types • Can also be used to output user-defined types • cout << ‘\n’; • Prints newline character • cout << endl; • endl is a stream manipulator that issues a newline character and flushes the output buffer • cout << flush; • flush flushes the output buffer
Stream Input • >> (stream-extraction) • Used to perform stream input • Normally ignores whitespaces (spaces, tabs, newlines) • Returns zero (false) when EOF is encountered, otherwise returns reference to the object from which it was invoked (i.e. cin) • This enables cascaded input cin >> x >> y; • >> controls the state bits of the stream • failbit set if wrong type of data input • badbit set if the operation fails
C++ I/O class Member Functions • cin.get(): inputs a character from stream • cin.get( c ): inputs a character from stream and stores it in c • cin.get(array, size); • cin.getline(array, size); • cin.ignore(3388, “\n”); • cin.putback(); • int c = cin.peek( ); • cout << setprecision(2) << x; • cout.precision(2); • cout << hex << 123 << endl;
Sample using iostream #include <iostream> using namespace std; int main() { cout.precision (4); cout.width(8); cout<<12.358<<endl; cout.fill ('*'); cout.width (8); cout<<12.135<<endl; cout<<"HaHa"<<endl; cout.width (12); cout.setf(ios::left); cout<<135.625<<endl; return 0; }
Sample using <iomanip> #include <iostream> #include <iomanip> using namespace std; int main() { int n; cout << "Enter a decimal number: "; cin >> n; cout << n << " in hexadecimal is: " << hex << n << '\n‘; cout << dec << n << " in octal is: " << oct << n << '\n' << setbase( 10 ) << n ; cout << " in decimal is: " << n << endl; return 0; }
Using fstream in C++ #include <iostream.h> #include <fstream.h> int main() { ofstream out("myscore.txt"); if(!out) {cout << "Cannot open file myscore.txt.\n"; return 1; } out << "C++ " << 89.5 << endl; out << "English " << 93.5 << endl; out << "Maths " << 87 << endl; out.close(); return 0; }
Open binary file static char a[512]; • 直接在 宣告/定義時給參數: ofstream wf(″data.dat″,ios∷binary); wf.write((char *)a, len); • 宣告/定義後再 open ofstream wf; wf.open(″data.dat″,ios∷binary); wf.write((char *)a, sizeof a);