0.展示PTA總分
- 指針:
1.本章學習總結
1.1 學習內容總結
-
指針做循環變量做法:
1.指針所指向的內容為字符型時:通常為*p='\0'但字符串是以fgets函數輸入時結束標志則為** p&&p!='\n' 。
2.指針所指向的內容為數字時:前提需知數組長度,通過q<p+n進行結束判斷(其中q、p為均為指針,n**為數組長度)。 -
字符指針如何表示字符串:
char* sp = "point";
printf("%s", sp);//字符指針sp作為printf的輸出參數
- 動態內存分配:此部分內容主要有4種函數malloc、calloc、realloc、free。
1.malloc- malloc()函數會向堆中申請一片連續的可用內存空間。若申請成功,返回指向這片內存空間的指針;若失敗,則會返回NULL。所以我們在用malloc()函數開辟動態內存之后,一定要判斷函數返回值是否為NULL。注意:malloc()返回的是void*,所以在分配內存時必須強制轉換為所需指針類型。
//示例
int *p = NULL;
int n = 0;//所需內存大小
scanf("%d", &n);
p = (int*)malloc(sizeof(int) * n);
2.calloc
* 與malloc()函數的區別只在於:calloc()函數會在返回地址之前將所申請的內存空間中的每個字節都初始化為0。calloc()函數功能是動態分配n個大小(字節長度)為size的內存空間。
//示例
int *p = NULL;
int n = 0;//所需內存大小
scanf("%d", &n);
p = (int*)calloc(n,sizeof(int));
3.realloc
* 當分配的內存大小不合適時(太大或太小),此時可通過realloc()進行對動態開辟內存大小的調整(既可以往大調整, 也可以往小了調整)。若調整成功, 返回值為調整大小后內存的起始位置, 若失敗(當沒有內存可以分配時), 則返回NULL, 所以還是要對返回值判空。
//示例
int *p = NULL;
p = (int*)malloc(20);
p=(int*)realloc(p,40);//調整內存
4.free
* 在堆中申請的內存空間不會自動釋放內存,如果我們不手動釋放,只有在程序運行結束時才會釋放, 這樣就可能會造成內存泄漏, 即堆中這片內存中的數據已經不再使用, 但它一直占着這片空間,(通俗說就是就是占着茅坑不拉屎), 所以當我們申請的動態內存不再使用時 ,一定要及時釋放。
//示例
int *p=NULL;
p=(int*)malloc(20);
free(p);//釋放內存
- 指針數組及其應用:
- 定義:int*a[10];其類似於二位數組,但列數未知,當我們進行賦值時,同樣需要進行動態內存分配。
//示例
for(i = 0; i < 10; i++)
{
a[i] = (char *)malloc(sizeof(int)*10);//分配內存
scanf("%d", a[i]);
}
2. 應用見PTA題目:<a href="https://pintia.cn/problem-sets/1192644021711056896/problems/1196345664248123398" target="_blank">7-10 6-8 計算最長的字符串長度</a>
題目相關內容截圖:
- 二級指針、行指針:
1.二級指針:定義:int **p;其類似於二維數組。可以寫成p[][]形式。對於 **p,*p表示的是 地址 ,**p才表示 內容 ,可借助二位數組進行理解。
2.行指針:行指針是指向數組的指針,定義:int a(*p)[5];(相當於int a[][5]);p即為行的地址。其中:*p=a[0],*(p+1)=a[1],*p+a[0][1]··· - 函數返回值為指針:
- 函數聲明:int*fun();此函數所返回的值即為一個地址。需注意的是:函數運行結束后會銷毀在它內部定義的所有局部數據,函數返回的指針請盡量不要指向這些數據,它們在后續使用過程中可能會引發運行時錯誤。
//示例
#include <stdio.h>
int* fun()
{
int n = 100;
return &n;
}
int main()
{
int* p, n;
p = fun();
scanf("%d", &n);
printf("%d\n", *p-n);
return 0;
}
- 輸入數據100時,結果2095176,為異常數據,說明返回了一個異常地址。
1.2 本章學習體會
剛剛開始時,的確覺得本章內容較難,有些難理解。但慢慢的跟數組聯系上,並刷了一些題目之后,就感覺難度就降了好多。怎么說呢,可能是熟能生巧吧。我個人感覺其實只要願意去學,去做題,該克服的困難總會克服。
2.PTA實驗作業
2.1 6-9 合並兩個有序數組
2.1.1 偽代碼
//此題為函數題,以下代碼為題目
#include <stdio.h>
#include <stdlib.h>
void printArray(int* arr, int arr_size); /* 打印數組,細節不表 */
void merge(int* a, int m, int* b, int n); /* 合並a和b到a */
int main(int argc, char const *argv[])
{
int m, n, i;
int *a, *b;
scanf("%d %d", &m, &n);
a = (int*)malloc((m + n) * sizeof(int));
for (i = 0; i < m; i++) {
scanf("%d", &a[i]);
}
b = (int*)malloc(n * sizeof(int));
for (i = 0; i < n; i++) {
scanf("%d", &b[i]);
}
merge(a, m, b, n);
printArray(a, m + n);
free(a); free(b);
return 0;
}
//題目結束,以下為偽代碼
void merge(int* a, int m, int* b, int n)//函數定義
int i=a數組長度-1;
int j=b數組長度-1;
int max=ab總長度之和-1;
while(i和j均大於0)
{
從兩數組末尾開始
if a的數大於b的數
則 a[max]=a的數,同時max自減
否則
a[max]=b的數,同時max自減
end if
}
end while
if b數組還有數沒有插入a數組
通過循環 將剩下的數插入a數組
2.1.3 總結本題的知識點
- 學習如何高效的將有序數組進行合並,而不是簡單粗暴的合並數組並重新排序。
2.1.4 PTA提交列表及說明
- 說明:
1.部分正確:剛開始的思路就如上說的簡單粗暴,而且排序的循環體還寫錯了。
2.部分正確:在1的基礎上寫完整了選擇法排序。但大數據過不去。
3.部分正確:更改為冒泡排序,大數據仍過不去。
4.編譯錯誤:改用上述偽代碼的方法,但是分號忘記打了。
5.全部正確。
2.2 7-4 說反話-加強版
2.2.1 偽代碼
for(從字符串末尾字符開始)
if 不是空格
計數器加1
else if 計數器不為0
循環往后輸出計數器個數字符
end if
輸出空格
計數器歸零
end for
2.2.3 總結本題的知識點
- 通過使用單詞‘開關’,判斷是否有單詞並記錄單詞長度,一舉兩得。
2.2.4 PTA提交列表及說明
- 說明:
1.編譯錯誤:定義的數組過大,超出范圍了。
2.編譯錯誤:同上。
3.內部錯誤:PTA的問題吧。
4.部分正確:最大句子測試點沒過,為50000個單詞。我只定義50000發現遠遠不夠。
5.內部錯誤:PTA問題。
6.全部正確:定義值改為100001。
2.3 實驗11-1-6 -指針 指定位置輸出字符串
2.3.1 偽代碼
//此題為函數題,以下為題目代碼
#include <stdio.h>
#define MAXS 10
char *match( char *s, char ch1, char ch2 );
int main()
{
char str[MAXS], ch_start, ch_end, *p;
scanf("%s\n", str);
scanf("%c %c", &ch_start, &ch_end);
p = match(str, ch_start, ch_end);
printf("%s\n", p);
return 0;
}
//題目結束,以下為我的函數偽代碼
char* match(char* s, char ch1, char ch2)//函數定義
for(遍歷數組)
找到ch1和ch2在數組中第一次出現位置
end for
如果 ch1沒找到
則輸出換行
結束函數
else if ch2沒找到
則從ch1在數組所在位置開始輸出
else
從ch1位置到ch2位置輸出
end if
返回 ch1在數組中的地址
2.3.3 總結本題的知識點
- 可能數組中有多個字符和啟示或終止符相同,此就需要設置開關僅需要第一次出現的位置。
2.3.4 PTA提交列表及說明
- 說明:
1.部分正確:忘了考慮ch2找不到的情況。
2.部分正確:ch1找不到的情況下,輸出跟PTA描述有誤。
3.部分正確:更改完還是一樣的問題。
4.部分正確:測試點取超長長度是過不去。
5.部分正確:改完ch2找不到時輸出少一個字符。
6.部分正確:(這個只是又提交了一遍一樣的)
7.部分正確:改回4的代碼
8.全部正確:發現代碼不能處理ch1重復出現情況,增加了是否第一次出現的開關。
3.閱讀代碼
poj 1972 Dice Stacking
代碼截圖
- 代碼功能:
- 有多組,每組有多個骰子,每個骰子的面由人決定。通過堆積骰子使得相鄰骰子的上下面相同。可以旋轉骰子使得面向自己所有面之和最大。
- 輸入:按順序為:組數,每組骰子個數,每個骰子每個面的數子。
- 輸出:面向的所有面之和的最大值。
- 值得學習地方:
1.for(scanf("%d",&T);T;T--),該句巧妙簡化了條件循環的代碼。
2.二維數組中通過字母建立面跟數的關系,但這種寫法對於目前c好像不能實現。