函數名就是地址
內存地址是連續的,相鄰內存單元間的地址差1,可以把內存看成一個平坦的一維空間
內存與CPU讀寫速度快,容量比較小 ROM
程序:
代碼區 數據區 堆棧
指針與指針變量
指針:一個變量的地址,
指針變量:專門存放變量地址的變量,指針變量的值是地址
指針類型 : char* short* int* float* double*
指針除了首地址以外還有類型,類型決定了指向的數據大小,決定了數據的解析方式,指針的類型必須要和指針的指向類型一致
否則一定會出現偏差,地址相同
&取地址
*根據地址取出內容 ——> num 等價於 *(&num)
int *p = # p是指針變量存放num的地址,*p 是對num的解引用,p可以是任何變量的地址
//(int *)是一個指向int類型的指針變量 容納int變量的地址,p僅僅是一個開始地址,int決定截取多長,裏面的數據按照int來解析
// *p 與int 對稱 ,*p 就是int類型數據
指針在函數內部可以改變外部變量
一個exe不可以隨意讀取另一個exe的內存,
聲明指針變量時必須初始化指針變量
無論什麼類型的指針變量(32位),大小是固定的,就是4個字節,指針變量是用來存儲地址的,什麼類型就是按照什麼類型來解析
指針的類型決定從地址開始有太長,這段數據如何解析
地址和指針的差別, 地址單單是一個內存區域,指針知道地址從哪裏開始哪裏結束,不同類型解析長度不同,解析方式並不同
空指針 NULL
int *p = NULL; //指針爲空,null是0,不指向任何變量
直接訪問:按變量地址存取變量值
間接訪問:通過存放變量地址的變量去訪問變量 (通過指針變量)
%p 按照地址打印,可顯示地址的位數
scanf初始化一個指針,可以指明一個指針指向的內存
C語言要改變外部數據只有傳地址,Java C++有引用,但是C語言沒有
!!!數據當做參數的時候,傳遞的是指針,改變的是原來的數組,數組數據拷貝非常浪費內存,除了數組以外,都是副本機制,傳數組名相當於傳指針
//數組作爲參數時
#include <stdio.h>
#include <stdlib.h>
//void showa(int a[10]); 形參a相當於一個指針
void showa(int *p) //一維數組可用如此使用指針
{
for (int i = 0; i < 10; i++)
printf("%d\n",p[i]);
}
void showb(int (*p)[4]) //二維數組,這樣使用指針
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%02d ",**(p + i)+j); //兩個**
}
printf("\n");
}
}
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
showa(a);
showb(b);
system("pause");
}
指向指針的指針(二級指針)
函數的形式參數,除了數組以外,傳遞任何數據,變量,都會新建一個變量接受傳入變量的值,不影響原來的變量
要想改變外部參數,如果是一個數據,傳遞數據的地址,
如果是一個指針,傳遞指針的地址,函數內部改變外部指針變量,這就是二級指針的用處
double *p = # //指向num的指針變量p
double **pp = &p; //聲明二級指針 *pp ,指向 雙精度指針變量p的地址
double* 指明是4個字節,*pp 是 double*類型的數據
可以通過用“**”聲明一個二級指針,間接改變指針的指向
指針類型儘量一致,類型不一致,會少讀取或者多讀取
#include <stdio.h>
#include <stdlib.h>
/*
指向指針的指針(二級指針)
函數的形式參數,除了數組以外,傳遞任何數據,變量,都會新建一個變量接受傳入變量的值,不影響原來的變量
要想改變外部參數,如果是一個數據,傳遞數據的地址,
如果是一個指針,傳遞指針的地址,函數內部改變外部指針變量,這就是二級指針的用處
double *p = # //指向num的指針變量p
double **pp = &p; //聲明二級指針 *pp ,指向 雙精度指針變量p的地址
可以通過用“**”聲明一個二級指針,間接改變指針的指向
*/
int a = 10, b = 11, c = 12;
void change(int *p) //不能改變p的指向
{
p = &b;
}
void changep(int **p) //傳遞pa的地址才能改變pa的指向,二維指針
{
*p = &c;
}
int main()
{
int *pa = &a; //聲明指向a的指針
int **p = &pa; //聲明指向pa的二級指針
printf("%d\n",*pa);
changep(p);
printf("%d\n", *pa);
change(p);
printf("%d\n", *pa);
system("pause");
}
同類型的指針賦值同一個變量,用於數據通信,三個數據一個改變全部改變
整數和指針最好不要直接運算
*指針就是指針指向的數據類型
#include<stdio.h>
#include<stdlib.h>
//指針的賦值運算,一般就是傳遞地址,根據地址內容進行操作
//三個數值,有一個變化,全部變化
//地址的比較是沒有意義的
//*p++ 和 *(p++)等價,結合方向從自右向左
//數組中,指針之差,可以判斷誰的編號在前面,誰的編號在後面
//可以判斷兩個指針之間相隔多少個元素
int main()
{
int num = 13;
int *p = #
int *pa = p;
printf("%d %d %d\n\n",num,*p,*pa);
num = 23; //直接賦值
printf("%d %d %d\n\n", num, *p, *pa);
*p = 26; //間接賦值
printf("%d %d %d\n\n", num, *p, *pa);
*pa = 37; //間接賦值
printf("%d %d %d\n\n", num, *p, *pa);
system("pause");
}
指針和二維數組
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
///int (*p)[4] = a; 二維數組的指針就是一個指向一維數組的指針,元素是確定的
//a[i][j] = *(*(a+i)+j) &a[i][j]=*(a+i)+j
for (int x = 0; x < 3; x++)
{
for (int y = 0; y < 4; y++)
{
printf("%2d %p ",a[x][y],&a[x][y]);
}
printf("\n");
}
printf("%p %p %p\n",a,a+1,a+2);//a是行指針,指向的數據一行有4個int類型
printf("%p %p %p\n", *a, *a + 1, *a + 2);//*a是一個指向第一行第一個元素的指針
printf("%p %p %p\n", *(a+1), *(a+1) + 1, *(a+1) + 2);//*(a+1)是一個指向第二行第一個元素的指針
//a[i][j] = *(*(a+i)+j) &a[i][j]=*(a+i)+j
//a[i]代表行指針,等價 a+1
system("pause");
}
int main9()
{
int a[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
printf("%p,%p,%p\n",a,&a,*a); //地址相同
//a是一個行指針,指向一個有四個元素的數組, 16
//&a是一個指向二維數組的指針,二維數組有12個元素, 48
//*a是一個指向int類型數據的指針 4
printf("%d,%d,%d\n", sizeof(*a), sizeof(*&a), sizeof(**a));//16 48 4
system("pause");
}