?? c primer plus
字號:
在上面例子中
datas == &data[0] // 相同的地址
datas + 2 == &data[2] // 相同的地址
*(dates + 2) == dates[2] // 相同的值
/* day_mon3.c -- uses pointer notation */
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for (index = 0; index < MONTHS; index++)
printf("Month %2d has %d days.\n", index +1,
*(days + index)); // 與 days[index] 相同
return 0;
}
7、函數、數組與指針
// sum_arr1.c -- sums the elements of an array
// use %u or %lu if %zd doesn't work
#include <stdio.h>
#define SIZE 10
// int sum(int *ar, int n);
int sum(int ar[], int n);
int main(void)
{
int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
long answer;
answer = sum(marbles, SIZE);
printf("The total number of marbles is %ld.\n", answer);
printf("The size of marbles is %zd bytes.\n",
sizeof marbles);
return 0;
}
//int sum(int *ar, int n) // ar[] 比 *ar 更好
int sum(int ar[], int n)
{
int i;
int total = 0;
for( i = 0; i < n; i++)
total += ar[i];
printf("The size of ar is %zd bytes.\n", sizeof ar);
return total;
}
/* sum_arr2.c -- sums the elements of an array */
#include <stdio.h>
#define SIZE 10
int sump(int * start, int * end);
int main(void)
{
int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
long answer;
answer = sump(marbles, marbles + SIZE); // C保證指針marbles + SIZE是合法的,但marbles[SIZE]越界了
printf("The total number of marbles is %ld.\n", answer);
return 0;
}
/* use pointer arithmetic */
int sump(int * start, int * end) // start數組首元素地址;end數組末元素的下一個單元的地址
{
int total = 0;
while (start < end)
{
total += *start; /* add value to total */
start++; /* advance pointer to next element */
}
return total;
}
8、對未初始化的指針存取值
int *pt;
*pt = 5; // 可怕的錯誤!!! 因為指針pt未初始化,它的是隨機的,不知5會被存儲到哪時
int a;
int *pt=&a;
*pt = 5; // 正確,5被存到a變量中
int urn[3];
int *ptr1, *ptr2;
ptr1 = urn; // 正確,ptr1 指向 urn[0]的地址
ptr1++; // 正確,ptr1 指向 urn[1]的地址
ptr2 = ptr1 + 2; // 正確,ptr2 指向 urn數組之后的存儲單元
ptr2 = urn + 1; // 正確,ptr2 指向 urn[1]
urn++; // 錯誤
ptr2 = ptr2 + ptr1; // 錯誤
ptr2 = urn * ptr1; // 錯誤
9、保護數組內容
通常我們直接傳遞數值,只有需要在函數中修改值時,才傳遞指針。
但對于數組,C不支持把整個數組作為函數參數進行傳遞,只能傳遞指針。
傳址效率更高,如果是傳值,那得分配足夠內存塊,然后復制一份過去。
如果不希望變量或數組的內容被函數修改,可以給形參加const。
例1:const用于形式參數
/* arf.c -- array functions */
#include <stdio.h>
#define SIZE 5
void show_array(const double ar[], int n);
void mult_array(double ar[], int n, double mult);
int main(void)
{
double dip[SIZE] = {20.0, 17.66, 8.2, 15.3, 22.22};
printf("The original dip array:\n");
show_array(dip, SIZE);
mult_array(dip, SIZE, 2.5);
printf("The dip array after calling mult_array():\n");
show_array(dip, SIZE);
return 0;
}
/* displays array contents */
void show_array(const double ar[], int n) // ar數組被限定為只讀,不能被修改
{
int i;
for (i = 0; i < n; i++)
printf("%8.3f ", ar[i]);
putchar('\n');
}
/* multiplies each array member by the same multiplier */
void mult_array(double ar[], int n, double mult) // 沒加const,ar數組可以修改
{
int i;
for (i = 0; i < n; i++)
ar[i] *= mult;
}
例2:const用于指針與數組
#include <stdio.h>
int main(void)
{
double arr_var[4] = {88.00, 100.12, 59.45, 183.11}; // 普通數組
arr_var[2] = 99.99;
const double arr_con[4] = {0.08, 0.075, 0.0725, 0.07}; // 常量數組
//arr_con[2] = 99.99; // 不允許
const double * pd = arr_var; // 指向常量的普通指針:指針可變,內容不可變
const double * pd2 = arr_con;
pd = &arr_var[2];
pd = &arr_con[2];
//*pd = 99.99; // 不允許
//pd[2] = 222.22; // 不允許
double * const pdc = arr_var; // 常量指針:指針不可變,內容可變
//double * const pdc2 = arr_con;//不允許
//pdc = &arr_var[2]; // 不允許
//pdc = &arr_con[2]; // 不允許
*pdc = 99.99;
pdc[2] = 222.22;
const double * const pcdc = arr_var; // 指向常量的常量指針:指針、內容都不可變
const double * const pcdc2 = arr_con;
//pcdc = &arr_var[2]; // 不允許
//pcdc = &arr_con[2]; // 不允許
//*pcdc = 99.99; // 不允許
//pcdc[2] = 222.22; // 不允
double *p = arr_var; // 普通指針:指針、內空都可變
//double *p2 = arr_con; // 不允許
p = &arr_var[2];
//p = &arr_con[2]; // 不允許
*p = 99.99;
p[2] = 222.22;
return 0;
}
10、指針和多維數組
/* zippo1.c -- zippo info */
#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {11,12}, {21,22}, {31,32}, {44, 42} };
printf(" zippo = %p, zippo + 1 = %p &zippo[1][0] = %p\n",
zippo, zippo + 1, &zippo[1][0]);
printf("zippo[0] = %p, zippo[0] + 1 = %p &zippo[0][1] = %p\n",
zippo[0], zippo[0] + 1, &zippo[0][1]);
printf(" *zippo = %p, *zippo + 1 = %p\n\n",
*zippo, *zippo + 1);
printf("zippo[0][0] = %d\n", zippo[0][0]);
printf(" *zippo[0] = %d\n", *zippo[0]);
printf(" **zippo = %d\n\n", **zippo);
printf(" zippo[2][1] = %d\n", zippo[2][1]);
printf("*(*(zippo+2) + 1) = %d\n\n", *(*(zippo+2) + 1));
int i,j;
for (i=0; i<4; i++)
{
for (j=0; j<2; j++)
printf("&zippo[%d][%d] = %p ", i, j, &zippo[i][j]);
printf("\n");
}
return 0;
}
輸出結果:
zippo = 0012FF44, zippo + 1 = 0012FF4C &zippo[1][0] = 0012FF4C
zippo[0] = 0012FF44, zippo[0] + 1 = 0012FF48 &zippo[0][1] = 0012FF48
*zippo = 0012FF44, *zippo + 1 = 0012FF48
zippo[0][0] = 11
*zippo[0] = 11
**zippo = 11
zippo[2][1] = 32
*(*(zippo+2) + 1) = 32
&zippo[0][0] = 0012FF44 &zippo[0][1] = 0012FF48
&zippo[1][0] = 0012FF4C &zippo[1][1] = 0012FF50
&zippo[2][0] = 0012FF54 &zippo[2][1] = 0012FF58
&zippo[3][0] = 0012FF5C &zippo[3][1] = 0012FF60
從上分析得出:
zippo[0]、*zippo 都是指向第1行的指針;
**zippo、*zippo[0]、zippo[0][0] 都是第1個元素的值;
zippo + 1 表示指向下一行。
數組與指針關系圖
zippo zippo+1 zippo+2 zippo+3
| zippo[0] | zippo[1] | zippo[2] | zippo[3] |
|~~~~~~~|~~~~~~~|~~~~~~~|~~~~~~~|~~~~~~~|~~~~~~~|~~~~~~~|~~~~~~~|
|zippo |zippo |zippo |ippo |zippo |zippo |ippo |zippo |
|[0][0] |[0][1] |[1][0] |[1][1] |[2][0] |[2][1] |[3][0] |[3][1] |
|_______|_______|_______|_______|_______|_______|_______|_______|
地址 |FF44 FF48 |FF4C FF50 |FF54 FF5C |FF60 FF64 |
/* zippo2.c -- zippo info via a pointer variable */
#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5, 7} };
int (*pz)[2]; // pz是指針,指向一個包含2個元素的int數組,pz[i]被解釋為一個由2個整數構成的元素,pz[i][j]是一個int
// int * pax[2];// pax是數組,是由兩個指向int的指針構成的數組,pax[i]是一個int的地址
pz = zippo;
printf(" pz = %p, pz + 1 = %p\n",
pz, pz + 1);
printf("pz[0] = %p, pz[0] + 1 = %p\n",
pz[0], pz[0] + 1);
printf(" *pz = %p, *pz + 1 = %p\n",
*pz, *pz + 1);
printf("pz[0][0] = %d\n", pz[0][0]);
printf(" *pz[0] = %d\n", *pz[0]);
printf(" **pz = %d\n", **pz);
printf(" pz[2][1] = %d\n", pz[2][1]);
printf("*(*(pz+2) + 1) = %d\n", *(*(pz+2) + 1));
return 0;
}
pz是一個指針,也可以像數組名一樣使用:
zippo[m][n] == * ( *(zippo+m) + n )
pz[m][n] == * ( *(pz+m) + n )
11、函數和多維數組
int sum2(int ar[][], int rows); // 錯誤的聲明
int sum2(int ar[3][4], int rows); // 3被忽略
int sum2(int ar[][4], int rows); // 標準形式
int sum2(int [][4], int ); // 可省略參數名
typedef int arr4[4]; // aar4是4個int的數組
typedef arr4 arr3x4[3]; // arr3x4 是3個aar4的數組
int sum2(arr3x4 ar, int rows);
一般聲明N維數組的指針時,除了最左邊的方括號可以留空之外,其他都需要填寫數值。
int sum4d(int ar[][12][20][30], int rows); // ar是四維數組指針
int sum4d(int (*ar)[12][20][30], int rows); // 與上面的方式等效,其中ar指向一個12x20x30的int數組
12、指針兼容性
int n = 5;
double x;
int * pi = &n;
double * pd = &x;
x = n; // 隱式的類型轉換
pd = pi; // 編譯時錯誤
int * pt;
int (* pa)[3]; // 指向3個元素的int數組,pa[i]被解釋為一個由3個整數構成的元素,pa[i][j]是一個int
int ar1[2][3];
int ar2[3][2];
int **p2; // 指向指針的指針
pt = &ar1[0][0]; // 都指向int
pt = ar1[0]; // 都指向int
pt = ar1; // 非法
pa = ar1; // 都指向int[3]
pa = ar2; // 非法
p2 = &pt; // 都指向int *
*p2 = ar2[0]; // 都指向int
p2 = ar2; // 非法
int *p1;
const int * p2;
const int **pp2;
p1 = p2; // 非法,把const指針賦給非const指針
p2 = p1; // 合法,把非const指針賦給const指針
pp2 = &p1; // 非法,把非const指針賦給const指針
const int **pp2;
int *p1;
const int n = 13;
pp2 = &p1; // 不允許,但我們假設允許
*pp2 = &n; // 合法,二者都是const,但這同時會使p1指向n
*p1 = 10; // 合法,改變const n的值
13、變長數組(VLA)
Fortran語言允許在函數調用中指定二維的大小,Fortran是很古老的編程語言
但多年來,數值計算庫豐富,C正在逐步代替Fortran,如果能轉找到C是很有意義的。
因此,C99標準引入了變長數組,它允許使用變量定義數組各維大小。
int quarters = 4;
int regions = 5;
int sales[regions][quarters]; // 一個變長數組(VLA)
變長數組必須是自動存儲類的,必須在函數內部或作為參數聲明,而且聲明時不可以初始化。
變長數組允許動態分配存儲單元,即在程序運行時指定數組大小;
常規的C數組是靜態存儲分配的,也就是說數組大小在編譯時已經確定。
int sum2d(int rows, int cols, int ar[rows][cols]); // ar是一個變長數組(VLA)
int sum2d(int ar[rows][cols], int rows, int cols); // 錯誤
int sum2d(int, int, int ar[*][*]); // 可省去參數名
int sum2d(int rows, int cols, int ar[rows][cols])
{
int r;
int c;
int tot = 0;
for (r=0; c<rows; r++)
for (c=0; c<cols; c++)
tot += ar[r][c];
return tot;
}
14、復合文字
C99標準新增復合文字,不過許多編譯器尚未支持。
普通數組聲明方法:
int diva[2] = {10, 20};
下面是一個復合文字,創建一個包含兩個int值的無名稱數組復合文字:
(int [2]) {10, 20}
使用復合文字方法:
int * pt1;
pt1 = (int [2]){10, 20};
例:
// flc.c -- funny-looking constants
#include <stdio.h>
#define COLS 4
int sum2d(int ar[][COLS], int rows);
int sum(int ar[], int n);
int main(void)
{
int total1, total2, total3;
int * pt1;
int (*pt2)[COLS];
pt1 = (int [2]) {10, 20}; // 復合文字
pt2 = (int [2][COLS]) { {1,2,3,-9}, {4,5,6,-8} };
total1 = sum(pt1, 2);
total2 = sum2d(pt2, 2);
total3 = sum((int []){4,4,4,5,5,5}, 6); // 參數為復合文字
printf("total1 = %d\n", total1);
printf("total2 = %d\n", total2);
printf("total3 = %d\n", total3);
return 0;
}
int sum(int ar[], int n)
{
int i;
int total = 0;
for( i = 0; i < n; i++)
total += ar[i];
return total;
}
int sum2d(int ar[][COLS], int rows)
{
int r;
int c;
int tot = 0;
for (r = 0; r < rows; r++)
for (c = 0; c < COLS; c++)
tot += ar[r][c];
return tot;
}
第十一章 字符串和字符串函數
stdio.h
gets() 輸入字符串
puts() 輸出字符串
string.h (ANSI C 之前的可能是 strings.h)
strcat() 連接字符串
strncat() 連接字符串,限制長度
strcmp() 比較字符串
strncmp() 比較字符串,限制長度
strcpy() 復制字符串
strncpy() 復制字符串,限制長度
sprintf() 格式化字符串
strchr() 從左向右查找字符
strrchr() 從右向左查找字符
strstr() 從左向右查找字符串
1、字符串表示和字符串I/O
// strings.c -- stringing the user along
#include <stdio.h>
#define MSG "You must have many talents. Tell me some."
// a symbolic string constant
#define LIM 5
#define LINELEN 81 // maximum string length + 1
int main(void)
{
char name[LINELEN];
char talents[LINELEN];
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -