第三章、c語言高階階段
Day9.指標和結構體
指標補充
1, 指標+1, 並不是真實的+1, 而是+4
2, 指標型別的兩個用途:
第一個用途, 取值的時候, 會根據指標型別所佔用的位元組去取出對應位元組的資料
第二個用途, 用於做加法運算, 指標+1, 其實是加上指標型別所佔用的長度 , 如果當前指標型別是int, 那麼+1本質上是加上4個位元組
3,只要一個指標指向了陣列, 那麼訪問陣列就有3種方式:
1. : ages[0];
2. : p[0];
3. : *(p + 0);
4,指標字串
// 通過陣列儲存字串和通過指標儲存字串的區別
// 如果通過陣列來儲存字串, 那麼字串是一個變數 str 可以修改
// 如果通過指標來儲存字串, 那麼字串是一個常量 str2 不能修該
// 陣列儲存的字串儲存在記憶體的棧中, 而通過指標儲存的字串儲存在常量區
// 儲存在棧中的變數有一個特點, 當作用域結束系統會自動釋放該變數
// 儲存在常量區中的值有一個特點, 不會被釋放, 而且多個相同的值對應的地址相同
// 利用指標儲存字串的應用場景
for (int i = 0; i < 100; i++) {
// 意味著會開闢100塊儲存空間來儲存xmg這個字串
// 並且會釋放100次
// char str5[] = "xmg";
char *str6 = "xmg";
printf("str5 = %s\n", str6);
}
/*
儲存字串的兩種方式:
char str[] = "lnj";
儲存的位置: 棧
特點: 相同的字串會重複的分配儲存空間
字串可以修改
char *str = "lnj"
儲存的位置: 常量區
特點: 相同的字串不會重複的分配儲存空間
字串不可以修改
*/
5,指向函式的指標
指向函式的指標的定義格式
void (*funtionP) ();
* : 代表是一個指標
funtionP : 代表指標變數的名稱, 區分
(*funtionP) : 代表將來指向一個函式
void : 代表將來指向的函式沒有返回值
() : 代表將來指向的函式沒有引數
int (*ageP)();
ageP = getAge;
printf("age = %i\n", ageP());
// void (*sumP)(int v1, int v2);
void (*sumP)(int, int);
sumP = sum;
sumP(10, 20);
int (*sumP2)(int , int);
sumP2 = sum2;
printf("sum = %i\n", sumP2(10, 20));
結構體
// 1.定義結構體型別
struct Person
{
// char name[20];
char *name;
int age;
double height;
};
// 2.定義結構體變數
// int num;
struct Person p;
// 注意: 陣列不能先定義再進行一次性的初始化, 所有下面的寫法是錯誤的
// p.name = "lnj"; // name = {'l', 'n', 'j', '\0'};
// 可以使用 結構體變數名稱.屬性的方式給結構體變數賦值
p.name = "lnj";
p.age = 30;
p.height = 1.75;
/*
int nums[] = {1, 3, 5};
int nums[3];
nums[0] = 1;
nums[1] = 3;
nums[2] = 5;
int nums[3];
nums = {1, 3, 5}; // 錯誤
int nums[3] = {[1] = 2};
printf("nums[0] = %i\n", nums[0]);
*/
struct Dog
{
char *name;
int age;
double height;
};
// 1.定義的同時初始化
struct Dog sd = {"wc", 13, 5.0};
// 2.先定義再初始化(逐個初始化)
struct Dog sd1;
sd1.name = "ww";
sd1.age = 5;
sd1.height = 10.9;
// 3.先定義再初始化(一次性初始化)
struct Dog sd2;
// 特別注意: 結構體和陣列有一點區別, 陣列不能先定義再進行一次性的初始化, 而結構體可以
// 只不過需要明確的告訴系統{}中是一個結構體
sd2 = (struct Dog){"xq", 8, 8.8}; // 陣列? 結構體?
// 4.指定將資料賦值給指定的屬性
struct Dog sd3 = {.height = 1.77, .name = "ww", .age = 33};
printf("name = %s, age = %i, height = %lf\n", sd3.name, sd3.age, sd3.height);
列舉
// 1.定義列舉型別
// 定義列舉型別的規範
// 列舉型別的取值一般以k開頭 後面跟上列舉型別的名稱 跟上當前取值的含義
// 和結構體一樣, 列舉型別的名稱首字母大寫
enum Season
{
kSeasonSpring,
kSeasonSummer,
kSeasonAutumn,
kSeasonWinter
};
enum Gender
{
kGenderMale,
kGenderFemale
};
enum Season es;
es = kSeasonAutumn;
enum Gender eg;
eg = kGenderFemale;
區域性和全域性變數
/*
區域性變數
概念: 區域性變數就是定義在函式, 程式碼塊和函式形參列表中的變數, 我們就稱之為區域性變數
作用範圍: 從定義的那一行開始一直直到遇到大括號結束或者遇到return為止
特點:
相同作用域範圍內不能出現同名的區域性變數
不同作用域範圍內出現同名的區域性變數, 內部的區域性變數會覆蓋外部的區域性變數
注意:
區域性變數沒有固定的初始化值, 如果沒有對區域性變數進行初始化, 那麼區域性變數中是一些隨機的值, 所以在開發中千萬不要使用未初始化的區域性變數
儲存位置:
區域性變數儲存在棧中, 當作用域結束系統會自動釋放棧中的區域性變數
全域性變數
概念: 寫在函式,程式碼塊,形參列表外的變數, 我們就稱之為全域性變數
作用範圍: 從定義的那一行開始一直直到檔案末尾(暫時這樣認為)
特點:
全域性變數和區域性變數可以同名
如果存在和全域性變數同名的區域性變數, 那麼區域性變數會覆蓋全域性變數
注意:
全域性變數如果沒有進行初始化, 那麼系統預設會將全域性變數初始化為0
儲存位置:
全域性變數儲存在靜態區中, 他會隨著程式的啟動而建立, 隨著程式的結束而結束
int num; // 全域性變數 num = 0;
/*
static應用場景":
當某個方法的呼叫頻率非常高, 而該方法中更有些變數的值是固定不變的
那麼這個時候就可以使用static來修飾該變數, 讓該變數只開闢一次儲存空間
這樣可以提高程式的效率和效能
*/
static double pi = 3.1415926; // 固定
巨集
巨集定義在什麼時候替換
原始碼 --> 預處理 -->彙編 -->二進位制 -->可執行程式
規範:
一般情況巨集名都大寫, 多個單詞之間用_隔開, 並且每個單詞全部大寫
有得公司又要求巨集名以k開頭, 多個單詞之間用駝峰命名
#define CLASS_COUNT 100
#define kClassCount 100
帶引數
#define PF(v1) ((v1)*(v1))
// 提前結束巨集定義的作用域
//#undef COUNT
typedef起別名
/*
什麼是typedef, 它有什麼作用
typedef可以給一個已知的資料型別起別名 (外號)
利用typedef給資料型別起別名的格式:
typedef 原有的資料型別 別名(外號);
注意:
1. typedef不僅能給系統原有的資料型別起別名, 也可以給一個自定義的資料型別起別名
2. 利用typedef給資料型別起別名, 並不會生成一個新的資料型別, 僅僅是給原有的型別起了一個別名而已
*/
int sum(int v1, int v2)
{
return v1 + v2;
}
int minus(int v1, int v2)
{
return v1 - v2;
}
// 注意: 如果是給指向函式的指標起別名, 那麼指向函式的指標的指標名稱就是它的別名
// functionPotinter == int(*functionPotinter)(int , int)
typedef int(*functionPotinter)(int , int);
int main(int argc, const char * argv[]) {
// 9如何定義變數 : 資料型別 變數名稱;
// int (*sumP)(int , int ) = sum;
functionPotinter sumP = sum;
printf("sum = %i\n", sumP(10 , 20));
// int (*minusP)(int, int) = minus;
functionPotinter minusP = minus;
printf("minus = %i\n", minusP(20, 10));
return 0;
}
// ----------------------------給指標起別名----------------------------
// String == char *
typedef char * String;
void test4()
{
// char *name = "lnj";
// 注意: 如果給指標起別名之後, 那麼以後利用別名定義變數就不用再加*了
String name = "lnj";
printf("name = %s\n", name);
}
// ----------------------------給列舉型別起別名----------------------------
// 1.先定義列舉型別, 再給列舉型別起別名
/*
enum Gender
{
kGenderMale,
kGenderFemale
};
typedef enum Gender SEX;
*/
// 2.定義列舉型別的同時給列舉型別起別名
/*
typedef enum Gender
{
kGenderMale,
kGenderFemale
} SEX;
*/
// 3.定義列舉型別的同時給列舉型別起別名, 並且省略列舉原有型別名稱
typedef enum
{
kGenderMale,
kGenderFemale
} SEX;
void test3()
{
// 給列舉起別名
// enum Gender sex;
SEX sex;
sex = kGenderMale;
/*
定義列舉變數有3種方式
1.先定義列舉型別, 再定義列舉變數
2.定義列舉型別的同時定義列舉變數
3.定義列舉型別的同時定義列舉變數, 並且省略列舉型別名稱
*/
/*
enum Gender2
{
kGenderMale2,
kGenderFemale2
} sex2;
sex2 = kGenderFemale2;
enum
{
kGenderMale3,
kGenderFemale3
} sex3;
sex3 = kGenderFemale3;
*/
}
// ----------------------------給結構體型別起別名----------------------------
// 1.先定義結構體型別, 再給型別起別名
/*
struct Person
{
int age;
double height;
char *name;
};
// SPerson == struct Person
typedef struct Person SPerson;
*/
// 2.定義結構體型別的同時, 給結構體型別起別名
/*
typedef struct Person
{
int age;
double height;
char *name;
} SPerson;
*/
// 3.定義結構體型別的同時, 給結構體型別起別名, 並且省略掉原有型別的名稱
typedef struct
{
int age;
double height;
char *name;
} SPerson;
void test2()
{
/*
// 給構造型別起別名
struct Person
{
int age;
double height;
char *name;
};
*/
// struct Person sp0;
SPerson sp;
SPerson sp1;
SPerson sp2;
SPerson sp3;
SPerson sp4;
/*
結構體變數的定義方式
1.先定義型別再定義變數
2.定義型別的同時定義變數
3.定義型別的同時定義變數, 並且省略型別名稱
*/
}
// ----------------------------給基本資料型別起別名----------------------------
// Integer == int
typedef int Integer;
typedef Integer myInt;
// int float doulbe char
void test1()
{
int num = 10;
printf("num = %i\n", num);
Integer age = 30;
printf("age = %i\n", age);
myInt score = 99;
printf("score = %i\n", score);
}
// 一般情況下如果要給資料型別起一個名稱建議用typedef, 不要用define
最後的建議如果想了解透徹c語言還是看看程式碼比較好。
相關文章
- 高階C語言1C語言
- 高階C語言2C語言
- 高階C語言7C語言
- c#語言-高階函式C#函式
- C語言學習的幾個階段C語言
- C語言巨集的高階應用C語言
- “高階”的程式語言是否真的高階?
- Linux C語言高階學習第四天(C高階-函式)LinuxC語言函式
- 從高階語言到機器語言
- c++進階(一)C語言條件編譯及編譯預處理階段C++C語言編譯
- python是高階語言嗎Python
- c語言實現階乘C語言
- 逍遙自在學C語言 | 位運算子&的高階用法C語言
- 逍遙自在學C語言 | 位運算子^的高階用法C語言
- SQL語言基礎(高階查詢)SQL
- 雜談現代高階程式語言
- C語言進階[2]:字串常量C語言字串
- python高階函式和C語言函式指標Python函式C語言指標
- Typescript 高階語法進階TypeScript
- 最新拓薪Java高階階段及ERP實戰專案(階段三)Java
- 高階語言實現的幾個點
- R語言學習-高階資料管理R語言
- 逍遙自在學C語言 位運算子 "|" 的5種高階用法C語言
- C++高階語言程式設計案例與實踐輔導pdfC++程式設計
- 高階程式設計師——java語言深度解析程式設計師Java
- 高階語言程式設計作業 10/12程式設計
- 高階語言程式設計作業 11/04程式設計
- C語言用遞迴方法求解階乘C語言遞迴
- C語言_簡單的階乘函式C語言函式
- 易語言進階
- C++高階功能C++
- c語言以及高階語言中的float到底是什麼以及IEEE754C語言
- R語言實戰試卷 第三章 圖形初階R語言
- javascript高階程式設計第三章JavaScript程式設計
- 函數語言程式設計(2) 高階函式函數程式設計函式
- 高階程式設計語言第2次作業程式設計
- 高階語言程式設計第2次作業程式設計
- 高階程式語言設計第5次作業