久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 10029|回復: 54
收起左側

關于C語言的指針,與教材不一樣的解釋

  [復制鏈接]
ID:266429 發表于 2023-4-20 17:27 | 顯示全部樓層 |閱讀模式
C語言中為什么要設計指針這個東西,這個東西的設計原理是什么,本來就是個很簡單的東西,小學生思維就夠了。還有,這些原理之類的,對于使用C來編程的人來說,也是必須完全了解的,了解的深度與你編程時的輕松度密切相關,所以,弄清這個對你很重要。

總有人在問指針是干什么用的,那我先說說我的理解:獲取某個數據所在單元的地址值,由此推算出其它數據所在單元的地址值,以用于找到這個數據所在的存儲位置。
計算機編程,可以說,基本就是對存于存儲器中的數據進行操作,這就牽扯到一個最重要的問題:你現在要操作的數據,存在哪個地方?
想要弄清這個問題,最根本的方法,是了解芯片的設計和工作基本原理與基本結構組成。當然,如果知道存儲器的大概結構,也算是有了一個基礎。這里我不講這么多,因為學單片機的人,基本的知識應該還是有的,不是那種不與硬件打交道的程序員,所以不需我多講。

C與匯編有兩個根本的區別,造成了C中指針的產生:一個是數據所存儲的地址是由C編輯器自動分配的,程序員沒自主權,所以一個數據存儲的地址,程序員是不知道的;二是C編程中所用到的數據的長度與存儲單元容量的不一致導致一個數據可能會占據數個存儲單元,由此造成數據存儲地址值的不連續,這個現象造成的原因在于,不管你是8位機、16位機還是其它位機,一個存儲單元的位數都是8位,這個是芯片設計就如此,原因自然主要是兼容問題而不得不做出的選擇。本段所述的現象,在下面的比喻之中會進行解釋。

C語言編寫的程序,在程序運行中,你所要處理的數據存在哪,你是必須知道的,否則你找不到這個數據在哪,你的程序就沒法編下去了;如果你把數據所在的位置給弄錯了,那這個程序在運行中就得不到你想要的結果。

有關數據存在哪,及如何找到這個位置,我打如下一個比方:
我們知道,賓館的房間都是有編號的,而且是用數字來編寫的,很統一,一個房間一個編號;每個房間的大小都是一樣的,也就是說其容量是一樣的。賓館來了一家一家的,住哪間?賓館前臺來安排,一家人數少,可能就是一間,人數多了,可能就得幾間了,也就是說,同樣是一家,可能他只占據一個房間編號,也有可能占據數個房間編號(這就造成了地址編號的不連續),這個數據,只有前臺知道。如果你想去找到哪一家,你怎么找?你一個房間一個房間地去看單子也好看現場也好,都不是個辦法,一般情況下,每一家都是有個名字的,如張家、李家、王家、陳家等等的,你告訴前臺,前臺根據這個名字查一下,就會把這家的第一個房間的編號(首地址)給了你,而你在事先知道他們家人數及賓館每間房能住的人數的情況下,也就知道了他們家占幾間房。這個比方里,與C語言中的情況極其相似,就是存儲內容物的位置都是用統一數字編號來標識的,存儲內容的每一個單元(房間)的容量都是固定一致的,每一個(組)數據(一個家庭)都是有一個名字的,單個數據的長度(某個家庭人數)你事先是知道的,內容物的存儲位置分配是由他人分配而你事先是不知道的,其占據幾個存儲單元數量你是事先知道的。

