指針知識點總結

来源:https://www.cnblogs.com/ningcode/archive/2023/01/11/17043062.html
-Advertisement-
Play Games

JavaWeb綜合案例 筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 視頻教程(P154~P163) 功能列表 環境搭建 執行提供的下麵的tb_brand.sql腳本 -- 刪除tb_brand表 drop table if ex ...


指針總結

基礎概念

系統給虛擬記憶體的每個存儲單元分配了一個編號,0x0000 0000-0xff ff ff ff,這個編號是地址,指針就是地址

記憶體數據的訪問方式:

(1)直接訪問—按變數名存取變數

(2)間接訪問——將變數的地址存放在另一個變數(指針變數),通過指針變數來訪問。

數據在記憶體中的地址也稱為指針,如果一個變數存儲了一份數據的指針,我們就稱它為指針變數

在C語言中,允許用一個變數來存放指針,這種變數稱為指針變數。指針變數的值就是某份數據的地址,這樣的一份數據可以是數組、字元串、函數,也可以是另外的一個普通變數或指針變數。

在32位平臺,地址匯流排是32位,地址是32位編號,所以指針變數是32位即4個位元組

 註意:

       (1)無論什麼類型的地址,都是存儲單元的編號,在32位平臺下都是4個位元組
                    即任何類型的指針變數都是4個位元組大小.在64位系統中任何類型的指針都是8個位元組大小。
                    
       (2)對應類型的指針變數,只能存放對應類型的變數的地址
                    舉例:整型的指針變數,只能存放整型變數的地址

 拓展:
    字元變數char ch=’b’;ch占一個位元組,它有一個地址編號,而這個編號就是ch的地址

    整型變數int a=0x12345678;a占4個位元組,它占4個位元組的存儲單元,有4個地址編號

指針的定義及賦值方法

指針變數同普通變數一樣,使用之前不僅要定義說明,而且必須賦予具體的值。未經賦值的指針變數不能使用, 否則將造成系統混亂,甚至死機。指針變數的賦值只能賦予地址, 決不能賦予任何其它數據,否則將引起錯誤。

    1.簡單的指針變數
    數據類型 * 指針變數名;
    int * p;//定義了一個指針變數p
    註意:在定義指針變數的時候 * 是用來修飾變數的,說明變數p是個指針變數。
    變數名是p

    2.關於指針的運算符
    &取地址、*取值(解引用)

int pa = &a; 也可以寫成 int pa = &a; 即 * 號可以緊跟在變數類型後,也可以緊跟在變數名字前,就是個指針類型標識符。這條語句等價於 int *pa; pa=&a;
其具體含義為:定義一個可以指向整型數據的指針變數pa,並用整型變數a的地址值對指針變數pa進行初始化,從而使指針變數pa具體地指向了整型變數a。

int a=0x12345678;
int b;
int *p;//在定義指針變數的時候*代表修飾的意思,修飾p是個指針變數
p=&a;//把a的地址給p賦值 &是取地址符
b=*p;//這裡的*是解引用,取指針p所指向的變數a的值

p保存了a的地址,也可以說p指向了a
p和a的關係分析:
a的值是0x12345678,假設a的地址是:0xbf e8 98 68

img

int num;
num=*p;

分析:(1)在調用的時候*代表取值的意思,*p就相當於p指向的變數a
     (2)即num=*p和num=a是等價的
     (3)所以num=0x12345678;
小拓展:如果在一行中定義多個指針變數,每個指針變數前面都需要加*來修飾
​    int *p,*q;//定義了兩個整型的指針變數p和q
​    int *p,q;//定義了一個整型指針變數p,和整型變數q

指針變數的運算(引用)

指針變數可以進行某些運算,但其運算的種類是有限的。 它只能進行賦值運算和部分算術運算及關係運算。

1指針運算符

指針運算符
(1)取地址運算符  &
​&是單目運算符,其結合性為自右至左,其功能是取變數的地址。例&a即變數a的地址

