程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++容易被忽視的基礎知識

C++容易被忽視的基礎知識

編輯:關於C++

作為一個java開發者,由於實際需要最近開始接觸C++,這是最近接觸C++碰到的一些難點和易錯點,整理如下,給自己和其他C++的初學者····

通過本文,你可以學到:

1)浮點值的上溢和下溢

2)浮點數捨入誤差

3)使用%d顯示float值不會把float轉化為近似的int值,而是顯示垃圾值

4)scanf的讀取習慣

5)strlen()函數和sizeof()區別

6)負數轉化為unsigned和大於255的值轉化為字符相當於取模

7)prinf讀取stack裡的數字是按%讀取的

 

1.浮點值的上溢和下溢:

如:假設系統最大的float的值為3.4E38,並進行如下操作:

 

float toobig =3.4E38*100.0f;
print("%e\n",toobig);
這會發生上溢(overflow),pronf()函數顯示的值是inf或infinity(或者這個含義的其他名稱)
當除以一個很小的數時,如0.1233E-10除以10,結果將失去一位精度,變為0.0123E-10,這種現象稱為下溢(underflow).

 

另外如用asin()返回反正弦值,但輸入參數卻大於1時返回NaN(Not-a-Number)

 

2.浮點數捨入誤差

將一個數加上1再減去原數,結果為1.如果用浮點計算,可能會有其他結果,如:

 

#include 
int main(void)
{
	float a, b;
	b = 2.0e20 + 1.0;
	a = b - 2.0e20;
	printf("%f\n", a);
	return 0;
}
結果:

 

\

造成這種結果的原因是:計算機缺少足夠的進行正確運算所需的十進制位數。2.0e20為2後面加20個0.若加1,變化的其實是第21位,若需要正確計算,至少需要存儲21位數字,但是float只要6.7位有效數字。以上錯誤結果會隨著平台不同而表現不同。

 

3.使用%d顯示float值不會把float轉化為近似的int值,而是顯示垃圾值。

 

4.scanf的讀取習慣

 

/* praise1.c -- uses an assortment of strings */
#include 
#define PRAISE "What a super marvelous name!"
int main(void)
{
    char name[40];

    printf("What's your name?\n");
    scanf("%s", name);
    printf("Hello, %s. %s\n", name, PRAISE);
  
    return 0;
}
結果:

 

What's your name?

Tony KK

Hello,Tony.What a super marvelous name!

造成這種原因是:使用%s的scanf()只會讀入第一個單詞而不會把整個語句作為字符串讀入。C可以使用其他讀取函數(如gets())來處理一般的字符串。

 

5.strlen()函數和sizeof():

sizeof運算符,以字節為單位給出數據的大小,strlen()函數以字符串為單位給出字符串的長度。

 

#include 
#include       /* provides strlen() prototype */
#define PRAISE "What a super marvelous name!"
int main(void)
{
	char name[40];

	printf("What's your name?\n");
	scanf_s("%s", name);
	printf("Hello, %s. %s\n", name, PRAISE);
	printf("Your name of %d letters occupies %d memory cells.\n",
		strlen(name), sizeof name);
	printf("The phrase of praise has %d letters ",
		strlen(PRAISE));
	printf("and occupies %d memory cells.\n", sizeof PRAISE);

	return 0;
}
交互:

 

What's your name?

Morgan Buttercup

Hello,Margan.What a super marvelous name!

Your name of 6 letters occupies 40 memory cells.

The phrase of praise has 28 letters and occupies 29 memory cells.

解釋:

對於name數組,sizeof顯示的是數組長度,strlen()顯示的是已經用了的數組內長度。對於字符串PRAISE,sizeof比strlen()多了1,因為它把結束的\0也計算進來了。

 

6.負數轉化為unsigned和大於255的值轉化為字符相當於取模

 

#include 
#define PAGES 336
#define WORDS 65618
int main(void)
{
    short num = PAGES;
    short mnum = -PAGES;

    printf("num as short and unsigned short:  %hd %hu\n", num,
            num);
    printf("-num as short and unsigned short: %hd %hu\n", mnum,
            mnum);
    printf("num as int and char: %d %c\n", num, num);
    printf("WORDS as int, short, and char: %d %hd %c\n",
            WORDS, WORDS, WORDS);
   return 0;
}
輸出:

 

\

首先,-336並沒有像我們期待的轉化為336,而是變成65200.原因是short int中 0到32767 表示他們本身,42768到65535表示負數,65535代表-1,65534代表-2,依此類推,65200表示-336。所以不要期待%u能把數字和符號分開。

第二行顯示如果你想把一個大於255的值轉化為字符,相當於取模:

2進制的336在內存中為0000000101010000,可是字符只能轉化小於等於255的數字,否則就只是截取一段轉化,此時值就變了。當我們試著打印一個比short int大的數字時也是這樣。

 

7.prinf讀取stack裡的數字是按%讀取的

 

#include 
int main(void)
{
    float n1 = 3.0;
    double n2 = 3.0;
    long n3 = 2000000000;
    long n4 = 1234567890;

    printf("%.1e %.1e %.1e %.1e\n", n1, n2, n3, n4);
    printf("%ld %ld\n", n3, n4);
    printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);
   
    return 0;
}
結果:

 

\

計算機根據變量的類型而非轉換說明符把這些值放入值棧中。所以,n1在堆棧中占用8個字節(float變為double),同理,n2占8個字節,n3,n4分別占用4個字節。然後控制轉移到prinf()函數,prinf()是按照轉換說明符去讀取的。%ld讀取4個字節,也就是n1前半部分,下一個%ld再讀取4個字節,n1的後半部分,因此最後結果都錯。
 

 



 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved