[C語言] 指針

1. 指針是什么
2. 指針和指針類型
3. 野指針
4. 指針運算
5. 指針和數組
6. 二級指針
7. 指針數組

目錄

1. 指針是什么?

2. 指針和指針類型

2.1 指針+-整數

2.2 指針的解引用

3. 野指針

3.1 野指針成因

3.2 如何規避野指針

4. 指針運算

4.1 指針+-整數

4.2 指針-指針

5. 指針和數組

6. 二級指針

7. 指針數組


1. 指針是什么?

指針是什么?
指針理解的 2 個要點:
1. 指針是內存中一個最小單元的編號,也就是地址
2. 平時口語中說的指針,通常指的是指針變量,是用來存放內存地址的變量
總結:指針就是地址,口語中說的指針通常指的是指針變量。
那我們就可以這樣理解:
內存

?

指針變量
我們可以通過 & (取地址操作符)取出變量的內存其實地址,把地址可以存放到一個變量中,這個
變量就是指針變量
#include <stdio.h>
int main()
{
int a = 10;//在內存中開辟一塊空間
int *p = &a;//這里我們對變量a,取出它的地址,可以使用&操作符。//a變量占用4個字節的空間,這里是將a的4個字節的第一個字節的地址存放在p變量
中,p就是一個之指針變量。
return 0;
}
總結:
指針變量,用來存放地址的變量。(存放在指針中的值都被當成地址處理)。
那這里的問題是:
一個小的單元到底是多大?(1個字節)
如何編址?
經過仔細的計算和權衡我們發現一個字節給一個對應的地址是比較合適的。
對于 32 位的機器,假設有 32 根地址線,那么假設每根地址線在尋址的時候產生高電平(高電壓)和低電平(低電壓)就是(1或者 0 );
那么 32 根地址線產生的地址就會是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
11111111? 11111111? ?11111111? ?11111111
這里就有 2 32 次方個地址。
每個地址標識一個字節,那我們就可以給 2^32Byte == 2^32/1024KB ==
2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB 4G 的空閑進行編址。
同樣的方法,那 64 位機器,如果給 64 根地址線,那能編址多大空間,自己計算。
這里我們就明白:
32 位的機器上,地址是 32 0 或者 1 組成二進制序列,那地址就得用 4 個字節的空間來存儲,所以
一個指針變量的大小就應該是 4 個字節。
那如果在 64 位機器上,如果有 64 個地址線,那一個指針變量的大小是 8 個字節,才能存放一個地
址。
總結:
指針是用來存放地址的,地址是唯一標示一塊地址空間的。
指針的大小在 32 位平臺是 4 個字節,在 64 位平臺是 8 個字節

2. 指針和指針類型

這里我們在討論一下:指針的類型
我們都知道,變量有不同的類型,整形,浮點型等。那指針有沒有類型呢?
準確的說:有的。
當有這樣的代碼:
int num = 10;
p = &num;

要將&numnum的地址)保存到p中,我們知道p就是一個指針變量,那它的類型是怎樣的呢? 我們給指針變量相應的類型。

char? ? ? ?? * pc = NULL ;
int? ? ? ? ? ?? * pi = NULL ;
short? ? ? ?* ps = NULL ;
long? ? ? ? ? * pl = NULL ;
float? ? ? ? ?* pf = NULL ;
double? ? * pd = NULL ;
這里可以看到,指針的定義方式是: type + *
其實:
char* 類型的指針是為了存放 char 類型變量的地址。
short* 類型的指針是為了存放 short 類型變量的地址。
int* 類型的指針是為了存放 int 類型變量的地址。
那指針類型的意義是什么?

2.1 指針+-整數

#include <stdio.h>
//演示實例
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return ?0;
}
總結: 指針的類型決定了指針向前或者向后走一步有多大(距離)。

2.2 指針的解引用

//演示實例
#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0; ? //重點在調試的過程中觀察內存的變化。
*pi = 0; ? //重點在調試的過程中觀察內存的變化。
return 0;
}

總結:

指針的類型決定了,對指針解引用的時候有多大的權限(能操作幾個字節)。
比如: char* 的指針解引用就只能訪問一個字節,而 int* 的指針的解引用就能訪問四個字節。

3. 野指針

概念: 野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)

3.1 野指針成因

1. 指針未初始化
#include <stdio.h>
int main ()
{
? ? ?int * p ; // 局部變量指針未初始化,默認為隨機值
* p = 20 ;
? ? ?return 0 ;
}
2. 指針越界訪問
#include <stdio.h>
int main ()
{
int arr [ 10 ] = { 0 };
int * p = arr ;
int i = 0 ;
for ( i = 0 ; i <= 11 ; i ++ )
? {
// 當指針指向的范圍超出數組 arr 的范圍時, p 就是野指針
* ( p ++ ) = i ;
? }
return 0 ;
}
3. 指針指向的空間釋放
這里放在動態內存開辟的時候講解,這里可以簡單提示一下。

3.2 如何規避野指針

1. 指針初始化
2. 小心指針越界
3. 指針指向空間釋放即使置 NULL
4. 避免返回局部變量的地址
5. 指針使用之前檢查有效性
#include <stdio.h>
int main ()
{
int * p = NULL ;
//....
int a = 10 ;
p = & a ;
if ( p != NULL )
? {
* p = 20 ;
? }
return 0 ;
}

4. 指針運算

指針 +- 整數
指針 - 指針
指針的關系運算

4.1 指針+-整數

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指針+-整數;指針的關系運算
for (vp = &values[0]; vp < &values[N_VALUES];)
{*vp++ = 0;
}

4.2 指針-指針

int my_strlen(char *s)
{char *p = s;while(*p != '\0' )p++;return p-s;
}
4.3 指針的關系運算
for ( vp = & values [ N_VALUES ]; vp > & values [ 0 ];)
{
*-- vp = 0 ;
}
代碼簡化 , 這將代碼修改如下:
for ( vp = & values [ N_VALUES - 1 ]; vp >= & values [ 0 ]; vp -- )
{
* vp = 0 ;
}
實際在絕大部分的編譯器上是可以順利完成任務的,然而我們還是應該避免這樣寫,因為標準并不保證它可行。
標準規定:
允許指向數組元素的指針與指向數組最后一個元素后面的那個內存位置的指針比較,但是不允許與
指向第一個元素之前的那個內存位置的指針進行比較。

5. 指針和數組

我們看一個例子:
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};printf("%p\n", arr);printf("%p\n", &arr[0]);return 0;
}

運行結果:

可見數組名和數組首元素的地址是一樣的。

結論: 數組名表示的是數組首元素的地址 。(2種情況除外,數組章節講解了)
那么這樣寫代碼是可行的:
int arr [ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 };
int * p = arr ; //p 存放的是數組首元素的地址
既然可以把數組名當成地址存放到一個指針中,我們使用指針來訪問一個就成為可能。
例如:
#include <stdio.h>
int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,0};int *p = arr; //指針存放數組首元素的地址int sz = sizeof(arr)/sizeof(arr[0]);for(i=0; i<sz; i++){printf("&arr[%d] = %p ? <====> p+%d = %p\n", i, &arr[i], i, p+i);}return 0;
}

運行結果:

?所以 p+i 其實計算的是數組 arr 下標為i的地址。

那我們就可以直接通過指針來訪問數組。
如下:
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指針存放數組首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}

6. 二級指針

指針變量也是變量,是變量就有地址,那指針變量的地址存放在哪里?
這就是 二級指針

?

對于二級指針的運算有:
*ppa 通過對 ppa 中的地址進行解引用,這樣找到的是 pa *ppa 其實訪問的就是 pa .
int b = 20 ;
* ppa = & b ; // 等價于 pa = &b;
**ppa 先通過 *ppa 找到 pa , 然后對 pa 進行解引用操作: *pa ,那找到的是 a .
** ppa = 30 ;
// 等價于 *pa = 30;
// 等價于 a = 30;

7. 指針數組

指針數組是指針還是數組?
答案:是數組。是存放指針的數組。
數組我們已經知道整形數組,字符數組。
int? ? ?? arr1 [ 5 ];
char? ? arr2 [ 6 ];

?那指針數組是怎樣的?

int* arr3 [ 5 ];? ? ? // 是什么?
arr3 是一個數組,有五個元素,每個元素是一個整形指針。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36370.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36370.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36370.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

不用技術代碼,分班查詢系統怎么做?

暑假即將結束&#xff0c;新學期開始將面臨分班信息公布的工作&#xff01;對于分班信息公布&#xff0c;涉及到學生的個人信息&#xff0c;包括姓名、學號、班級等。在發布這些信息時&#xff0c;必須確保數據的保密性&#xff0c;防止未經授權的人員獲取到學生的個人信息。因…

對字符串中所有單詞進行倒排-C語言/Java

描述 輸入一個字符串&#xff0c;輸出字符串中單詞的倒序。 要求 構成單詞的字符只有26個大寫或小寫英文字母。非構成單詞的字符均視為單詞間隔符&#xff1b;倒排后的單詞間隔符以一個空格表示&#xff1b;如果原字符串中相鄰單詞間有多個間隔符時&#xff0c;倒排轉換后也只…

docker的服務/容器缺少vim問題

背景/問題&#xff1a; docker的服務/容器缺少vim問題 bash: vim: command not found 在docker的mysql服務中安裝Vim 1、執行apt-get update root6d8d17e320a0:/# apt-get update問題:文件下載失敗 Err:1 http://security.debian.org/debian-security buster/updates InRe…

【Linux】程序地址空間

程序地址空間 首先引入地址空間的作用什么是地址空間為什么要有地址空間 首先引入地址空間的作用 1 #include <stdio.h>2 #include <unistd.h>3 #include <stdlib.h>4 int g_val 100;6 int main()7 {8 pid_t id fork();9 if(id 0)10 {11 int cn…

自動方向識別式 LSF型電平轉換芯片

大家好&#xff0c;這里是大話硬件。 今天這篇文章想分享一下電平轉換芯片相關的內容。 其實在之前的文章分享過一篇關于電平轉換芯片的相關內容&#xff0c;具體可以看鏈接《高速電路邏輯電平轉換設計》。當時這篇文章也是分析的電平轉換芯片&#xff0c;不過那時候更多的是…

矩陣的轉置

題目&#xff1a; 給你一個二維整數數組 matrix&#xff0c; 返回 matrix 的 轉置矩陣 。 示例 1&#xff1a; 輸入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 輸出&#xff1a;[[1,4,7],[2,5,8],[3,6,9]]class Solution(object):def transpose(self, matrix):"&q…

JMeter 的并發設置教程

JMeter 是一個功能強大的性能測試工具&#xff0c;可以模擬許多用戶同時訪問應用程序的情況。在使用 JMeter 進行性能測試時&#xff0c;設置并發是非常重要的。本文將介紹如何在 JMeter 中設置并發和查看報告。 設置并發 并發是在線程組下的線程屬性中設置的。 線程數&#…

3.解構賦值

解構賦值是一種快速為變量賦值的簡潔語法&#xff0c;本質上仍然是為變量賦值。 3.1數組解構 數組解構是 將數組的單元值快速批量賦值給一系列變量 的簡潔語法 1.基本語法: &#xff08;1&#xff09;賦值運算符左側的[ ]用于批量聲明變量&#xff0c;右側數組的單元值將被賦…

前后端分離------后端創建筆記(04)前后端對接

本文章轉載于【SpringBootVue】全網最簡單但實用的前后端分離項目實戰筆記 - 前端_大菜007的博客-CSDN博客 僅用于學習和討論&#xff0c;如有侵權請聯系 源碼&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

