ANSI C


 

原碼、反碼和補碼的解釋

一、官方定義

原碼:原碼是一種計算機中對數字的二進制表示方法,數碼序列中最高位為符號位,符號位為0表示正數,符號位為1表示負數;其余有效值部分用二進制的絕對值表示。 

反碼:如果機器數是正數,則該機器數的反碼與原碼一樣;如果機器數是負數,則該機器數的反碼是對它的原碼(符號位除外)各位取反而得到的。 

補碼:如果機器數是正數,則該機器數的補碼與原碼一樣;如果機器數是負數,則該機器數的補碼是對它的原碼(除符號位外)各位取反,並在末位加1。

 

二、解釋說明

為了方便說明問題,假定用4位二進制數表示一個整數(一般32位電腦上主流C語言編譯器用32位表示一個整數,不過原理都是一致的)。 

2.1 有符號數的引入和原碼表示的局限性 

圖1說明了無符號數的原碼表示方法,其中內圈的數字為二進制數,外圈的數字是內圈二進制數所對應的十進制數。

 

 

 圖1 無符號數的原碼表示方法 

顧名思義,無符號數不能表示負數。為了解決這個問題,我們把最高位定義為符號位。圖2說明了有符號數的原碼表示方法,最高位為1表示負數,其中內圈的數字為二進制數,外圈的數字是內圈二進制數所對應的十進制數。

 

 圖2 有符號數的原碼表示方法 

用原碼來表示一個有符號數會帶來兩個問題。 

  • 第一個問題就是正負相加不等於零。如圖2所示,十進制運算 2+(-2) 對應的二進制運算為 0010+1010=1100 ,按照原碼表示等於 -4 。
  • 第二個問題就是有兩個零存在,分別為0000 和1000。 

可見,原碼不適合用來表示有符號數! 

2.2 反碼和補碼的引入 

為了解決用原碼表示有符號數時出現的第一個問題,我們引入了反碼的概念。圖3說明了有符號數的反碼表示方法。如果把二進制數想象成12點,把二進制數想象成6點,原碼就是從12點開始順時針排列到,而反碼就是從6點開始逆時針排列到。 

這樣做的好處就在於現在正負數相加等於零了。例如,十進制運算 2+(-2) 對應的二進制運算為 0010+1101=1111,按照反碼表示等於 -0。 

  圖3 有符號數的反碼表示方法

在用反碼表示有符號數的圖3中,依然有兩個零存在,分別為 0000 和 1111。為了解決用原碼和反碼表示有符號數時出現的第二個問題,我們引入了補碼的概念。圖4說明了有符號數的補碼表示方法。按照補碼的定義,-0 的反碼為 1111,不過現在必須在末位加1,那現在就是 0000 了,以此類推。與反碼表示不一樣的是,補碼在負數上從 -1 表示到 -8,-0 不再存在了。經過驗證,正負相加也等於零!

 圖4 有符號數的補碼表示方法 

而對於無符號數,原碼、反碼、補碼都是一致的。因此,我們可以說:整型數在計算機中,使用補碼表示。 

三、補充說明

溢出。對於無符號數,溢出發生的地方在6點鍾方向;而對於有符號數,溢出的邊界在12點方向,
無符號數。在實際的應用中,有很多種情況是不會出現負數的。比如說我們的年齡,一個班級的課程數,一個國家的人數等。如果用有符號數來保存這些值,那么永遠不會用到表示負數的那一半范圍,這樣就被白白浪費了,而且還使得正數的表示范圍被占用了一半。針對這個問題,C語言中引入了無符號數的概念。
char。當要在不同平台移植我們的程序時,字符是否有符號的這種歧義性會給我們帶來很大的麻煩。如果移植性的要求很高,那么你就需要確保你的字符變量中保存的值的范圍在0到127之間,這樣無論字符類型是否有符號,都可以正確地表示這個范圍之內的值。
浮點數。浮點數通常用一個分數和以某個基數的指數來組成,以 m×b的方式保存在電腦中,一般電腦中基數 和分數 都是用二進制表示的。
數制和碼制的區別。由於教材對碼制的解釋比較嚴謹全面,因而比較難懂。我這里不太嚴謹但是通俗易懂解釋一下:數制規定了每一位的權重和系數,碼制規定了有幾位以及這幾位不同排列代表的含義。

  

二維數組作為函數參數來傳遞的三種方法

參考鏈接:深入理解數組指針與指針數組的區別

 

方法一:形參給出第二維的長度

#include <stdio.h>
void func(int n, char str[][5])
{
  int i;   for(i = 0; i < n; i++)   printf("/nstr[%d]=%s/n",i,str[i]); } void main() {   char* p[3];   char str[][5]={"abc","def","ghi"};   func(3,str); }

方法二:形參聲明為指向數組的指針

#include <stdio.h>
void func(int n,char(*str)[5])
{
  int i;
  for(i=0;i<n;i++)
  printf("/nstr[%d]=%s/n",i,str[i]);
}
void main()
{
  char* p[3];
  char str[][5] = {"abc","def","ghi"};
  func(3,str);
}

數組指針的理解(重要!)

int *p; 可以理解為步長為1的指針,int (*p)[4]; 可以理解為步長為4的指針。本質和二維數組名一樣都是一維的。

方法三:形參聲明為指針的指針

#include <stdio.h>
void func(int n, char **str)
{
  int i;
  for(i=0;i<n;i++)
  printf("/nstr[%d]=%s/n",i,str[i]);
}
void main()
{
  char* p[3];
  char str[][5] = {"abc","def","ghi"};
  p[0] = &str[0][0];
  p[1] = str[1];
  p[2] = str[2];
  func(3,p);
}

方法三說明:在函數中使用傳參過來的二維數組(指針)進行數組取值的時候不能使用(array[i][j] )這種形式來取值,應該將二維數組看成一個一維數組,使用array[i * j + j]這種形式來進行取值。這是因為在傳參的時候,將array[][]數組當成二級指針來進行傳遞,所以數組的屬性退化成了二級指針的屬性,不能使用array[i][j]這種方式來進行數組取值。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM