c++隨筆1

C語言和C++都有一個專爲調試而準備的工具函數,就是 assert()函數c++

這個函數是在C語言的 assert.h 庫文件裏定義的,程序員

因此包含到C++程序裏咱們用如下語句:#include <cassert>express

做用是,若是它的條件返回錯我,則終止程序的執行。編程

 

區分char *和char []:char *定義的是一個指向字符串的指針(注意:C語言中沒有對應字符串的內置類型或者類類型),而char []就是C語言中的用來定義字符數組(注意:字符數組是不一樣於字符串,若是字符數組以'\0'結尾,那麼能夠視爲字符串)。數組

char a[]在運行時賦值,值會從靜態區賦值到函數的棧中,對它進行修改不會產生任何問題。char *a在編譯時就肯定了,a指向靜態區中的值,沒有賦值到函數棧中, 所以對指針的內容進行修改會產生錯誤數據結構

瞭解一下 一個由 C / C++ 編譯的程序佔用的內存分爲如下幾個部分: 
一、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操做方式相似於數據結構中的棧。
二、堆區(heap) — 通常由程序員分配釋放, 若程序員不釋放,程序結束時可能由 OS 回收。注意它與數據結構中的堆是兩回事,分配方式卻是相似於鏈表。
三、全局區(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另外一塊區域。 - 程序結束後由系統釋放 。
四、文字常量區 —常量字符串就是放在這裏的。 程序結束後由系統釋放
五、程序代碼區—存放函數體的二進制代碼。函數

 

關於頭文件和源文件的分別工具

首先,咱們能夠將全部東西都放在一個.cpp文件內.this

而後編譯器就將這個.cpp編譯成.obj,obj是什麼東西?url

就是編譯單元了.一個程序,能夠由一個編譯單元組成,

也能夠有多個編譯單元組成. 若是你不想讓你的源代碼變得很難閱讀的話,

就請使用多個編譯單元吧.(一個函數不能放到兩個編譯單元裏面,但兩個以上

就能夠分別放在一個單元,也就是cpp裏面)

    那麼就是一個.cpp對應一個.obj,而後將全部的obj連接起來(經過一個叫連接器的程序),

組成一個.exe,也就是程序了.

    若是一個.cpp要用到另外一個.cpp定義的函數怎麼辦? 只需在這個.cpp種寫上他的函數聲明

就能夠了.其他工做由連接器幫你完成,你能夠隨便調用該函數.

    連接器將全部的obj鏈接起來,可是若是碰巧有相同的函數或外部變量怎麼辦?他如何識別?

通常來講是不能容許在同一個程序中,出現兩個同樣的函數名或外部變量名.

    可是隻得慶幸的是,c++能夠經過一種叫作連接屬性的關鍵字來限定,你這個函數是屬於整個程序

公用的,仍是隻是在一個編譯單元obj裏面使用的.

    這些關鍵字就是extern 和 static extern是外部連接的意思,也就是除了這個單元,外部的單元也是可以訪問這個函數的.static 是內部連接,自屬於本身單元.

說了這麼久,尚未說.h的做用呢?

    其實沒有.h也能很好的工做,可是當你發現一個外部連接的函數或外部變量,須要許多份

聲明,由於c++這種語言,在使用函數和變量的時候,必須將他聲明,爲什麼要聲明?聲明以後才

知道他的規格,才能更好的發現不和規格的部分.你別妄想一個編譯單元,會自動從另外一個

編譯單元那裏獲得什麼信息,知道你是如何定義這個函數的.

    因此說,只要使用到該函數的單元,就必須寫一份聲明在那個.cpp裏面,這樣是否是很麻煩,

並且,若是要修改,就必須一個一個修改.這真讓人受不了.


.h就是爲了解決這個問題而誕生,他包含了這些公共的東西.而後全部須要使用該函數的.cpp,只須要

用#include包含進去即可.之後須要修改,也只是修改一分內容.


請注意不要濫用.h,.h裏面不要寫代碼,.h不是.cpp的倉庫,什麼都塞到裏面.

若是在裏面寫代碼,當其餘.cpp包含他的時候,就會出現重複定義的狀況,

好比將函數func(){printf};放到頭文件a.h,裏面還有一些a.cpp須要的聲明等;

而後你發現b.cpp須要用到a.cpp裏面的一個函數,就很高興的將a.h包含進來.

注意,#include並非什麼申請指令,他就是將指定的文件的內容,原封不動的拷貝

進來.


這時候實際上a.cpp和b.cpp都有一個func()函數的定義.

若是這個函數是內部連接static的話,還好,浪費了一倍空間;

若是是extern,外部連接(這個是默認狀況),那麼根據在同一個程序內不可出現

同名函數的要求,鏈接器會絕不留情給你一個鏈接錯誤!

 

爲了避免同一個文件被include屢次

1   #ifndef方式
2   #pragma once方式

在可以支持這兩種方式的編譯器上,兩者並無太大的區別,可是二者仍然仍是有一些細微的區別。
    方式一:

    #ifndef __SOMEFILE_H__
    #define __SOMEFILE_H__
    ... ... // 一些聲明語句
    #endif

    方式二:

    #pragma once
    ... ... // 一些聲明語句


    #ifndef的方式依賴於宏名字不能衝突,這不光能夠保證同一個文件不會被包含屢次,也能保證內容徹底相同的兩個文件不會被不當心同時包含。固然,缺點就是若是不一樣頭文件的宏名不當心「撞車」,可能就會致使頭文件明明存在,編譯器卻硬說找不到聲明的情況

    #pragma once則由編譯器提供保證:同一個文件不會被包含屢次。注意這裏所說的「同一個文件」是指物理上的一個文件,而不是指內容相同的兩個文件。帶來的好處是,你沒必要再費勁想個宏名了,固然也就不會出現宏名碰撞引起的奇怪問題。對應的缺點就是若是某個頭文件有多份拷貝,本方法不能保證他們不被重複包含。固然,相比宏名碰撞引起的「找不到聲明」的問題,重複包含更容易被發現並修正。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 int main()
 4 {
 5     printf("The program test print style!\n");
 6     /* 以十進制形式輸出帶符號整數(正數不輸出符號) */
 7     printf("%d\n", 223);
 8     printf("%d\n", -232);
 9     printf("\n");
10     /* 以八進制形式輸出無符號整數(不輸出前綴O) */
11     printf("%o\n", 223);
12     printf("%o\n", -232);
13     printf("\n");
14     /* 以十六進制形式輸出無符號整數(不輸出前綴OX) */
15     printf("%x\n", 223);
16     printf("%x\n", -232);
17     printf("\n");
18     /* 以十進制形式輸出無符號整數 */
19     printf("%u\n", 223);
20     printf("%u\n", -232);
21     printf("\n");
22     /* 以小數形式輸出單、雙精度實數 */
23     printf("%f\n", 223.11);
24     printf("%f\n", 232.11111111);
25     printf("%f\n", -223.11);
26     printf("%f\n", -232.11111111);
27     printf("\n");
28     /* 以指數形式輸出單、雙精度實數 */
29     printf("%e\n", 223.11);
30     printf("%e\n", 232.11111111);
31     printf("%e\n", -223.11);
32     printf("%e\n", -232.11111111);
33     printf("\n");
34     /* 以%f%e中較短的輸出寬度輸出單、雙精度實數 */
35     printf("%g\n", 223.11);
36     printf("%g\n", 232.111111111111);
37     printf("%g\n", -223.11);
38     printf("%g\n", -232.111111111111);
39     printf("\n");
40     /* 輸出單個字符 */
41     printf("%c\n", 'a');
42     printf("%c\n", 97);   //輸出爲  'a'
43     printf("\n");
44     /* 輸出單個字符 */
45     printf("%s\n", "this is a test!");
46     printf("%s\n", "2342o34uo23u");
47     printf("\n");
48     getch();
49 }

assert的做用是現計算表達式 expression ,若是其值爲假(即爲0),那麼它先向stderr打印一條出錯信息,而後經過調用 abort 來終止程序運行

 

C編譯器要求變量的聲明須要放在做用域的開頭,這裏是函數的開始處。而C++編譯器不要求在哪用就在哪聲明,也能夠在開頭聲明好。因此,寫C++代碼是就比較放得開,何時須要何時聲明就能夠了。

 

sizeof(數組名)計算數組大小並非每次都管用哦。sizeof(數組名)/sizeof(數組一個元素)也並非每次均可以正確計算數組元素個數哦。

強行記憶學很差編程

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 int main()
 4 {
 5     char url[] = "www.baidu.com";
 6     char bb[] = { 0,1,2,3,4 };
 7     int age[]= { 0,1,2,3,4 };
 8     int isizeurl = sizeof(url);
 9     int isizebb = sizeof(bb);
10     int isizeage = sizeof(age);
11     printf("isizeurl:%d\n", isizeurl);
12     printf("isizebb:%d\n", isizebb);
13     printf("isizeage:%d", isizeage);
14     getchar();
15 }

你能夠看到,sizeof(數組名)是能夠計算獲得數組的字節大小的。這並非所有的事實!

 

Linux系統下C程序開發詳解:

1 .ii爲擴展名的文件,是已經預處理過的C++源代碼文件,也是中間代碼文件。 

2  .o爲擴展名的文件,是編譯後的目標文件,源文件生成的中間目標文件。

3 .s爲擴展名的文件,是彙編語言源代碼文件。 

4 .S爲擴展名的文件,是通過預編譯的彙編語言源代碼文件。 

5 .o爲擴展名的文件,是編譯之後的程序目標文件(Object file),目標文件通過鏈接成可執行文件

 

 

注意 NULL 就是 NULL,它被宏定義爲 0

  #define NULL 0

 不少系統下除了有 NULL 外,還有 NUL

NUL 是 ASCII 碼錶的第一個字符,表示的是空字符,其 ASCII 碼值爲 0。其值雖然都爲 0,但表示的意思 徹底不同。

 

函數宏中的#和##運算符

在函數宏中#能夠實現由函數宏實參生成字符串常量##實現了由函數宏實參生成標識符的一部分。(前者用於拼接字符串後者用於拼接標示符)看一下下邊的示例:

假如但願在字符串中包含宏參數,ANSI C容許這樣做,在類函數宏的替換部分,#符號用做一個預處理運算符,它能夠把語言符號轉化程字符串。例如,若是x是一個宏參量,那麼#x能夠把參數名轉化成相應的字符串。該過程稱爲字符串化

1 #include<stdlib.h>
2 #include<stdio.h>
3 #define psqs(x) printf("the square of"#x "is %d.\n",(x)*(x))
4 int main(void) {
5     int y = 4;
6     psqs(y);
7     psqs(2 + 4);
8     system("pause");
9 }

第一次調用宏時使用「y」代替#x;第二次調用時用「2+4″代#x。

##運算符能夠使用類函數宏的替換部分。另外,##還能夠用於類對象宏的替換部分。這個運算符把兩個語言符號組合成單個語言符號。例如:

#define XNAME(n) x##n

這樣宏調用:

XNAME(4)

展開後:x4

相關文章
相關標籤/搜索