【JavaEE進階】Bean 作用域和生命周期

文章目錄 一. 關于Bean作用域的實例1. lombok2. 實例代碼 二. 作用域定義1. Bean的六種作用域2. 設置作用域 三. Spring 執行流程和 Bean 的生命周期1. Spring 執行流程2. Bean生命周期 一. 關于Bean作用域的實例 注意在此例子中需要用到lombok 1. lombok lombok是什么? Lo…

【C#】判斷打印機共享狀態

打印機共享狀態 /// <summary>/// 打印機共享狀態/// </summary>public enum PrinterShareState{/// <summary>/// 無打印機/// </summary>None -1,/// <summary>/// 未共享/// </summary>NotShare 0,/// <summary>/// 已共享/// …

soap通信2

首先&#xff0c;定義一個XSD&#xff08;XML Schema Definition&#xff09;來描述你的數據結構。在你的Maven項目的src/main/resources目錄下&#xff0c;創建一個名為schemas的文件夾&#xff0c;并在其中創建一個名為scriptService.xsd的文件&#xff0c;內容如下&#xff…

【kubernetes】調度約束

目錄 調度約束 Pod 啟動典型創建過程如下 調度過程 指定調度節點 查看詳細事件&#xff08;發現未經過 scheduler 調度分配&#xff09; 獲取標簽幫助 需要獲取 node 上的 NAME 名稱 給對應的 node 設置標簽分別為 ggls 和 gglm 查看標簽 修改成 nodeSelector 調度方…

vue學習筆記

1.官網 v2官網 https://v2.cn.vuejs.org/ v3官網 https://cn.vuejs.org/ 2.vue引入 在線引入 <script src"https://cdn.jsdelivr.net/npm/vue2.7.14/dist/vue.js"></script> 下載引入(下載鏈接) https://v2.cn.vuejs.org/js/vue.js 3.初始化渲…

Redis——通用命令介紹

Redis官方文檔 redis官方文檔 核心命令 set 將key和value存儲到Redis中&#xff0c;key和value都是字符串 set key valueRedis中不區分大小寫&#xff0c;字符串類型也不需要添加單引號或者雙引號 get 根據key讀取value&#xff0c;如果當前key不存在&#xff0c;則返回…

Offset Explorer

Offset Explorer 簡介下載安裝 簡介 Offset Explorer&#xff08;以前稱為Kafka Tool&#xff09;是一個用于管理和使Apache Kafka 集群的GUI應用程序。它提供了一個直觀的UI&#xff0c;允許人們快速查看Kafka集群中的對象以及存儲在集群主題中的消息。它包含面向開發人員和管…

RANSAC算法

RANSAC簡介 RANSAC(RAndom SAmple Consensus,隨機采樣一致)算法是從一組含有“外點”(outliers)的數據中正確估計數學模型參數的迭代算法。 “外點”一般指的的數據中的噪聲&#xff0c;比如說匹配中的誤匹配和估計曲線中的離群點。所以&#xff0c;RANSAC也是一種“外點”檢…

若依-plus-vue啟動顯示Redis連接錯誤

用的Redis是windows版本&#xff0c;6.2.6 報錯的主要信息如下&#xff1a; Failed to instantiate [org.redisson.api.RedissonClient]: Factory method redisson threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect t…

基于epoll的TCP服務器端(C++)

網絡編程——C實現socket通信(TCP)高并發之epoll模式_tcp通信c 多客戶端epoll_n大橘為重n的博客-CSDN博客 網絡編程——C實現socket通信(TCP)高并發之select模式_n大橘為重n的博客-CSDN博客 server.cpp #include <stdio.h> #include <sys/types.h> #include <…

Coin Change

一、題目 Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make changes with these coins for a given amount of money. For example, if we have 11 cents, then we can make changes with one 10-cent coin and one 1-c…