一、字符串與指針
? ? ? ? 用字符指針指向一個字符串,可以不定義字符數組,而定義字符指針。用字符指針指向字符串中的字符。不能使用指針去改變不能修改的空間。
eg1. 運用指針將 src 的內容拷貝到 dest 中去
?
void Strcpy(char *dest, char *src)
{while(*src != '\0'){*dest = *src;++dest;++src;}*dest = '\0';
}
eg2. 運用指針將 src 的內容剪切到 dest 后面
void Strcat(char *dest, const char *src)
{while(*dest){*dest = *dest;++dest;}while(*src){*dest = *src;++dest;++src;}*dest = '\0';
}
eg3. 運用指針比較 s1 與 s2 的大小
int Strcmp(const char *s1, const char *s2)
{while(*s1 == *s2 && *s1 != '\0' && *s2 != '\0') {++s1;++s2;}return *s1 - *s2;
}
eg4.?運用指針將 src 的前 n 個字符拷貝到 dest 中去
//將src的前n個字符拷給dest中去
void Strncpy(char *dest, const char *src,int n)
{while(*src != '\0' && n-- != 0 ){*dest = *src;++dest;++src;}//*dest = '\0';
}
eg5. 運用指針將 src 前 n 個字符連接到 dest 的后面去
void Strncat(char *dest, const char *src, int n)
{while(*dest){++dest;}while(*src && n--){*dest++ = *src++;}*dest = 0;
}
eg6. 運用指針只比較 s1 與 s2 的前 n 個字節的大小(可用于查找子串)
int Strncmp(const char *s1, const char *s2, int n)
{while(--n && *s1 == *s2 && *s1 && *s2)// --n{++s1;++s2;}return *s1 - *s2;
}
上述函數在主函數中的運行格式:
int main(void)
{char s1[100] = "Hello ";char s2[100] = "Herld!";Strcpy(s2, s1);Strcat(s1,s2);//Strcat(s1, "World");Strncpy(s1, s2, 2);Strncat(s1, s2, 2);//puts(s1);int t = Strncmp(s1, s2, 2);printf("%d\n", t);return 0;
}
二、萬能指針(空指針)
? ? ? ? 萬能指針可以用來接收任何數據類型的指針,當多個函數的運行程序段一致,但函數形參類型不一致時,可用萬能指針結合強制類型轉換符進行合并。
????????例如,只將?src 空指針型數組中的前 n 個數據拷貝到 dest 空指針型數組中去(適用于任何數據類型的拷貝)
//萬能指針
void Memcpy(void *dest, const void *src, int n)
{char *q = (char *)dest;char *p = (char *)src;while(n--){*q++ = *p++;}
}
int main(void)
{short a[10] = {1,2,3,4,5,6,7,8,9,0};short b[10];int len = sizeof(a) / sizeof(*a);Memcpy(b, a, sizeof(a));int i;for(i = 0; i < len; ++i){printf("%d\n", b[i]);}return 0;
}
三、查找子串
? ? ? ? 運用?Strncmp 函數查找 sub 在 s?中首次出現的位置
int subString(const char *s, const char *sub)
{int i;//printf("%d\n",strlen(s));for(i = 0; i <= strlen(s) - strlen(sub); ++i){if(strncmp(s + i, sub, strlen(sub)) == 0){break;} }if(i > strlen(s) - strlen(sub)){return 0;}else{return i;}
}
int main(void)
{char *sub = "hand";char *s = "He is handsome";int ret = subString(s, sub);if(ret != 0){printf("found\n");printf("在s[%d]\n", subString(s, sub));}else{printf("not found\n");}return 0;
}
四、一維數組指針
? ? ? ? 一維數組指針也稱為指向一維數組元素的指針,本質是一個指針變量。
????????一般形式:數據類型 (*標識符)[一維數組長度]
例如:int (*p)[10]:長度為10的一維整型數組,對指針 p 加?n 表示: 偏移 n*sizeof(基類型) 個字節。
五、二維數組指針
? ? ? ?1、概念
???????? 二維數組指針也稱為指向二維數組的指針或數組指針,其作為函數參數傳遞的媒介,形參是指向一維數組的指針,是一種特殊的指針類型,用于指向二維數組的整體或其行、元素,實現靈活的數組訪問和傳遞。
? ? ? ? (1) 指向二維數組的行(以下皆用 p 當作二維數組 a[][4] 的指針)
? ? ? ? ? ? ? ? int (*p)[4]=a? <=等價于=> a[0]
? ? ? ? (2) 指向二位數組的 i 行 j 列
? ? ? ? ? ? ? ? *(*( a+ i) + j)? <=等價于=> a[i][j]
? ? ? ? ? ? ? ? 例如:*(*(a + 1) + 1)? <=表示=> 二維數組中 a[1][1] 的值
? ? ? ? 2、二維數組指針的輸出
void printArray2D(int (*a)[4], int rows)
{int i, j;int cols = sizeof(*a) / sizeof(**a);for(i = 0; i < rows; ++i){for(j = 0; j < cols; ++j){printf("%2d ", *(*(a+i)+j));}puts("");}
}
? ? ? ? 3、二維數組指針的求和
int sumArray2D(int (*a)[4], int rows)
{int i, j;int sum = 0;int cols = sizeof(*a) / sizeof(**a);for(i = 0; i < rows; ++i){for(j = 0; j < cols; ++j){sum += *(*(a + i) + j);}}return sum;
}
????????4、二維數組指針的水平鏡像
//a與b的交換
void swap(int *a, int *b)
{int t;t = *a;*a = *b;*b = t;
}
//一維數組的逆序
void reverse(int *begin, int *end)
{while(begin < end){swap(begin++, end--);}
}
//二維數組的水平鏡像
void reverse2D(int (*a)[4], int rows)
{int i, j;int cols = sizeof(*a) / sizeof(**a);for(i = 0; i < rows; ++i){reverse(*(a + i), *(a + i) + (cols -1));}
}
上述函數在主函數中的使用格式:
int main(void)
{int a[][4] = {1,2,3,4,5,6,7,8,9,10,11,12};int rows = sizeof(a) / sizeof(*a);int t = sumArray2D(a, rows);printArray2D(a, rows);//printf("%d\n", t);reverse2D(a, rows);printArray2D(a, rows);return 0;
}
可以運用強制類型轉換符改變指針輸出類型,例如:
? ? ? ? printf("%d\n", *( (int *)(p + 3) - 5) ),對于三行四列的二維數組a[3][4],該輸出指向 a[1][3] 中的值。
六、返回指針值的函數
? ? ? ? 一般定義形式:類型名 *函數名(參數列表)
? ? ? ? 返回指針值的函數稱為指針函數。一個函數可以返回一個整型值、字符值、實型值等,也可以返回指針型的數據,即地址。可應用到多種函數的創建中去,例如字符型數組的拷貝(eg1. )、字符型數組的剪切(eg2.)。
eg1. 將 src 字符串的內容拷貝到 dest 字符串中去,要求函數須有返回值,并在輸出時直接打印出結果
char *Strcpy(char *dest, const char *src)
{char *ret = dest;while(*src){*dest++ = *src++;}*dest = '\0';return ret;
}
eg2. 將 src 字符串的內容粘貼到 dest 字符串的后面,要求函數須有返回值,并且輸出時直接打印出結果
char *Strcat(char *dest, const char *src)
{char *ret = dest;while(*dest){++dest;}while(*src){*dest = *src;++dest;++src;}return ret;
}
以上函數在主函數中的運行的書寫格式?
該類函數不能返回局部變量的值,例如:
static int i; |
return &i; |
*foo(&i) = 100; // * 為取地址 |
需要在變量 i 前加上 static ,讓其存儲與靜態區(全局區)。
七、關鍵字 const
? ? ? ? 在指針前加 const 表示無法通過該指針去修改它所指向的變量,但指針本身可以指向其他地址。可以提高代碼可讀性和函數的傳參效率。常用于不能修改的字符指針前。例如:
int a = 10;
int b = 20;
const int *p = &a;
若執行" *p = 20 ",會編譯錯誤,不能通過 p 修改所指向的值;
若執行“ p = &b?”,可以執行,指針 p 可以指向其他地址。