(2)取內容運算符  *
​*是單目運算符,其結合性為自右至左,用來表示指針變數所指的變數。在*運算符之後跟的變數必須是指針變數。
註意:指針運算符*和指針變數說明中的指針說明符* 不是一回事。
     在指針變數說明中,“*”是類型說明符,表示其後的變數是指針類型。int *p;
     而表達式中出現的“*”則是一個運算符用以表示指針變數所指的變數。*p=&a
若有定義:  int  a,  p=&a
(1)&*p 表示:p
(2)*&a 表示: a          
(3)(*p)++相當於a++    
(4)*p++相當於*(p++),即先取p所指向變數的值,然後,讓p指向下一個存儲單元。
(5)*++p相當於*(++p),即先讓p指向下一個存儲單元,然後再取p所指向變數的值。
//利用指針輸入變數的值
main()
{  int a,b;
    int *p;
    p=&a; 
   scanf("%d",p);
    p=&b; 
    scanf("%d",p);
   printf(”a=%d, b=%d\n",a,b);
}

2指針變數的賦值運算

指針變數的賦值運算有以下幾種形式: 
 1.指針變數初始化賦值,前面已作介紹。
 
 2.把一個變數的地址賦予指向相同數據類型的指針變數。
例如:    int a,*pa;
             pa=&a;    /*把整型變數a的地址賦予整型指針變數pa*/
 
 3.把一個指針變數的值賦予指向相同類型變數的另一個指針變數。
如:    int a,*pa=&a,*pb;
           pb=pa;  
    把a的地址賦予指針變數pb,
由於pa,pb均為指向整型變數的指針變數,
因此可以相互賦值 

 4.把數組的首地址賦予指向數組的指針變數。
例如:    int a[5],*pa;
    pa=a;    (C語言規定數組名錶示數組的首地址)
也可寫為: pa=&a[0]; 
      數組第一個元素的地址也是整個數組的首地址,也可賦予pa
當然也可採取初始化賦值的方法:
                           int a[5],*pa=a;

5.把字元串的首地址賦予指向字元類型的指針變數。
            例如:    char *pc;
              pc="C language";
    或用初始化賦值的方法寫為:    
             char *pc="C Language"; 
這裡應說明的是並不是把整個字元串裝入指針變數, 而是把存放該字元串的字元數組的首地址裝入指針變數。

註意:指針變數可以賦予0值,則p=0表明p是空指針,它不指向任何變數;

字元串的地址和指向字元串的指針變數

字元串在記憶體中的起始地址稱為字元串的地址,可以定義一個字元指針變數指向一個字元串。

1.逐個引用
main()
{ 
      char *string=”I love Beijing.”; 
      for(; *string!=’\0’; string++) 
      printf(“%c”, *string);
      printf(“\n”);
}
   字元指針變數string中,僅存儲串常量的地址,而串常量的內容(即字元串本身),是存儲在由系統自動開闢的記憶體塊中,併在串尾添加一個結束標誌’\0’。
  
2.整體引用
main()
    { char *string=”I love Beijing.”; 
       printf(“%s\n”,string);
     }
通過指向字元串的指針變數string,整體引用它所指向的字元串的原理:系統首先輸出string指向的第一個字元,然後使string自動加1,使之指向下一個字元;重覆上述過程,直至遇到字元串結束標誌。

3.字元指針變數與字元數組之比較
雖然用字元指針變數和字元數組都能實現字元串的存儲和處理,但二者是有區別的,不能混為一談。
(1)存儲內容不同。
字元指針變數中存儲的是字元串的首地址,而字元數組中存儲的是字元串本身(數組的每個元素存放一個字元)。
(2)賦值方式不同
對字元指針變數,可採用下麵的賦值語句賦值:
       char  *pointer;
        pointer="This is a example.";
而字元數組,雖然可以在定義時初始化,但不能用賦值語句整體賦值。下麵的用法是非法的:
       char   array[20];
       char   array="This is a example.";   /*非法用法*/
!!!補:字元數組的正確賦值方法
     1、定義的時候直接用字元串初始化
        char a[10]="hello";
     註意:不能先定義再給它賦值,如char a[10]; a[10]="hello";這樣是錯誤的!只有定義初始化是才能這樣賦值
     2、對數組中字元逐個賦值
     char a[10]={'h','e','l','l','o'};
     3、利用strcpy,這個比較值得推薦的方法
     char a[10]; strcpy(a, "hello");
(3)指針變數的值是可以改變的,字元指針變數也不例外;而數組名代表數組的起始地址,是一個常量,而常量是不能被改變的。

函數與指針

•用指針變數可以指向一個函數。簡稱函數指針。
•函數在編譯時被分配給一個入口地址。這個函數的入口地址就稱為函數的指針
定義格式:函數的返回值類型(函數指針名)(函數的形參列表)
例:int (
p)(int a,int b);

//函數的指針
 int  max(int x,int y)//max函數:判斷兩個值的最大值
{ int z;
     if(x>y)z=x;
  else      z=y;
    return(z);
  }
void main()
{  int  max(int,int);
      int (*p)();//int (*p)()為函數指針的定義
      int a,b,c;
     p=max;//將max函數賦給指針函數p
   scanf(″%d,%d″,&a,&b);
     c=(*p)(a,b);//此時*p起到了max函數相同的作用
   printf(″a=%d,b=%d,max=%
                 d″,a,b,c);
  }

指針函數:是一個函數,但是這個函數的返回值類型是另一個指針。

int *fun()
{
    int a=10;
    int *p=10;
    return p;
    //return &a;這樣寫是錯的,指針函數需要返回一 個指針,例如上面的*p才是正確的返回類型
}
int main()
{
    int *q=fun();
    printf("%d\n",*q);
}
//例:使用函數指針得出兩個數的最大值,最小值,相加值。
#include<stdio.h>
void main()
{//函數聲明
    int max(int,int);
    int min(int,int);
    int add(int,int);
    void process(int,int,int(*fun)(int,int));
    
    int a,b;
    printf("enter a and b:");
    scanf("%d,%d",&a,&b);
    printf("max=");  process(a,b,max);
    printf("min=");  process(a,b,min);
    printf("sum=");  process(a,b,add);
}
int max(int x,int y)
{
    int z;
    if(x>y) z=x;
    else    z=y;
    return(z);
}
int min(int x,int y)
{
    int z;
    if(x<y) z=x;
    else    z=y;
    return(z);
}
int add(int x,int y)
{
    int z;
    z=x+y;
    return(z);
}
void process(int x,int y,int(*fun)(int,int))
{
    int result;
    result=(*fun)(x,y);
    printf("%d\n",result);
}
//這裡的fun函數就是一個函數指針,可以在main函數中將max,min,add函數帶入使用。

數組與指針

一個數組,若其元素均為指針類型數據,稱為指針數組,也就是說,指針數組中的每一個元素都相當於一個指針變數。
一維指針數組的定義形式為:
類型名 數組名[數組長度];
例如:int *p[4];

//將若幹字元串按字母順序(由小到大)輸出。
#include <stdio.h>
#include <string.h>
void main()
{
     void sort(char *name[],int n);
     void print(char *name[],int n);
     //指針數組定義與賦值
     char *name[]={"Follow me","BASIC","Great Wall","FORTRAN","Computer design"};
     int n=5;
     sort(name,n);
     print(name,n);
}
void sort(char *name[],int n)
{//比較首字母順序
     char *temp;//字元串指針變數
     int i,j,k;
     for(i=0;i<n-1;i++)
     {
        k=i;
	   for(j=i+1;j<n;j++)
	      if(strcmp(name[k],name[j])>0)
          {
              k=j;
          }
	     if(k!=i)
          {
             temp=name[i];
             name[i]=name[k];
             name[k]=temp;
          }
	 }
}
void print(char *name[ ],int n)
{//字元串的輸出
    int i;
    for(i=0;i<n;i++)
    printf("%s\n",name[i]);
}

小結

有關指針的數據類型的小結

定義 含義
int i; 定義整型變數i
int *p; p為指向整型數據的指針變數
int a[n]; 定義整型數組a,它有n個元素
*int p[n]; 定義指針數組p,它由n個指向整型數據的指針元素組成
int (*p)[n]; p為指向含n個元素的一維數組的指針變數
int f(); f為帶回整型函數值的函數
*int p(); p為帶回一個指針的函數,該指針指向整型數據
int(*p)(); p為指向函數的指針,該函數返回一個整型值
int **p; p是一個指針變數,它指向一個指向整型數據的指針變數

指針運算小結

(1) 指針變數加(減)一個整數
例如:p++、P--、p+i、p-i、p+=i、p-=i等。

(2) 指針變數賦值
將一個變數地址賦給一個指針變數。如:
​p=&a(將變數a的地址賦給p)
​p=array;(將數組array首元素地址賦給p)
​p=&array[ i ];(將數組array第i個元素的地址賦給p)
​p=max;(max為已定義的函數,將max的入口地址賦給p)
​p1=p2;(p1和p2都是指針變數,將p2的值賦給p1)

(3) 指針變數可以有空值,即該指針變數不指向任何變數。

(4) 兩個指針變數可以相減
如果兩個指針變數都指向同一個數組中的元素,則兩個指針變數值之差是兩個指針之間的元素個數 。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Image模塊是PIL最基本的模塊,其中導出了Image類,一個Image類實例對象就對應了一副圖像。同時,Image模塊還提供了很多有用的函數。本文只是初步學習了一些用法與實際操作。 ...
  • 在 YARN 中,Application 是指應用程式,它可能啟動多個運行實例,每個運行實例由 —個 ApplicationMaster 與一組該 ApplicationMaster 啟動的任務組成,它擁有名稱、隊列、優先順序等屬性,是一個比較寬泛的概念,可以是一個 MepReduce 作業、一個 D... ...
  • 2023-01-10 一、MyBatis自動映射與自定義映射 1、自動映射: 在映射文件中使用的是“resultType”。指的是自動將資料庫中表的欄位與類中的屬性進行關聯映射。 2、自定義映射: (1)在映射文件中使用的是“resultMap”。一般是自動映射解決不了的問題,就使用自定義映射。 有 ...
  • 圖文並茂的內容往往讓人看起來更加舒服,如果只是文字內容的累加,往往會使讀者產生視覺疲勞。搭配精美的文章配圖則會使文章內容更加豐富,增加文章可讀性的同時,也能提升用戶體驗。但由於PDF文檔安全性較高,不易對其進行修改編輯,那我們要如何在PDF中插入、替換或刪除圖像呢?別擔心,今天為大家介紹一種高效便捷... ...
  • 一、前言 今天小編帶大家一起整合一下easyExcel,之所以用這個,是因為easyExcel性能比較好,不會報OOM! 市面上常見的導入導出Excel分為三種: hutool easyExcel poi hutool和easyExcel都是對poi的封裝,使用起來更加方便! 如果想使用poi和hu ...
  • 一、前言”前後端分離“已經成為互聯網項目開發的業界標桿,通過Tomcat+Ngnix(也可以中間有個Node.js),有效地進行解耦。並且前後端分離會為以後的大型分散式架構、彈性計算架構、微服務架構、多端化服務(多種客戶端,例如:瀏覽器,車載終端,安卓,IOS等等)打下堅實的基礎。前後端分離(解耦) ...
  • 1、在任意目錄之間快速移動 你發現自己要在兩個或更多目錄之間頻繁移動,一會切換到這裡,一會切換到那裡,來回跳轉。這些目錄之間隔得還挺遠,反覆輸入冗長的路徑讓人疲憊不堪。 使用內建命令 pushd 和 popd 來管理目錄棧,輕鬆地在目錄之間切換。下麵是一個簡單的示例: $ cd /tmp/tank ...
  • 奉行長期主義的開發者都有一個共識:對於伺服器來說,數據備份非常重要,因為伺服器上的數據通常是無價的,如果丟失了這些數據,可能會導致嚴重的後果,伴隨雲時代的發展,備份技術也讓千行百業看到了其“雲基因”的成長與進化,即基於雲存儲的雲備份。 本次我們使用Golang1.18完成百度網盤(百度雲盤)介面AP ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...