__func__
當前函數的名字
全域性變數初始化:
區域性變數不會初始化:
#include <stdio.h>
int f(void);
int gAll = f(); // 指明不是一個編譯時刻的常數,不可如此寫
int main(int argc, char const *argv[]) {
printf("in %s gAll=%d\n", __func__, gAll);
f();
printf("agn in %s gAll=%d\n", __func__, gAll);
return 0;
}
int f(void) {
printf("in %s gAll=%d\n", __func__, gAll);
gAll += 2;
printf("agn in %s gAll=%d\n", __func__, gAll);
return gAll;
}
#include <stdio.h>
int f(void);
const int gAll = 12;
int g2 = gAll;
int main(int argc, char const *argv[]) {
printf("in %s gAll=%d\n", __func__, gAll);
f();
printf("agn in %s gAll=%d\n", __func__, gAll);
return 0;
}
int f(void) {
printf("in %s gAll=%d\n", __func__, gAll);
// gAll += 2;
printf("agn in %s gAll=%d\n", __func__, gAll);
return gAll;
}
不建議如此做
相同的變數,原生的會覆蓋全域性的變數
*返回指針的函數
tips:
編譯預處理指令:
#define:
宏:
沒有值的宏:
#define _DEBUG
這類宏是用於條件編譯的,後面有其他的編譯預處理指令來檢查這個宏是否已經被定義過了
檢查是否存在來做條件編譯程式碼
預定義的宏:
像函數的宏:
#define cube(x) ((x)*(x)*(x))
宏可以帶參數,但是參數沒有型別
帶參數的宏的原則:
一切都要括號
#define RADTODEG(x) ((x)*57.29578)
帶參數的宏:
可以帶多個參數
#define MIN(a, b) ((a)>(b)?(b):(a))
也可以組合(巢狀)使用其他宏
其他編譯預處理指令:
多個.c檔案:
專案:
編譯單元:
其他c檔案使用這個c檔案的時候,呼叫它的h檔案,是爲了告訴其他c檔案原來它的函數原型是這樣的
這個c檔案呼叫自己的h檔案是爲了檢查函數型別是否一致
標頭檔案是橋樑,是合同
#include:
""還是<>:
#include的誤區:
標頭檔案:
不對外公開的函數:
變數的宣告:
宣告和定義:
宣告是不產生程式碼的東西
定義是產生程式碼的東西
以上的都是宣告,因爲他不產生程式碼,只是告訴你有這個東西
標頭檔案:
重複宣告:
標準標頭檔案結構:
#ifndef __LIST_HEAD__
#define __LIST_HEAD__
#include "node.h"
typedef struct _list {
Node* head;
Node* tail;
} List;
#endif
printf
%[flags][width][.prec][hIL]type
Flags | 含義 |
---|---|
- | 左對齊 |
+ | 在前面放+或- |
(space) | 正數留空 |
0 | 0填充 |
width或.prec(width指整個輸出佔的位數) | 含義(用於格式靈活性) |
---|---|
number | 最小字元數 |
* | 下一個參數是字元數 |
.number | 小數點後的位數 |
.* | 下一個參數是小數點後的位數 |
#include <stdio.h>
int main(int argcm char const *argv[]) {
printf("%*d\n", 6, 123); // 123
printf("%9.2f\n", 123.0); // 123.00
return 0;
}
型別修飾(hIL,修飾type) | 含義 |
---|---|
hh | 單個位元組 |
h | short |
l | long |
ll | long long |
L | long double |
type | 用於 | type | 用於 |
---|---|---|---|
i或d | int | g | float |
u | unsigned int | G | float |
o | 八進制 | a或A | 十六進制浮點 |
x | 十六進制 | c | char |
X | 字母大寫的十六進制 | s | 字串 |
f或F | float,6 | p | 指針 |
e或E | 指數 | n | 讀入/寫出的個數 |
#include <stdio.h>
int main(int argc, char const *argv[]) {
int num;
printf("%dty%n\n", 12345, &num); // 到%n之前已經輸出了多少個字元;12345ty
printf("%d\n", num); // 7
return 0;
})
scanf
%[flag]type
flag | 含義 | flag | 含義 |
---|---|---|---|
* | 跳過 | l | long,double |
數位 | 最大字元數 | ll | long long |
hh | char | L | long double |
h | short |
type | 用於 | type | 用於 |
---|---|---|---|
d | int | s | 字串(單詞) |
i | 整數,可能爲十六進制或八進制 | […] | 所允許的字元 |
u | unsigned int | p | 指針 |
o | 八進制 | ||
x | 十六進制 | ||
a,e,f,g | float | ||
c | char |
[^.]:到逗號之前的所有東西
//$GPRMC,004319.00,A,3016.98468,N,12006.39211,E,0.047,,130909,,,D*79
// 上方是GPS模組會產生的1083協定的數據
scanf("%*[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,]", sTime, sAV, sLati, &sNW, sLong, &sEW, sSpeed, sAngle, sDate); // 讀取上面的數據,第一個是逗號之前的所有東西都跳過不要
printf和scanf的返回值:
用>和<做重定向
FILE:
FILE* fopen(const char *restrict path, const char *restrict mode);
int fclose(FILE *stream);
fscanf(FILE*, ...);
fprintf(FILE*, ...);
開啓檔案的標準程式碼:
FILE *fp = fopen("file", "r");
if (fp) {
fscanf(fp, ...);
fclose(fp);
} else {
...
}
#include <stdio.h>
int main(int argc, char const *argv[]) {
FILE *fp = fopen("12.in", "r");
if (fp) {
int num;
fscanf(fp, "%d", &num);
printf("%d\n", num);
fclose(fp);
} else {
printf("無法開啓檔案!\n");
}
return 0;
}
fopen:
mode | 功能 |
---|---|
r | 開啓只讀 |
r+ | 開啓讀寫,從檔案頭開始 |
w | 開啓只寫。如果不存在則新建,如果存在則清空 |
w+ | 開啓讀寫。如果不存在則新建,如果存在則清空 |
a | 開啓追加。如果不存在則新建,如果存在則從檔案尾開始 |
…x | 只新建,如果檔案已存在則不能開啓 |
文字vs二進制:
程式爲什麼要檔案:
二進制讀寫:
size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
注意FILE指針是最後一個參數
返回的是成功讀寫的位元組數
爲什麼nitem?
// student.h
#ifndef _STUDENT_H_
#define _STUDENT_H_
const int STR_LEN = 20;
typedef struct _student {
char name[STR_LEN];
int gender;
int age;
} Student;
#endif
#include <stdio.h>
#include "student.h"
void getList(Student aStu[], int number);
int save(Student aStu[]. int number);
int main(int argc, char const *argv[]) {
int number = 0;
printf("輸入學生數量:");
scanf("%d", &number);
Student aStu[number];
getList(aStu, number);
if (save(aStu, number)) {
printf("儲存成功\n");
} else {
printf("儲存失敗\n");
}
return 0;
}
void getList(Student aStu[], int number) {
char format[STR_LEN];
sprintf(format, "%%%ds", STR_LEN - 1); // 產生格式字串,%%指%
// "%19s", 20-1是因爲字串陣列最後留一個"\0"
int i;
for (i=0; i<number; i++) {
printf("第%d個學生:\n", i);
printf("\t姓名:");
scanf(format, aStu[i].name);
printf("\t性別(0-男,1-女,2-其他):");
scanf("%d", &aStu[i].gender);
printf("\t年齡:");
scanf("%d", &aStu[i].age);
}
}
int save(Student aStu[], int number) {
int ret = -1;
FILE *fp = fopen("Student.data", "w");
if (fp) {
ret = fwrite(aStu, sizeof(Student), number, fp);
fclose(fp);
}
return ret == number;
}
在檔案中定位:
long ftell(FILE *stream);
int fseek(FILE *stream, long offset, int whence);
// whence的參數:
// SEEK_SET:從頭開始
// SEEK_CUR:從當前位置開始
// SEEK_END:從尾開始(倒過來)
#include <stdio.h>
#include "student.h"
void read(FILE *fp, int index);
int main(int argc, char const *argv[]) {
FILE *fp = fopen("student.data", "r");
if (fp) {
fseek(fp, 0L, SEEK_END);
long size = ftell(fp); // 返回當前的位置,其實在這裏就是指檔案的大小
int number = size / sizeof(Student);
int index = 0;
printf("有%d個數據, 你要看第幾個:", number);
scanf("%d", &index);
read(fp, index - 1);
fclose(fp);
}
return 0;
}
void read(FILE *fp, int index) {
fseek(fp, index*sizeof(Student), SEEK_SET);
Student stu;
if (fread(&stu, sizeof(Student), 1, fp) == 1) {
printf("第%d個學生:\n", index + 1);
printf("\t姓名:%s\n", stu.name);
printf("\t性別:");
switch (stu.gender) {
case 0: printf("男\n"); break;
case 1: printf("女\n"); break;
case 2: printf("其他\n"); break;
}
printf("\t年齡:%d\n", stu.age);
}
}
可移植性:
按位元運算:
& // 按位元的與
| // 按位元的或
~ // 按位元取反
^ // 按位元的互斥或
<< // 左移
>> // 右移
按位元與&:
按位元或|:
按位元取反~:
邏輯運算vs按位元運算:
按位元互斥或^
左移<<:
右移>>:
左移不管符號位
移位的位移不要用負數,這是沒有定義的事情
輸出一個數的二進制:
#include <stdio.h>
int main(int argc, char const argv[]) {
int number;
scanf("%d", &number);
unsigned mask = 1u<<31;
for (; mask; mask>>=1) {
printf("%d", number & mask? 1 : 0);
}
printf("\n");
return 0;
}
位元欄:控制多個bite
struct {
unsigned int leading: 3; // 冒號後面的數表示這個成員佔幾個bite
unsigned int FLAG1: 1;
unsigned int FLAG2: 1;
int trailing: 11;
};
#include <stdio.h>
void prtBin(unsigned int number);
struct U0 {
unsigned int leading: 3;
unsigned int FLAG1: 1;
unsigned int FLAG2: 1;
int trailing: 27;
};
int main(int argc, char const *argv[]) {
struct U0 uu;
uu.leading = 2;
uu.FLAG1 = 0;
uu.FLAG2 = 1;
uu.trailing = 0;
printf("sizeof(uu)=%lu\n", sizeof(uu));
prtBin(*(int*)&uu); // 取得uu的地址然後把struct U0型別的指針強制轉換爲int型別指針,並取得地址所指向的值
return 0;
}
void prtBin(unsigned int number) {
unsigned mask = 1u<<31;
for (; mask; mask>>=1) {
printf("%d", number & mask? 1 : 0);
}
printf("\n");
}
位元欄: