C語言指針,及指針識別能力

指針的基本意義

在創建變量時 *號和變量名結合,不和類型名結合
編譯器在編譯時,是從右到左識別的,哪怕在定義時

(int*)p,s;

這樣寫也是錯誤的,這樣的寫法編譯器會識別爲強轉功能,但是p和s並沒有初始化,自然也就無法進行強轉
強轉的寫法是:

int a=0x12345678;
int *ip=&a;
char *cp=(char*)&a;
char *p=(char*)&a;
*p='a';
p=p+1;
*p='b';
p=p+1;
*p='c';
p=p+1;
*p='d';
p=p+1;

要明白上面的程序首先我們要明白小段存放的原理
小段存放
通過這個程序我們可以知道不同類型轉換時,替換值的過程,建議通過編譯調試來看看
這裏p=p+1;因爲是char*類型,所以只移動了一個字節。而且高位數存放在高地址,低位數存放在低地址,所以從低位數開始改變
ps:p=p+1 相當於p=p+sizeof(char)*1;
*p=‘a’;
在這裏插入圖片描述
*p=‘b’;
在這裏插入圖片描述
*p=‘c’;
在這裏插入圖片描述
*p=‘d’;
在這裏插入圖片描述

我們也不能做這樣的操作

int *p;
p=&10;

這樣也是不對的,在給p傳地址時,我們不能對常量取地址

int p=&a(將a的地址傳給p,而不是p)
指針類型的大小是4字節

例如

int a=10;
int b=20;
int *p=NULL
p=&a;	這裏我們要注意,這是*p是a,而不是10,a纔是*p的指向,只不過a被賦值爲10罷了
*p=100;
p=&b;
*p=200;

爲了解釋指針的值的問題,在這我假設a的地址時0x0012ff28,他存放的是10,b的地址是0x0012ff1e,存放的是20。p的地址是0x0012ff10,存放的是a或b的地址0x0012ff28/0x0012ff1e,這要看程序員將誰的地址給了p。
那麼有下面的幾個等式
&p=0x0012ff10;
p=0x0012ff28/0x0012ff1e;
*p=a/b
*p=100(相當於給a賦值爲100)

另外引入另一個知識,關於數在內存中存放的問題。以及指針識別能力問題

double x=12.32;
int a=10;
char y='a';

由於x86系統採取的是小端存放,所以一般以其地位地址所謂某類型變量的首地址。
我畫圖來解釋。在這裏插入圖片描述
以此類推,可知++p或者p++或者p+1這些加的都是對應類型的字節數。
那麼自然有可能發生
char *p
int *p
double *p
的指針同時都指向了0x0012ff00,雖然都指向了地位的第一個地址,但是代表的意義不同
雖然指針類型的大小是4字節
但是每個類型的指針的識別能力是有限的,比如char型的指針,每次只識別內存中的一個字節來確定char的值,int類型的指針會識別4字節內存來確定int的值。而double會識別8個字節的地址。要注意,不同類型的指針不能相互賦值

還要注意我們在使用指針是切記不能定義野指針
我們需要注意的是,我們需要區分野指針和失效指針,我舉個例子來講解
如int *p;
這是上面的指針p就是野指針,我們爲指針p開闢了一個4字節的內存空間,但是我們沒有給這個指針添加指向。那麼我們無法知道指針p的指向。
而 失效指針
比如

void *fun()
{
  int a=100;
  return &a;
}

當這個函數使用完畢後,返回的指針變爲了失效指針,它依舊指向原來的空間,但是那塊空間依舊失效沒有了原來的主人。那麼即使得到了原來的結果,在實際上也是沒有意義的

int *p;//沒有對象的指針

解決野指針的方法有

int *p=NULL;//令其爲空
int *p=&a//給他一個對象

同時我們還要知道指針的下標操作
比如char *p = “abcdef”;
此時p[2]值 爲’c’。而p表示字符串"abcdef"的首地址,*p的值則相當於p[0],值爲’a’。
如果我們在函數中要調用指針,在使用前我們必須要進行判空操作

if(p==NULL);

首先要知道指針都是四字節的
下面舉一個例子
可以讓我們知道指各種類型指針的加一的範圍

char a3, a2, a1, a0;
	char *p3, *p2, *p1, *p0;
	char **s;
	//假設 a3, a2, a1, a0和*p3, *p2, *p1, *p0存放的內存空間都是連續的,並且s指向p
	//求s+1  =4字節
	//*s+1   =4字節
	//**s+1  =其本身的數加一
	s+1=s+sizeof(type*)*1;//二級指針+1,指的是指針,+1加指針類型的4個字節
	*s+1=s+sizeof(type)*1;//一級指針+1,指的是不同的類型變量,+1加的是指向類型的字節數
	**s+1=數值加一//就是數值加一

接下來要說明指針變量在和0,NULL比較是的方式
指針變量作爲if的判斷條件時,同樣有三種方式
A:if(p==0) if(p!=0)
B),if(p ) if(!p);
C) ,if(NULL == p); if(NULL != p);
哪一組或是那些組正確呢?我們來分析分析:
A)寫法:p 是整型變量?容易引起誤會,不好。儘管 NULL 的值和 0 一樣,但意義不同。
B)寫法:p 是 bool 型變量?容易引起誤會,不好。
C)寫法:這個寫法纔是正確的,但樣子比較古怪。爲什麼要這麼寫呢?是怕漏寫一個 “=”號:if(p = NULL),這個表達式編譯器當然會認爲是正確的

最後介紹一下普通的利用指針識別能力的特質完成數據打包和解析

int main()
{
    int a = 3;
    int c = 'x';
    float f = 3.14f;

    char buffer[20];

    // 在下面實現打包代碼
    *((int*)buffer) = a;
    *(buffer + sizeof(int)) = c;
    *((float*)(buffer + sizeof(int) + sizeof(char))) = f;

    // 在下面實現解包代碼
    printf("a = %d\n", *((int*)buffer));
    printf("c = %c\n", *(buffer + sizeof(int)));
    printf("f = %f\n", *((float*)(buffer + sizeof(int) + sizeof(char))));

    return 0;
}

所以同理也可以這麼做

	int arr[3] = { 1, 2, 3 };
	int x = 10;
	*((int*)arr) = x;

它的另一種寫法爲:

    // 在下面實現打包代碼
    int *pi = (int*)buffer;
    *pi = a;

    char *pc = (char*)(pi+1);
    *pc = c;

    float *pf = (float*)(pc+1);
    *pf = f;

    // 在下面實現解包代碼
    printf("a = %d\n", *pi);
    printf("c = %c\n", *pc);
    printf("f = %f\n", *pf);

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