同樣的原理,在C語言中,要找到一個數據的首地址,我們先要把這個數據的名字給編輯器(前臺),編輯器就會依據這個名字把這個數據存儲單元的首地址給你,這個動作,就是在這個數據的名字前面加一個“&”,其首地址值就出來了。
然后這里就又有了一個問題,這個查出的地址值,放在什么地方?賓館是可以將地址值寫在紙上,那計算機呢?它能放這個數據的地方,還是只有存儲器,當然,你也可以為存儲這些個地址而單獨在芯片中設計一個專門的區域,那你可以算是創新,但是,現有的芯片怎么辦?沒辦法,還是只能存于現有的存儲器之中,于是,C編輯器還得給一個房間(存儲單元)專門用于存儲這個地址值,然后,這個單元編號是多少?程序員又不知道了,因為又是編輯器自動分配的,所以,沒法,又得給這個取個名字以便查找利用,所以,在將要存入的內容存入之前,得先對要存入的內容進行定義(取名)一個變量,這樣我們以后就可以用名字直接找到這個內容了。

下面就談談C中有關獲取地址與使用地址的一些規則,有關這個概念的名詞,現有教材都稱之為指針,本人對這個名詞比較不感冒,這個名詞顯然沒能與“地址”一詞緊密聯系,于是不易理解不易記住(現有計算機教材中,類似槽點很多):
存放入單元的內容要要先取個名字,也就是所謂的定義(前面已經解釋過),這個因為指針變量的功能不同,所以定義變量名時,也要給出區別,讓編輯器知道這個變量的用途,也讓讀程序的人知道這個變量是用于存儲地址的,也就是所謂的指針變量。其進行區別的規則是變量名前面加一個*”以示區別,如果不加會怎么樣?你照樣可以將取得的地址值存入其中,但是,你用這個變量去取這個地址所指向數據時,程序在編譯時就報錯了,這個現象,只是編輯器的硬性規定,也是有道理的。其實編輯器在分配指針變量在存儲器中的位置時,也沒做什么特殊處理,它與其它變量都是統一分配地址的,基本也是順序分配,誰先使用誰先排前面(不是誰先定義誰先排前面),一點也不特殊。

在使用指針來取得存儲單元中的數據時,C的規定也是在指針變量名前加一個“*”以示這個是用地址值來取得數據,如a=*p,它的含意是:P所表示的存儲單元中的數據,是一個地址值,a=*p就是把這個地址值所指向的單元中的數據送給a。其實吧,個人覺得這個“*”符號用得不好,改為“@”可能更讓人容易理解,這個“@”有“在”的意思,然后我們就可以理解為“把在這個p值所指向的單元中的值,把它給a”。如果是這樣,很多運算公式就很容易理解了,如@p++就是操作“在”p值為地址所指向的單元中的數據,這個具體操作就是將其加1,而p++就是p值加1個數據長度值以將p值變為下一個數據的地址值(不是地址值本身直接增加1,這個在后面再解釋),也就是說,只要在p前面加了@,那要操作的對象就并不是p本身,而是它所指向的單元,這個一定要牢記不是操作p本身,這樣你在編程時就不容易出錯了。

指針變量是可以直接賦一個常量值的,但是,這個值必須是你所要用到的單元的地址值,如果不是,程序編譯時不會報錯,但程序運行時肯定是亂了,也就是說,前提是你知道這個數據的絕對地址值。

接下來的一個問題,就是指針變量的長度,既然是表示地址,那它就是一個沒有負號的整數,其長度最長也就是存儲器地址值的長度,如51機的RAM,其地址就只有八位,所以,在定義時,它的指針長度也就一個單元,多了浪費。
還有一個規則,指針變量的加減運算,是與其所指向的數據的長度綁定的,這個是在編譯處理時用到的,意思是其盡管這個指針變量也是一個數據,但它在做加減運算時,例如p=p+1,并不是p值直接加1,而是加一個其所指向的數據的長度址,以直接變為下一個數據的首地址值,這個處理,并不是在程序運行中進行的,而是在編譯時進行的,所以指針變量在使用之前一定要先定義,定義之后,編輯器才會知道這個是個指針變量,然后這樣做處理。
還有一個教材中沒說清楚的問題,這個所謂的指針,到底是只針對RAM,還是包括ROM?這個有興趣的朋友可以研究一下,方法也不難。
以上所說,其實都可以用編輯器調試中的匯編窗口來證實。
以上純屬個人理解,如有錯誤與不當,萬請指出。

評分

參與人數 2黑幣 +95 收起 理由
admin + 80 共享資料的黑幣獎勵!
xiaoshan7748 + 15 說的很通透

查看全部評分

回復

使用道具 舉報

ID:266429 發表于 2023-4-20 20:06 | 顯示全部樓層
C的指針問題,對于匯編來說,其實是個非常簡單的問題,就是用地址值來尋址的方式。當然,在現有的匯編教材中,也沒有具體的說什么用地址值來來尋址的這種說法,在匯編中,除了立即尋址方式,其它的方式,都是用到地址值的尋址方式。事實上,只要是用到RAM,就得知道其地址才能進行存取操作。
說起來,在C中,C的指針的操作,都只是取操作,前面已經說得很清楚了,其存操作,是由編輯器來進行的,程序員無權直接操作。也當然,如果程序員知道編輯器的分配規則,那么程序員想把某數在編輯器分配時分配在某單元中,也是可以做到的,這個就是對芯片和C通透了。
回復

使用道具 舉報

ID:266429 發表于 2023-4-20 20:48 | 顯示全部樓層
這個帖子內容,如果配上匯編窗口的實驗,應該也是一篇不錯的文檔吧?
回復

使用道具 舉報

ID:266429 發表于 2023-4-20 21:27 | 顯示全部樓層
知道了指針的原理,那我們完全可以在編程時很容易地確定任一數據的存儲地址,以及任一數據中某一字節的地址,哪怕各數據的字節長度并不一致。
回復

使用道具 舉報

ID:883242 發表于 2023-4-20 22:04 | 顯示全部樓層
C與匯編有兩個根本的區別,造成了C中指針的產生:一個是數據所存儲的地址是由C編輯器自動分配的,程序員沒自主權,所以一個數據存儲的地址,程序員是不知道的;

這話說明你的匯編沒學好。以Keil C51自帶的A51匯編器為例:

  1. Datum EQU 50h
復制代碼

這是大部分人常用的把變量Datum定義到50h地址上,嚴格地說是錯誤的。正確的寫法是這樣:
  1. Datum data 50h
復制代碼

但是這個寫法把Datum定義到50h地址上,如果是純匯編編程那么沒有問題,如果是匯編和c語言混合編程,這種寫法會和BL51.exe分配內存的方法發生沖突,不會出現編譯錯誤,也不會出現運行錯誤,但是可能會浪費RAM空間,不能實現資源的高效利用。那么最合理的寫法是這樣的:
  1. Datum ds 1
復制代碼
給Datum變量保留一個字節的空間,在編譯期間,編譯器也是不知道Datum地址是多少,只有最后連接完成,才能確定,可以查看連接器生成的map文件來知道Datum的地址到底是幾。


評分

參與人數 1黑幣 +5 收起 理由
IdeaMing + 5

查看全部評分

回復

使用道具 舉報

ID:401564 發表于 2023-4-20 22:10 | 顯示全部樓層
純技術問題不要搞這種花里胡哨的東西,對于學習意義不大
什么"老王教你用示波器","七天學會單片機"......之類的,往往是沒什么用的,說它不行,它好像有點用,說它行,好像用處不大
老外的書就簡單,往往枯燥,生澀難懂,但往往能真正的學到東西,很多時候能當工具書來查資料
這是對指針的描述,幾行代碼,加黑字,很快就能理解指針了
51hei截圖20230420220523.png

回復

使用道具 舉報

ID:8222 發表于 2023-4-20 22:29 | 顯示全部樓層
這個更通俗易懂。用@更容易理解,但現在都在用*,干脆就把*當@吧。
回復

使用道具 舉報

ID:146878 發表于 2023-4-20 22:36 | 顯示全部樓層
指針的根源是接尋址寄存器,沒有這個寄存器的MCU無法用指針。
回復

使用道具 舉報

ID:883242 發表于 2023-4-20 22:40 | 顯示全部樓層
pdwdzz 發表于 2023-4-20 22:36
指針的根源是接尋址寄存器,沒有這個寄存器的MCU無法用指針。

