C語言學習——指針

C語言學習——指針

一、指針的概念

​ 變量在內存中是一塊一塊的,每一塊都有一個對應的編號,這個編號就是指針。

在C程序中使用指針可以

  • 使程序簡潔、緊湊、高效
  • 有效的表示複雜的數據結構
  • 動態分配內存
  • 得到多於一個的函數返回值

1.1、變量與地址

​ 在計算機內存中,每一個字節單元,都有一個編號,這個編號就是指針。

直接上傳(img-lCEHBAaG-1582356736681)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1582287932081.png)]

每一個編號都對應着一個字節,我們知道int型變量佔用4個字節。

來一個簡單的程序:1.1、bianliang.c

#include<stdio.h>
int main()
{
	int a=10; //變量的類型 定義變量
	int *aq; //指針的類型爲int 定義指針
	aq=&a; //將指針指向變量的地址
	printf("%d\n%d\n",*aq,a);
	printf("%p\n",aq);
	return 0;
} 

運行結果:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ZeSlGVAu-1582356736684)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1582340296481.png)]

1.2、指針變量和指針的類型

​ 指針變量就是一個變量,它存儲的內容是一個指針,例如程序中的 int *aq,aq就是指針變量,它的存儲內容是0x7ffe02d0c7ec,0x7ffe02d0c7ec實際上就是變量a的地址。

​ 我們在定義一個變量的時候要確定他的類型,例如這裏我們定義變量a,int a,在定義指針變量時,也要定義指針的類型,int 變量的指針需要用 int 類型的指針存儲,float 變量的指針需要用 float 類型的指針存儲。

例如,當用aq儲存a的地址的時候,必須保證aq和a的類型是一致的,都是int類型。

二、變量的指針與指針變量

變量的指針就是變量的存儲地址,指針變量就是存儲指針的變量

2.1、指針變量的使用

  • 取地址運算符&:單目運算符&是用來取操作對象的地址。例:&a爲取變量 a 的地址。對於常量表達式、寄存器變量不能取地址(因爲它們存儲在存儲器中,沒有地址)。

  • 指針運算符*(間接尋址符):與&爲逆運算,作用是通過操作對象的地址,獲取存儲的內容。例:x = &i,x 爲 i 的地址,*x 則爲通過 i 的地址,獲取 i 的內容。

    ​ 在上面程序中,

    printf("%d\n%d\n",*aq,a);

    aq已經是變量a的地址,aq就是通過a的地址訪問a的內容,所以 *aq就是10。

2.2、指針變量的初始化

​ 指針變量與其它變量一樣,在定義時可以賦值,即初始化。也可以賦值“NULL”或“0”,如果賦值“0”,此時的“0”含義並不是數字“0”,而是 NULL 的字符碼值。

2.3、指針的運算

(1)賦值運算

指針變量可以互相賦值,也可以賦值某個變量的地址,或者賦值一個具體的地址

#include<stdio.h>
int main()
{
	int *px,*py,a=100;
	px=&a;//賦值某個變量的地址
	py=px;//指針變量相互賦值
	px=100;//賦值一個具體的地址
	printf("%p\n%d\n",py,px);
}

(2)指針與整數的加減運算

  1. 指針變量的自增自減運算。指針加 1 或減 1 運算,表示指針向前或向後移動一個單元(不同類型的指針,單元長度不同)。這個在數組中非常常用。

  2. 指針變量加上或減去一個整形數。和第一條類似,具體加幾就是向前移動幾個單元,減幾就是向後移動幾個單元。

    程序:

    #include<stdio.h>
    int main()
    {
    	int a=10; //變量的類型 定義變量
    	int *aq; //指針的類型爲int 定義指針
    	aq=&a; //將指針指向變量的地址
    	printf("%d\n%d\n",*aq,a);
    	printf("%p\n",aq);
    	printf("%p\n%p\n",aq+1,aq+2);
    	return 0;
    } 

輸出結果:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fM3RyUYk-1582356736685)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1582347160396.png)]

​ 從運行結果可以看出,aq的值是0x7ffec8o74eec,aq+1是0x7ffec8074ef0,aq+2是0x7ffec8074ef4,我們通過計算可以看出aq+1在aq的基礎上相加了4個字節,aq+2在aq的基礎上相加了8個字節,因爲int型佔4個字節。加1就是一個int型佔4個字節,加2就是兩個兩個int型佔8個字節。

(3)關係運算

  1. px > py 表示 px 指向的存儲地址是否大於 py 指向的地址
  2. px == py 表示 px 和 py 是否指向同一個存儲單元
  3. px == 0 和 px != 0 表示 px 是否爲空指針

三、指針與數組

​ 數組可以通過下標來訪問,還可以通過指針來訪問,在數組中,數組名爲數組的首地址,通過指針對整數的加減來訪問數組中的元素。

3.1、 指向數組的指針

來一個簡單的程序:

#include<stdio.h>
int main()
{
	int sum[5]={1,2,3,4,5};
	int *px;
	px=sum;
	printf("%d\n%d\n",*(px+2),*(px+4)); 
}

​ 定義了一個名爲sum的數組,定義它分配5個連續的int內存空間,而一個數組的首地址即爲數組名sum,或者第一個元素的首地址也是數組的首地址。那麼有兩種方式讓指針變量 p 指向數組 sum:

所以輸出的*(px+2)=3, *(px+4)=5

img

1、*p = 1,此操作爲賦值操作,即將指針指向的存儲空間賦值爲 1。此時 p 指向數組 nums 的第一個元素,則此操作將 nums 第一個元素賦值爲 0,即 nums[0] = 1。
2、p + 1,此操作爲指針加整數操作,即向前移動一個單元。此時 p + 1 指向 nums[0]的下一個元素,即 nums[1]。通過p + 整數可以移動到想要操作的元素(此整數可以爲負數)。
3、如上面,p(p + 0)指向 nums[0]、p + 1 指向 nums[1]、、、類推可得,p+i 指向 nums[i],由此可以準確操作指定位置的元素。
4、在 p + 整數的操作要考慮邊界的問題,如一個數組長度爲 2,p+3 的意義對於數組操作來說沒有意義。

注:數組名不等價於指針變量,指針變量可以進行 p++和&操作,而這些操作對於數組名是非法的。數組名在編譯時是確定的,在程序運行期間算一個常量。

3.2、字符指針和指針數組

在 C 語言中本身沒有提供字符串數據類型,但是可以通過字符數組和字符指針的方式存儲字符串。

指針方式操作字符串和數組操作字符串類似。

程序:將數組fl中的內容複製到令一數組word中

#include<stdio.h>
int main()
{
	char fl[]="I LOVE YOU",word[100];
	char *ch = word;
	int i;
	for(i=0;fl[i]!='\0';i++)
	{
		*(ch+i)=fl[i];
	}
	*(ch+i)='\0';
	printf("ch=%s\n,word=%s\n",ch,word);
}

注:指針變量必須初始化一個有效值才能使用

四、動態內存分配

定義數組時數組大小在程序運行時才知道 , 靜態開闢就無法實現。

在C中動態開闢空間需要用到三個函數 :

malloc(), calloc(), realloc() ,這三個函數都是向堆中申請的內存空間.

malloc()函數用法:

void * malloc(size_t size)
p=(int*)malloc(sizeof(int) * n);

calloc()函數用法:

void * calloc(size_t num,size_t size)
p=(int*)calloc(n,sizeof(int));

4.1、malloc函數

1).malloc()函數會向堆中申請一片連續的可用內存空間

2).若申請成功 ,返回指向這片內存空間的指針 ,若失敗 ,則會返回NULL, 所以我們在用malloc()函數開闢動態內存之後, 一定要判斷函數返回值是否爲NULL.

3).返回值的類型爲void型, malloc()函數並不知道連續開闢的size個字節是存儲什麼類型數據的 ,所以需要我們自行決定 ,方法是在malloc()前加強制轉 ,轉化成我們所需類型 ,如: (int)malloc(sizeof(int)*n).

4).如果size爲0, 此行爲是未定義的, 會發生未知錯誤, 取決於編譯器

來一個程序:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	int n=0,i;
	int *p = NULL;//定義指針
	scanf("%d",&n);
	p=(int*)malloc(sizeof(int) * n);
	if(p != NULL) //判斷內存空間是否申請成功
	{
		for(i=0;i<n;i++)
		{
			scanf("%d",&p[i]);
		}
		for(i=0;i<n;i++)
		{
			printf("%3d",p[i]+1);
		}
		free(p); //釋放內存
		p = NULL;
	}
}

4.2、realloc函數

​ realloc()函數讓動態內存管理更加靈活 .在程序運行過程中動態分配內存大小, 如果分配的太大 ,則浪費空間, 如果太小, 可能還是會出現不夠用的情況 .爲了合理的利用內存,我們使用realloc() 函數對內存進行靈活的調整。

程序:將數據文件放入數組中

#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE *in,*out;
	char ch,infile[10];
	int size=0,i;//size-1代表數據的個數
	char a[100];
	double *data = (double*)malloc(sizeof(double));
	printf("輸入文件名稱");
	scanf("%s",infile); //輸入文件名稱
	if((in=fopen(infile,"r"))==NULL)//判斷是否打開文件
	{
		printf("打開文件失敗\n");
		exit(0);
	}
	while(fgets(a,100, in) != NULL)
	{
		double num = atof(a); //將字符串轉換成浮點數
		data[size] = num;//把數據存入數組
		size++;
		data = (double*)realloc(data, (sizeof(double))*(size+1));//每讀一個字節就重新分配一次內存
	}
	fclose(in);
	for(i=0; i<size-1; i++)
    	printf("%lf\n",data[i]);	//打印行號和該行的數據
    free(data);	//釋放內存
	//while(!feof(in))
	//{
		//ch=fgetc(in);
		//putchar(ch);
	//}
	//fclose(in);
	//return 0;
}

五、函數與指針

5.1、指針做函數參數

程序:交換兩個變量的內容

#include<stdio.h>
int swap(int *a,int *b)
{
	int t;
	t=*a;//指針a的內容給t
	*a=*b;//指針b的內容放到指針b中
	*b=t;//t中的數放到指針b中
}
int main()
{
	int a=50,b=20;
	swap(&a,&b);
	printf("%d %d",a,b);
}

5.2、函數返回數組

C 語言不允許返回一個完整的數組作爲函數的參數。但是,**可以通過指定不帶索引的數組名來返回一個指向數組的指針。**如果您想要從函數返回一個一維數組,必須聲明一個返回指針的函數

#include<stdio.h>
#include<time.h>
#include<stdlib.h> 
int *gt(int a[])
{
	int i;
	srand( (unsigned)time( NULL ) );//產生隨機數
	for(i=0;i<10;i++)
	{
		a[i]=rand();
	}
	return a;
}
int main()
{
	int *b,j;
	int c[10]={1,2,3,4,5,6,7,8,9,0};
	b=gt(c);
	for(j=0;j<10;j++)
	{
		printf("%d\n",b[j]);
	}
}

明一個返回指針的函數

#include<stdio.h>
#include<time.h>
#include<stdlib.h> 
int *gt(int a[])
{
	int i;
	srand( (unsigned)time( NULL ) );//產生隨機數
	for(i=0;i<10;i++)
	{
		a[i]=rand();
	}
	return a;
}
int main()
{
	int *b,j;
	int c[10]={1,2,3,4,5,6,7,8,9,0};
	b=gt(c);
	for(j=0;j<10;j++)
	{
		printf("%d\n",b[j]);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章