在之前的第三課中學習了基本數據類型,第五課學習了循環結構程序,做練習的時候處理的是一些有規律的數據,比如1~100的正整數,而當我們面對一堆沒有規律的數據時該怎麼去循環處理呢?把數據組合在一起構成一個新的數據結構,并且能利用自增的序号來循環引用它們,這就是數組。
注意,請認真學習完《C程序設計(第五版)》第六章後再閱讀本文會有更大的收獲。
C語言數組
數組數組名和變量名
C語言數組命名遵從變量命名的規則,但是它們本質上有區别:變量名在程序裡是該變量對應存儲地址裡存儲的值;數組名等同于數組第一個元素的存儲地址。
下标尋址
數組元素的使用采用數組名[下标]的形式,那它的原理是怎樣的呢?
我們來深究一下數組内部元素是怎樣存儲的。首先,不管是數組名還是變量名,程序首先都會為它們開辟存儲空間,分配一個存儲地址;那麼變量名的值就是這個存儲地址裡存儲的值,數組名的值則是該數組第一個元素(下标0)的存儲地址,這樣就可以根據第一個元素的地址計算出第N個元素的存儲地址(數組元素的地址是遞增的),進而得到該存儲地址裡的值,也就是第N個元素的值。
元素數據類型統一
定義數組聲明數據類型,實際上是元素的數據類型,一個數組裡所有元素數據類型統一,好處就是在循環處理的時候都按照同一數據類型處理,不必額外做判斷,這樣省去不少麻煩。
多維數組
書本上介紹了二維數組,那如果把多個相同數據類型的二維 數組組合在一起,就構成了三維數組,同理,還有四維、五維……N維數組。
字符串學習過其他高級語言的小夥伴在一開始會有點迷惑:字符串作為一種常見的數據形式居然沒有定義在C語言的基本數據結構中,卻介紹了字符char這種數據結構。原來在C語言中,字符串借助于字符數組,才有了一席生存的空間和施展的舞台。
C語言字符數組
注意,使用字符串相關的函數時,首先要引入頭文件:#include <string.h>。
字符串輸入和輸出
輸出指的是把字符數組輸出為字符串的形式,常用printf('%s', str),和puts(str)。
書中的輸入函數gets()在visual studio 2022中被強制要求使用gets_s()函數來代替,區别在于後者要指定字符數組的長度,而筆者推薦使用另外一個函數fgets(),至于他們有何區别又為何推薦使用fgets()大家自己寫代碼去對比分析以及上網查閱資料來加深理解。
字符串的長度
strlen()返回字符串自身的長度(以第一個\0為結尾但不包含\0),strlen("hello")和strlen("hello\0world")結果一樣。
sizeof()返回的是字符數組的長度,字符數組一旦定義了,其長度就不會再變了。
字符串連接
與其叫字符串連接,不如稱之為字符串合并/追加更直觀。書上的strcat()函數在visual studio 2022推薦用strcat_s()來替代,這個函數多一個參數——字符串連接後的長度,這個是為了防止合并後的字符串過長(超出目标字符數組的長度)導緻内存溢出,有興趣的可以網上搜索相關的資料。
實戰編程回顧上一課輸出1000以内完數,并且輸出因子如6 its factors are 1,2,3
舊的思路:通過循環取因子相加判斷出來完數,然後再循環輸出因子,要寫兩次同樣的循環。
優化思路:把第一次循環得到的因子存儲在數組中,判斷是完數之後再輸出這個數組裡的因子,代碼參考:
static void fun() {
for (int num = 1; num < 1000; num ) {
int tmp_sum = 0, factor_index = 0;
int factors[50] = { 0 };
for (int i = 1; i < num; i ) {
if (num % i == 0) {
tmp_sum = i;
factors[factor_index] = i;
factor_index ;
}
}
if (num == tmp_sum) {
printf("%d its factors are ", num);
for (int j = 0; j < factor_index; j ) {
if (j < factor_index - 1) {
printf("%d,", factors[j]);
}
else {
printf("%d\n", factors[j]);
}
}
}
}
}
有一個已排好序的數組,要求輸入一個數後,按原來排序的規則将它插入數組中。
解題關鍵有兩點,一是找到插入的位置,然後要把後面的元素依次往後移動一個位置。我們以一個從小到大的數組為例進行編程:
static void fun4() {
int arr_len = 11;
int arr[11] = { 0,10,20,30,40,50,60,70,80,90,100 };
int new_num;
printf("請輸入插入的數值:\n");
scanf_s("%d", &new_num);
int tmp_num = -10000, flag = 0;
for (int i = 0; i < arr_len; i )
{
int cur_num = arr[i];
if (flag == 1) {
arr[i] = tmp_num;
tmp_num = cur_num;
continue;
}
if (new_num <= cur_num) {
flag = 1;
tmp_num = cur_num;
arr[i] = new_num;
}
if (flag == 0 && i == arr_len - 1) {
arr[i] = new_num;
}
}
for (int i = 0; i < arr_len; i )
{
printf("%d ", arr[i]);
}
}
程序裡把找插入位置和元素後移的兩個循環合成一個循環裡面,一旦确定了插入位置之後,就不用再去判斷找插入位置了,所以定義了一個flag标識,當flag為1時啟用continue語句不執行後續的代碼了。如果循環結束還沒有找到插入的位置則說明插入的數比數組中任意數字都大,就讓它直接替換數組末尾。
輸出楊輝三角(10行)
解題思路的關鍵是找到規律:arr[i][j] = arr[i - 1][j] arr[i - 1][j - 1]
static void fun6() {
int rows = 10;
int arr[10][10];
for (int i = 0; i < rows; i )
{
for (int j = 0; j < 10; j )
{
if (j == 0 || i == j) {
arr[i][j] = 1;
printf("1\t");
continue;
}
if (j > i) {
arr[i][j] = 0;
//printf("0\t");
continue;
}
if (i > 1) {
arr[i][j] = arr[i - 1][j] arr[i - 1][j - 1];
printf("%d\t", arr[i][j]);
}
}
printf("\n");
}
}
目前,我們的《C程序設計》課程已過半,通過程序練習可知,目前的知識能解決好多數學上的問題,進行一些較為複雜的程序設計。
不斷的編程累積經驗。一道題往往不止一種解法,要多去嘗試,不僅嘗試不同的算法,還要嘗試用不同的數據結構、循環結構等C語言自身的語法特性來進行程序編碼。
關于算法性的題目。目前比較好的學習方式是練習,去網站上刷題,把常見的經典算法題過一遍,慢慢地去積累。
邏輯向代碼的轉換。有的同學知道題目的解法,能用文字描述出來,但是就是不知道程序如何下手。比如今天學習的數組,一個簡單的M行N列的二維數組,嵌套循環取值那裡一時半會轉不過來彎,總是覺得很“别扭”。
初學者的問題多而且千奇百怪,一定要堅持下來,多寫多練,沒有什麼捷徑可言。至于為何有的人學得快,而有的人卻還沒入門,筆者認為最重要的是興趣。不要把程序看成是一行行冰冷的代碼,經過不斷地調試、修改後,程序運行出想要的結果時,相信你的嘴角一定是上揚的^_^
往期文章
一起學《C程序設計》第五課——循環控制及實戰練習
一起學《C程序設計》第四課——if語句、switch語句及實戰練習
一起學《C程序設計》第三課——數據結構、運算符、表達式和語句
一起學《C程序設計》第二課——算法
一起學《C程序設計》第一課——C語言概述和學習前的準備、意識
C程序設計(譚浩強)——第五版和第三版對比
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!