有indirect/index register也不好用,比如51強行上指針代碼密度和執行效率都是直線下降,得不償失。
回復

使用道具 舉報

ID:970057 發表于 2023-4-21 09:52 | 顯示全部樓層
其實就是間接尋址方式,給這么多教材解釋得繞來繞去
回復

使用道具 舉報

ID:266429 發表于 2023-4-21 11:59 | 顯示全部樓層
Y_G_G 發表于 2023-4-20 22:10
純技術問題不要搞這種花里胡哨的東西,對于學習意義不大
什么"老王教你用示波器","七天學會單片機"......之 ...

我寫的是有關單片機底層的工作原理和運行過程的東西,是比較接近其本質的東西。如果不懂這些,在C中那有些動作可能是不知道如何去做的,比如說,結合指針操作把一個四字節變量中的第三個字節的內容快速單獨地讀出來。
在單片機運行程序中,i=*p,這個語句執行時操作的數據并不是p本身,而是另一個數據:這個數據的首地址是p所指向的單元。
指針的本質是操作地址,所以,了解單片機芯片存儲結構及地址之類的概念,才能從底層上深入了解指針。
回復

使用道具 舉報

ID:883242 發表于 2023-4-21 12:41 | 顯示全部樓層
真要研究指針,怎么也要找個正經的c語言編譯器吧,如STM32用的三大編譯器IAR、GCC和MDK,找個天生殘疾的%的不正規c語言編譯器搞指針是%嗎?
回復

使用道具 舉報

ID:401564 發表于 2023-4-21 13:35 | 顯示全部樓層
慢慢思考 發表于 2023-4-21 11:59
我寫的是有關單片機底層的工作原理和運行過程的東西,是比較接近其本質的東西。如果不懂這些,在C中那有 ...

1: 匯編不需要C指針的功能,用法不一樣
2: 匯編的指針在不同單片機中,用法是不一樣的,你說的只能是8051的匯編,別的匯編用的不是這方法,像PIC的匯編壓根就沒有像8051這種指針尋址方式,它是由固定文件寄存器來進行操作的,你的說法很容易誤導別人
3:C語言很少有人去動內存,都是由編譯器自動分配,閑著沒事干才會去動內存
回復

使用道具 舉報

ID:1073144 發表于 2023-4-21 14:14 | 顯示全部樓層
指針的根源是接尋址寄存器
回復

使用道具 舉報

ID:73992 發表于 2023-4-21 18:49 來自觸屏版 | 顯示全部樓層
c51地址指針xdat區是兩個字節。變量的值存儲位置是編譯器決定的,但程序員要存儲的值是可以存到指定位置的。開機時候需要清理64k內存,如果沒有地址指針,程序員就需要寫64k行代碼。0000h=0,,,,ffffh=0  .有地址指針只需要地址加一。
回復

使用道具 舉報

ID:1073299 發表于 2023-4-22 15:04 來自觸屏版 | 顯示全部樓層
一句話,指針就是內存地址,然后通過地址取這個地址的數據,說一大堆沒用的云山霧繞的

評分

參與人數 1黑幣 +5 收起 理由
cxxx180 + 5 很給力!

查看全部評分

回復

使用道具 舉報

ID:266429 發表于 2023-4-24 09:42 | 顯示全部樓層
Hephaestus 發表于 2023-4-20 22:04
C與匯編有兩個根本的區別,造成了C中指針的產生:一個是數據所存儲的地址是由C編輯器自動分配的,程序員沒 ...

關于EQU是什么意思有什么用法,看下面一段程序:
  tryy EQU 0A0H
  abyte EQU 0A0H
  abit EQU 0A0H

ORG tryy
START:
   MOV tryy,#tryy
   MOV abyte,#tryy
   MOV C,tryy
   MOV C,abit
DB  1,2,3,4,tryy
ORG 0B0H  
   ddat: ds tryy
   ACALL tryy
END

偽指令EQU如果用于分配存儲單元,那它是用于RAM;偽指令data用于RAM;偽指令ds則是用于ROM。
我的主貼最后有一段話,指針究竟是只針對RAM,還是包括ROM?
回復

使用道具 舉報

ID:883242 發表于 2023-4-24 12:42 | 顯示全部樓層
慢慢思考 發表于 2023-4-24 09:42
關于EQU是什么意思有什么用法,看下面一段程序:
  tryy EQU 0A0H
  abyte EQU 0A0H

老老實實看c51的幫助文件吧,你的回復就沒有任何正確的地方。

EQU就是簡單的替換,相當于c語言的#define,如果純匯編那么可以用,因為內存分配完全是你的責任,發生沖突也跟編譯器無關。如果匯編和c混合編程那么絕對不可以使用EQU定義變量,因為這么做連接器BL51.exe不知道這些地址已經被占用,會發成沖突。

ds就是用于RAM,可讀可寫,用于ROM是很不合理的,讓編譯器分配一個字節內容未知也不能寫的ROM你想干什么?
回復

使用道具 舉報

ID:266429 發表于 2023-4-24 15:05 | 顯示全部樓層
Hephaestus 發表于 2023-4-24 12:42
老老實實看c51的幫助文件吧,你的回復就沒有任何正確的地方。

EQU就是簡單的替換,相當于c語言的#defi ...

北航2012年出版的《單片機系統設計基礎》中強調DS及DW只能用于程序存儲器,不能用于數據存儲器,這是目前我找到的唯一說明了DS應用存儲目標的書。
我的其它的錯誤,還是希望一條條地說明,有討論就會有進步。DS在編程中有什么實際用途,的確如你所說,本人也困惑。
回復

使用道具 舉報

ID:709761 發表于 2023-4-24 16:12 | 顯示全部樓層
編程這么久了,也沒感覺到指針有多么厲害
回復

使用道具 舉報

ID:883242 發表于 2023-4-24 18:28 | 顯示全部樓層
慢慢思考 發表于 2023-4-24 15:05
北航2012年出版的《單片機系統設計基礎》中強調DS及DW只能用于程序存儲器,不能用于數據存儲器,這是目前 ...

你直接看Keil自帶的幫助文件好了,中文的資料都是%為了晉升%灌水出來的,毫無價值的%。
回復

使用道具 舉報

ID:1074328 發表于 2023-4-26 23:16 | 顯示全部樓層
很少有人把這個講的這么好了
回復

使用道具 舉報

ID:888585 發表于 2023-4-27 08:34 | 顯示全部樓層
題主講的不錯,對于初學者來說是很有用的
回復

使用道具 舉報

ID:402993 發表于 2023-4-27 20:15 | 顯示全部樓層
講得很明細。
回復

使用道具 舉報

ID:291668 發表于 2023-4-28 13:26 | 顯示全部樓層
爭論的焦點就是指針的用途。我理解指針就像上學時的樓管阿姨,手里有一大串鑰匙,對應每個宿舍門,至于里邊住幾個人,從哪里來的。她不關心。只要找到能打開這扇門的鑰匙就行了。
回復

使用道具 舉報

ID:689425 發表于 2023-5-4 09:26 | 顯示全部樓層
li64331218 發表于 2023-4-28 13:26
爭論的焦點就是指針的用途。我理解指針就像上學時的樓管阿姨,手里有一大串鑰匙,對應每個宿舍門,至于里邊 ...

很形象
回復

使用道具 舉報

ID:721848 發表于 2023-5-10 11:53 | 顯示全部樓層
比較難懂,不好理解
回復

使用道具 舉報

ID:1079700 發表于 2023-5-24 21:59 | 顯示全部樓層
講的很好
回復

使用道具 舉報

ID:1083793 發表于 2023-6-13 14:12 | 顯示全部樓層
講的很清楚,新手可以看一看。
回復

使用道具 舉報

ID:333446 發表于 2023-7-12 11:57 | 顯示全部樓層
c語言引入指針是為了程序設計簡單,因為cpu里可以間接尋址,這樣在類似查表之類的操作時,直接把間接尋址寄存器加減相應的值就行了。可以快速取得數據地址。
回復

使用道具 舉報

ID:73833 發表于 2023-7-19 14:51 | 顯示全部樓層
指針就是鐘表上的指針,指向哪里就可表示出哪里的數字。比如,指針指向3點鐘那里(存放3這個數據的地址),人們就知道是3點(3,就是存放3 de地址里 de 數據)
回復

使用道具 舉報

ID:73833 發表于 2023-7-19 14:52 | 顯示全部樓層
wydev 發表于 2023-4-22 15:04
一句話,指針就是內存地址,然后通過地址取這個地址的數據,說一大堆沒用的云山霧繞的

言簡意賅
回復

使用道具 舉報

ID:475306 發表于 2023-7-28 08:47 | 顯示全部樓層
wydev 發表于 2023-4-22 15:04
一句話,指針就是內存地址,然后通過地址取這個地址的數據,說一大堆沒用的云山霧繞的

都快讓他們搞蒙了,剛入學
回復

使用道具 舉報

ID:123289 發表于 2023-8-25 15:49 | 顯示全部樓層
【北航2012年出版的《單片機系統設計基礎》中強調DS及DW只能用于程序存儲器,不能用于數據存儲器】
個人不同意這個說法。
回復

使用道具 舉報

ID:1096033 發表于 2023-10-18 10:20 | 顯示全部樓層
解釋的挺好
回復

使用道具 舉報

ID:1098507 發表于 2023-11-5 13:18 | 顯示全部樓層
好資料,51黑有你更精彩!!!
回復

使用道具 舉報

ID:1105351 發表于 2023-12-20 13:56 | 顯示全部樓層
看懂啦!感謝樓主
回復

使用道具 舉報

ID:1088185 發表于 2024-1-6 17:19 | 顯示全部樓層
也許從應用倒過來理解"為什么要用指針"更加容易讓你了解指針。

比如就不讓你用指針寫C代碼, 可以嗎?
不用指針的話有什么功能是做不到的?
有什么功能不給你用指針做就效率大大的降低?

能正確的回答以上問題,你才算懂指針是個啥玩意兒。
回復

使用道具 舉報

ID:311731 發表于 2024-2-4 18:47 | 顯示全部樓層
東莞朋友 發表于 2023-4-21 09:52
其實就是間接尋址方式,給這么多教材解釋得繞來繞去

就是匯編語言的間接尋址
回復

使用道具 舉報

ID:123036 發表于 2024-2-5 10:35 | 顯示全部樓層
wydev 發表于 2023-4-22 15:04
一句話,指針就是內存地址,然后通過地址取這個地址的數據,說一大堆沒用的云山霧繞的

同意。一大堆去說間接/尋址/寄存器。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 精品一区二区三区免费毛片 | 亚洲免费三区 | 精品入口麻豆88视频 | 午夜小电影| 欧美黄色小视频 | 91精品在线播放 | 欧美一级二级在线观看 | 五月花丁香婷婷 | 一级大黄色片 | 国产aⅴ精品 | www.色综合| 日韩人体在线 | 日韩在线国产精品 | 国产福利资源 | 91香蕉嫩草 | 免费在线毛片 | 瑟瑟激情| 99久久婷婷国产综合精品电影 | 欧美xxxx色视频在线观看免费 | 亚洲天堂精品久久 | 超碰人人人人 | 在线免费黄色小视频 | 久久免费国产 | 成人欧美日韩一区二区三区 | 精品熟人一区二区三区四区 | 日本网站免费在线观看 | 欧美9999| 成年人黄色免费视频 | 国产欧美精品一区二区 | 影音先锋亚洲资源 | 人人干人人玩 | 国产精品a级 | 日韩视频区 | 久久精品国产一区 | 91视视频在线观看入口直接观看 | 中文字幕一区二区视频 | 精品伊人 | 国产精品国产三级国产aⅴ原创 | 久久成人免费视频 | 成人a视频| 国产aa|