相較於基本型別
int, double,C語言還有衍伸資料型別(Derived datatype)
。
其中很常被應用的,就是指標(pointer)
、陣列(Array)
、結構(struct)
指標的設計,是為了讓CPU可以間接取得資料,有以下優點:
指標本身是一個物件,指向任何一個已存在物件,可以被指定或拷貝
int i = 42;
int *p = &i; //p指向i
#include <stdio.h>
int main() {
int i = 42;
int *p; //* 跟在一個型別,且是宣告的一部份,所以p是一個pointer
p = &i; //p指向i
printf("i: %d\n", i);
printf("*p: %d\n", *p);
printf("p: %p\n", p);
printf("&i: %p\n", &i);
return 0;
}
是一個複合資料型別,放置單一型別物件的容器,並且以位置來存取它們,有固定的尺寸。
通常是存放char
, int
型別的資料
在C語言,一個字串本身會在結尾自帶\0
結束字元,所以當我們把一個字串用陣列儲存時,實際結尾會有一個\0
也被儲存。
例如: char str[20] = "Hello"
在陣列的存放,是一個長度為6的陣列,最後擺放\0
int a[10]; //宣告一個10個int物件的陣列
int *p[10]; //宣告一個10個int指標的陣列
因為陣列的長度要在編譯期就決定好。如果想要在執行期動態生成陣列,要用動態配置記憶體的方式。
int *arr = (int *) malloc(sz * sizeof(int));
我們以 sizeof 求得單一元素的大小後,乘上陣列的長度 sz 即可配置一塊足夠大小的記憶體,用來儲存陣列 arr 的元素。由此可知,陣列在電腦中以是一整塊連續的記憶體來儲存,所以可以用索引值快速存取。
如果想要在配置記憶體時一併將元素初始化為 0,改用 calloc() 函式即可。但 calloc() 函式的參數略有不同:
int *arr = (int *) calloc(sz, sizeof(int));
由於多了初始化的動作,calloc() 函式會比 malloc() 函式慢一點點。
使用完後同樣要釋放記憶體:
free(arr);
由於陣列內部是單一且連續的記憶體區塊,所以可在單一 free() 函式呼叫中釋放掉。不論使用 malloc() 或 calloc(),皆使用 free() 來釋放記憶體。
我們來看一個動態配置記憶體陣列的範例:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int size = 0;
printf("輸入長度:");
scanf("%d", &size);
int *arr = malloc(size * sizeof(int));
printf("指定元素:\n");
for(int i = 0; i < size; i++) {
printf("arr[%d] = ", i);
scanf("%d" , arr + i);
}
printf("顯示元素:\n");
for(int i = 0; i < size; i++) {
printf("arr[%d] = %d\n", i, *(arr+i));
}
free(arr);
return 0;
}
陣列使用零或正整數存取陣列元素。參考以下範例:
#include <stdio.h>
int main(void)
{
int arr[] = {3, 4, 5};
printf("%d", arr[0]);
printf("%d", arr[1]);
printf("%d", arr[2]);
return 0;
}
對一個指標做加減,會移動指向陣列中的位置
#include <iostream>
using namespace std;
int main() {
int a[] = {1,2,3,4,5};
int *ip = a; //等同於int *ip = &a[0]
int *ip2 = ip + 4; //ip2指向a[4]
cout << ip2 << endl;
return 0;
}
走訪陣列元素的方式是使用 for 迴圈搭配計數器 (counter)。參考下例:
#include <stdio.h>
int main(void)
{
int arr[] = {3, 4, 5, 6, 7};
for (int i = 0; i < 5; i++) {
printf("%d\n", arr[i]);
}
return 0;
}
C 陣列本身沒有儲存陣列大小的資訊。如果想要知道陣列的大小,得自行計算。參考下例:
#include <stdio.h>
int main(void)
{
int arr[] = {3, 4, 5, 6, 7};
int sz = sizeof(arr) / sizeof(int);
printf("%d", sz);
return 0;
}
在此範例程式中,我們在第 6 行分別計算陣列大小和陣列元素大小,將其相除後即可得陣列長度。在本例中其值為 5。
但這個方式只對自動配置記憶體的陣列有效,若陣列使用動態配置記憶體,則無法使用這個方法。
先前的範例皆為一維陣列,但 C 語言允許多維陣列。參考以下宣告多維陣列的敘述:
int mtx[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
我們同樣可以對多維陣列存取索引值:
#include <stdio.h>
int main(void)
{
int mtx[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
printf("%d\n", mtx[1][1]);
return 0;
}
結構(struct)
可以讓使用者創造自己定義的資料型別
例如一本書的銷售資訊包含多種資料:
struct Sales_data {
char* book_no;
int units_sold;
int price;
double revenue;
};
其中book_no
, units_sold
, price
,revenue
是這個struct的data members,簡稱members
#include <stdio.h>
struct Sales_data {
char* book_no;
int units_sold;
int price;
double revenue;
};
int main() {
struct Sales_data book1;
book1.book_no = "AAA";
book1.units_sold = 1000;
book1.price = 200;
book1.revenue = book1.units_sold * book1.price;
printf("Revenue: %.2f\n", book1.revenue);
return 0;
}
C/C++程式語言觀念