C語言之指針二

函數指針

如果在程序定義了一個函數,在編譯時,編譯系統爲函數代碼分配一段存儲空間,這段存儲空間的起始地址,稱爲這個函數的指針 

函數名就是函數開始的地址


函數二級指針可以修改函數指針的指向


函數指針,不僅僅是地址,必須明確函數指針類型和輸出參數類型和數量
函數名可以作爲參數傳遞給函數指針

#include <stdio.h>
#include <stdlib.h>

int add(int a, int b)
{
	return a + b;
}

void print()
{
	printf("你好,明天\n");
}

int main()
{
	printf("%p %p\n", add, print);

	void(*p)() = print;     //聲明函數指針,並初始化函數指針
	int(*pa)(int a, int b) = add;	//聲明函數指針,並初始化函數指針
									//初始化指針只能傳遞地址

	print();			//直接調用
	p();				//調用函數指針,相當於調用函數,間接調用

	printf("%d\n",pa(12,36));

	system("pause");
}


函數的返回值可以是指針

#include <stdio.h>
#include <stdlib.h>
#include<time.h>

//函數,返回一個地址,對於數組而言,函數參數調用沒有副本機制
//函數返回值是一個指針類型的函數
int* mindata(int a[], int n)		//查找最小數 
{
	int *p = NULL;	//聲明指針變量,指向空指針,最後保存最小值的地址
	int min = a[0];
	p = &a[0];
	for (int i = 1; i < n; i++)  //選擇法
	{
		if (min > a[i])
		{
			min = a[i];
			p = &a[i];
		}
	}
	printf("最小的值爲%d\n",*p);
	return p;			//返回最小值的地址
}

int main()
{
	int a[10];
	time_t ts;
	srand((unsigned int)time(&ts));	 //按照時間設置隨機數種子
	for (int i = 0; i < 10; i++)
	{
		a[i] = rand() % 100;
		printf("%d\n",a[i]);
	}

	int *p = mindata(a,10);  //獲取最小數的地址

	//此時 直接修改*p 可以起到修改最小值  如,*p = 35;
	printf("%d\n",p -a);   //可以知道下標符號

	system("pause");
}

左值,能放在賦值號左邊的值
int *const px;   //指針常量


寫一個和strcpy函數功能相同的函數

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//寫一個和strcpy函數功能相同的函數
char* mystrcpy(char* dest, char* source)  //兩個參數目的 ,來源
{
	char * last = NULL;			//最後結果
	if (dest == NULL || source == NULL)
	{
		return last;    //如果傳入的兩個字符串有一個是指向空指針的,結束函數
	}
	last = dest;//存入首地址
	while ((*dest++  = *source++) != '\0');
									//沒有遇到字符 '/0',一直拷貝數據
	return last;
}

int main()
{
	char str[40] = {0};

	//char * p = mystrcpy(str, "你好明天\n");		//聲明一個指針接受字符串str的首地址
	//printf("%p %p\n",str,p);				地址相同
	//printf("%s", p);
	//printf("地址爲%p\n", strcpy(str, "你好明天\n"));//strcpy函數返回字符串str的地址


	printf("%s", strcpy(str, "山陰路的夏天\n"));    //兩條語句的作用相同,函數沒有問題
	printf("%s", mystrcpy(str, "你好明天\n"));    //兩條語句的作用相同,函數沒有問題
	
	system("pause");
}


指針包括 類型和地址,將地址轉換爲指針,需要進行類型的轉換
如:
int* p;
int x;
scanf("%x",&x);
p = (int*) x;   //將地址轉換爲指針
 
void指針和空指針
void* 類型的指針,只包含地址不包含類型,是不指向任何類型的指針,任何類型都可以賦值給空類型指針,純地址的賦值,但指向不明確,大小不確定,無法取出內容,如果需要取讀地址的內容
應先對地址進行類型的轉換,一般用於參數還有返回值,不明確指針類型的情況傳遞地址,如  malloc() 函數的返回值


int* p =NULL;//不指向任何地址,即沒有初始化,空指針,*p等價於int類型,p等價於int*類型


void *p = malloc(20); //分配20個字節的內存,返回值賦值給void*類型指針變量p,可以轉換成任何類型的指針,malloc函數在stdlib.h頭文件中
int *px = (int*)p;     //強制轉換指針類型,使分配的內存可以按照int類型解析
ferr(p); //根據地址釋放指針,此時p爲迷途指針

p = NULL;

動態內存分配

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>

//void* calloc(size_t num.size_t size)
//分配內存函數,第一個參數爲個數,第二個參數爲內存大小,內存自動初始化爲0
//void* realloc(void *ptr,size_t size)爲以分配的內存重新分配空間並複製內容。
//參數一,已分配的內存地址,參數二重分配的字節數		如果能拓展就拓展,不能就重新分配

int main()
{
	int x;
	scanf("%d",&x);
	int *p = (int *)malloc( sizeof(int) * x );		//分配 x乘於int類型字節數的內存
	//分配失敗則返回一個空指針NULL,返回值爲空類型指針 malloc(1024) == NULL 判斷是否分配成功
	//指針變量p指向分配的內存之後,不應更改指針的指向
	
	//實現動態數組,按照數組的方式訪問,
	for (int *px = p,i = 0; px < p+x; i++,px++)		//指針法
	{
		*px = i;
		printf("%d\n",*px);
	}
	free(p);			//根據地址釋放內存,一定要記得釋放內存,除非空指針能反覆釋放
	p = NULL;			
	//內存釋放之後,指針應該賦值爲空,可以規避再次引用和反覆釋放的問題
									
	//for (int i = 0; i < x; i++)		//下標法
	//{
	//	p[i] = i;
	//	printf("%d\n",p[i]);
	//}

        system("pause");
}




靜態內存分配由編譯器完成,如爲一個不大的數組分配內存

動態內存分配

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

void detection(float* str)
{
	for (int i = 0; i < 5; i++)
	{
		if (str[i] < 60)
			printf("不及格成績爲%.2f 第%d個\n", str[i], i + 1);
	}

}

int mainaa()
{
	float* p = (float*)malloc(5 * sizeof(int));

	printf("輸入五個成績並以空格隔開\n");
	scanf("%f %f %f %f %f", p, p + 1, p + 2, p + 3, p + 4);
	detection(p);
	free(p);		//釋放內存
	system("pause");
}





return 也有副本機制,存儲在寄存器中,無法取地址  

一級指針作爲函數返回值返回地址,一定不能返回指向棧的地址

#include<stdio.h>
#include <stdlib.h>

//void swap(int* pa, int* pb)			//無法交換pa pb的值
//{
//	int *p = pa;
//	pa = pb;
//	pb = pa;
//
//}

void swap(int* pa, int* pb)			//可以交換pa pb的值
{
	int *p = pa;
	*pa = *pb;
	*pb = *p;

}

int main()
{
	int a, b;
	int *pa = &a, *pb = &b;
	scanf_s("%d %d", pa, pb);
	printf("%d %d\n", a, b);
	swap(pa,pb);
	printf("%d %d\n", a, b);
	system("pause");
}




char *p = "你好,明天"; //指針存儲常量字符串首地址,常量字符串不能修改


一級指針75% 二級指針20%,三級 四級指針.....N級指針 用於權限管理???
沒有初始化的指針叫也指針
更高級指針可以改變低級指針的指向
   
指針聲明一定要初始化


#作用:加上雙引號
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章