c-指標進階篇
指標函式
指標函式:
1.引數是指標
1.1 在子函式中,修改普通的實參的值,傳的是普通實參的地址(一級指標),在函式中修改是*一級指標
1.2 在子函式總,修改指標的實參的值,傳的是指標實參的地址(二級指標),在子函式中修改是*二級指標
指標最基本的使用
void modify(int* a) //int *a=# 賦值操作,形參,實參型別一致
{
*a = 1001; //*一級指標
} //在子函式中,修改普通的實參的值,傳的是普通實參的地址(一級指標),在子函式中修改是*一級指標
int main()
{
int num = 1;
modify(&num);
printf("%d\n", num);
int aa = 1;
int bb = 1001;
return 0;
}
在子函式中,修改的是*a
交換a,b的值,使其可以在主函式當中輸出
void Swap(int* a, int* b) //交換a,b的值,使其可以在主函式當中輸出
{
int temp = *a;
*a = *b;
*b = temp;
} //子函式當中修改了函式的值
int main()
{
int aa = 1;
int bb = 1001;
Swap(&aa, &bb); //傳參就係要傳實參的地址
printf("a=%d,b=%d\n", aa, bb);
return 0;
}
在子函式總,修改指標的實參的值,傳的是指標實參的地址(二級指標),在子函式中修改是*二級指標
int g_num = 1001;
void modifyPoint(int** p) //在當前函式中修改指標的指向,由p指向num改為p指向g_num
{ //在子函式總,修改指標的實參的值,傳的是指標實參的地址(二級指標),在子函式中修改是*二級指標
*p = &g_num; //修改p的指向需要p的地址,就要傳二級指標**p
}
int main()
{
num = 1111;
int* p = #
modifyPoint(&p);
printf("%d\n", *p);
returnPremer2(p);
return 0;
}
2.反回值是指標
2.1 不能返回區域性變數地址
2.2 規定用int型別的返回變數,int*型別的返回變數的地址,int返回變數
int* returnNum() //合法
{
return &g_num;
}
//int a 是區域性變數 不能返回區域性變數的地址
int* returnPremer(int a) //1
{
return &a; //return 1對 return &1錯
}
int* returnPremer2(int* a) //傳入的是指標變數的值,不是區域性變數
{
return a; //所以返回指標變數的值
}
陣列中
//在陣列中
void initArray(int array[], int arrayNum) //傳陣列的專用寫法
{
for (int i = 0; i < arrayNum; i++)
{
array[i] = i;
}
}
void initArray2(int* array, int arrayNum) //傳指標或地址的寫法
//int array[],int* array兩種寫法等效
{ //相當於傳一級指標
for (int i = 0; i< arrayNum; i++)//array 等效於&array[0](第一的元素的地址) int *array
{
array[i] = i;
}
}
字串函式(string.h)
int strcmp(char const* _Str1, char const* _Str2);//字串比較函式
//str1>str2 返回值大於0 1
//str1==str2 0
//str1<str2 -1
strlen(char const* _Str); //計算字串可見長度
strcat(str,str); //字串連線
strcpy(str,str); //字串拷貝
#include <string.h> //字串處理標頭檔案
#include <stdio.h>
int main()
{
//int strcmp(char const* _Str1, char const* _Str2);
//str1>str2 返回值大於0 1
//str1==str2 0
//str1<str2 -1
char str1[] = "ABC";
char str2[] = "ACB";
char str3[] = "ACB";
//mystrcmp
if (strcmp(str1, str2) > 0) //
{
printf("str1>str2\n");
}
if (strcmp(str2, str3) == 0)
{
printf("str2==str3\n");
}
//size_t 等效 unsigned int
//size_t strlen(char const* _Str);
printf("%d\n", strlen(str1));
int size = strlen(str1) + 1; // +\0
//字串連線 strcat
char strInfo[1024] = "ILoveyou";
strcat(strInfo, str1); //字串必須要空間足夠,前面的字串必須大於兩個字串的總長度
puts(strInfo); //列印字串
//字串拷貝 strcpy
//C語言中操作字串不能直接賦值
char strA[] = "ILoveLOUU";
char strB[] = "IMissYou";
//strA = strB; 不能直接賦值
strcpy(strA, strB); /*一定要能裝的下,第一個要大於等於第二個,一般用於字串賦值,和
作用原理,把第一個清空掉在賦值,陣列申請的空間長度空間長度不會改變,裝不下的話會溢位*/
printf("strA:%s\n", strA);
printf("strB:%s\n", strB);
//字串函式都是處理到\0
char str11[10] = "abc";
char str22[12] = "ABCD";
strcpy(str11, str22);
puts(str11);
//不常見的:
//1.大寫轉小寫
char ABC[] = "ABCDd";
_strlwr(ABC);//'_'是vs對函式做了修改
puts(ABC);
//2.小寫轉大寫
_strupr(ABC);
puts(ABC);
return 0;
}
字串賦值溢位時報錯,順便教幾個單詞
動態申請記憶體
1.動態申請記憶體
動態申請的記憶體是堆記憶體,特點 人為申請,手動釋放
size_t 就是 unsigned int 無符號整型的另一個名字(正整數)
void *malloc(size_t size); 使用時需要強制轉換
(int*)malloc(sizeof(int))
前面(int*)是: 指標型別 //去掉變數名
後面是(int): 指標所指向的型別 //去掉變數名和* 你要儲存的資料型別
2.free(void *point);
3. 野指標: 沒有指向的指標
NULL :通常會給指標一個指向
動態記憶體申請的格式
void *malloc(size_t size); //void *說明使用malloc函式時需要強制轉換
釋放格式
free(void *point);
只申請一個變數記憶體
//只申請一個變數記憶體
int* pInt = (int*)malloc(sizeof(int));
//指標變成變數,有兩種方式
//1.指向變數的地址
*pInt1001;//*+地址就是一個變數
//int* pVoid = NULL;
//*pVoid=1001; *pVoid不能被改變,NULL是空,相當於0,是常量,常量不能改變
//2.申請堆記憶體,只要申請了堆記憶體,它就是一個變數
動態記憶體申請的好處
int* malloNum() //所做的操作會被保留
{
int* p = (int*)malloc(sizeof(int));
*p = 1002;
return p;
}
申請一段記憶體: 陣列
int arrayNum = 0;
scanf("%d", &arrayNum);
int* pArray = (int*)malloc(sizeof(int) * arrayNum); //pArray[5],申請陣列
for (int i = 0; i < arrayNum; i++)
{
pArray[i] = i;
printf("%d\t", pArray[i]);
}
printf("\n");
//釋放一定要置空
free(pInt);//釋放指標
pInt = NULL;
free(pArray);
pArray = NULL;
通過二級指標去理解二維陣列
int** makeArray2D(int row, int cols)
{
//int *array --->array[i] 存放多個整數
//int **p--->(*p)[i] 存放多個一級指標
//p[i]---> 存放多個整數
//二級指標如何變成二維陣列
int **p = (int **)malloc(sizeof(int*) * row); //指標型別(int **),
for (int i = 0; i < row; i++)
{
p[i] = (int*)malloc(sizeof(int) * cols);
}
return p;
}
int main()
{
//通過二級指標去理解二維陣列
//二級指標如何變成二維陣列
int** array2D = makeArray2D(2, 2);
array2D[1][1] = 1001;
printf("%d\n", array2D[1][1]);
free(array2D);
array2D = NULL;
return 0;
}
釋放問題:在哪裡申請的, 在哪個位置釋放
//釋放問題: 在哪裡申請的, 在哪個位置釋放
int* pMove = (int*)malloc(sizeof(int) * 3);
//正常的使用
pMove[0] = 1;
pMove[1] = 2;
pMove[2] = 3;
//做了指標指向的改變
pMove++; //此時pMove指向pMove[1]
//pMove[i]等效於 *(pMove+i) 指標的運算
printf("pMove[-1]=%d\n", pMove[-1]);
//釋放前要還原指標原來的指向
--pMove;
free(pMove);//從哪裡申請就要從哪裡釋放
pMove = NULL;
其他釋放函式
//1
//malloc申請的記憶體是沒有初始化,存放的是垃圾值
//void * calloc(size_t count,size_t size); 申請記憶體過程中初始化
int* pMalloc = (int*)malloc(4 * sizeof(int));
memset(pMalloc, 0, sizeof(int) * 4); //設定記憶體每個位元組的值
int* pCalloc = (int*)calloc(4, sizeof(int));//(4, sizeof(int))相當於(4 * sizeof(int))
//以上三句話中,前兩句話相當於第三句話
free(pMalloc); //使用完後要釋放
pMalloc = NULL;//一定要為空,否則成為野指標
free(pCalloc);
pCalloc = NULL;
//2
//為指標重新申請記憶體
//void *realloc(void *p,size_t size);
int* pRealloc = (int*)malloc(sizeof(int) * 2);
pRealloc[0] = 1;
pRealloc[1] = 2;
printf("%p\n", pRealloc + 1);
printf("%p\n", pRealloc + 2);
pRealloc=(int *)realloc(pRealloc, sizeof(int) * 4);//重新申請的空間一定要比上次的大
//該返回值指向重新申請的空間的首地址
pRealloc[2] = 3;
pRealloc[3] = 4;
printf("%p\n", pRealloc + 1);
printf("%p\n", pRealloc + 2);
for (int i = 0; i < 4; i++)
{
printf("%d\t", pRealloc[i]);
}
printf("\n");
free(pRealloc);
pRealloc = NULL;
指標陣列與陣列指標
1.如何區分指標陣列,陣列指標
看主謂賓
整形陣列: 存放的整數的陣列,他是多個整數
指標陣列: 指標的陣列 --->他是陣列
存放多個指標的陣列,他是多個指標
陣列指標: 陣列的指標 --->他是一個指標
2. 功能
2.1 指標陣列一般是用來操作字串
2.2 陣列指標-->表示二維陣列
2.2.1 變成二維陣列
2.2.2 當做二維陣列的指標使用
指標陣列
一般是用來操作字串
//指標陣列
int a = 1;
int b = 2;
int c = 3;
int* pInt[3];//每一個pInt[i]都可以存放一個指標,數字類比較少用
//pInt[i] 多個一級指標
pInt[0] = &a;
pInt[1] = &b;
pInt[2] = &c;
const char* p = "ILove";//一級指標可以操作一個字串,所以常用指標陣列操作多個字串
const char* pStr[3] = {"ILove","IMissyou","wantyou"};
for (int i = 0; i < 3; i++)
{
puts(pStr[i]);//pStr[i]是一級指標,puts自動換行
//好處,每個字串的申請空間可以不相同
}
陣列指標
可以表示二維陣列
2.2.1 變成二維陣列
2.2.2 當做二維陣列的指標使用
傳二維陣列時的一個錯誤做法
void print(int array[][3], int row, int cols)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < cols; j++)
{
printf("%d\t", array[i][j]);
}
printf("\n");
}
}
int main()//真正的二維陣列其實不是二維指標
{
int array[2][3] = { 1, 2, 3, 4, 5, 6 };
//“函式”:“int (*)[3]”與“int **”的間接級別不同
int **p = array;
print(p, 2, 3); //按規矩來說其實本身不允許這樣寫
//c語言中可以執行,但是會有問題,如下圖。但是c++中會報錯
return 0;
}
當看到有以下問題時,將其當做錯誤程式碼處理
這些都是因為指標的型別不一致,一般情況下陣列與二級指標是有區別的,所以一般情況下我們傳的是陣列指標
正確做法將後半段改為
int array[2][3] = { 1, 2, 3, 4, 5, 6 };
//陣列指標
int (*p)[3] = array; //這裡做了改變
//*優先跟p結合在一起,就形成了一個指標,這個指標是指向一個陣列的,這個陣列的長度是三
print(p, 2, 3);
陣列指標如何申請記憶體
變成二維陣列
//陣列指標如何申請? 讓他變成二維陣列
//(指標的型別)malloc(sizeof(指標所指向的型別)*n);
//指標的型別:去掉變數
//指標所指向的型別:去掉變數名和*
int(*pArray)[3] = (int(*)[3])malloc(sizeof(int[3]) * 2); //等效 int pArray[2][3];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
pArray[i][j] = i + j;
printf("%d\t", pArray[i][j]);
}
printf("\n");
}
free(pArray);
pArray = NULL;
相關文章
- JavaScript進階之(一) this指標JavaScript指標
- C++進階(智慧指標)C++指標
- 【C進階】28、指標和陣列分析指標陣列
- 【C進階】26、指標的本質分析指標
- 指標高階指標
- 指標初階指標
- Rust 程式設計影片教程(進階)——009 智慧指標Rust程式設計指標
- Go語言高階資料型別之指標篇Go資料型別指標
- Rust 程式設計視訊教程(進階)——009 智慧指標Rust程式設計指標
- Rust 程式設計影片教程(進階)——028_1 函式指標Rust程式設計函式指標
- React進階篇2React
- React進階篇1React
- 【webpack 系列】進階篇Web
- C語言重點——指標篇(一文讓你完全搞懂指標)| 從記憶體理解指標 | 指標完全解析C語言指標記憶體
- Rust 程式設計視訊教程(進階)——028_1 函式指標Rust程式設計函式指標
- Rust 程式設計影片教程(進階)——025_2 解引用裸指標Rust程式設計指標
- python網路進階篇Python
- 介面測試進階篇
- 樹莓派-進階篇樹莓派
- 《MySQL 進階篇》二十:鎖MySql
- Rust 程式設計影片教程(進階)——013 使用 Rc 引用計數智慧指標Rust程式設計指標
- Rust 程式設計視訊教程(進階)——025_2 解引用裸指標Rust程式設計指標
- 指標還沒弄清楚?一篇文章搞定 “地址、指標、指標的指標、引用”,並附程式碼示例,建議收藏!指標
- Android面試題——進階篇Android面試題
- Dagger2進階篇(二)
- web前端進階篇(一 )JSWeb前端JS
- 【資料庫】Redis進階篇資料庫Redis
- fx 框架上手 - 進階篇框架
- Nginx--進階篇(實踐)Nginx
- Rust 程式設計視訊教程(進階)——013 使用 Rc 引用計數智慧指標Rust程式設計指標
- Java面試題中高階進階(JVM篇01)Java面試題JVM
- Go高階特性 12 | 指標詳解:在什麼情況下應該使用指標?Go指標
- C-隨筆1
- iOS逆向之旅(進階篇) — 工具(LLDB)iOSLLDB
- iOS逆向之旅(進階篇) — HOOK(Logos)iOSHookGo
- iOS逆向之旅(進階篇) — HOOK(FishHook)iOSHook
- go 單元測試進階篇Go
- [ ES6 ] 進階篇(一) —— PromisePromise