指針: 用來存放變數地址的變數,就成為"指針變數". 定義: 一般形式:類名標識符 指針變數名; " "是說明符,用來說明這個變數是個指針變數,是不能省略的,但不屬於變數名的一部分 前面的類型標誌符表示指針變數所只想的變數的類型,而且只能指向這種類型的變數 示例1:值交換 示例2:函數多個返回值 示 ...
- 指針: 用來存放變數地址的變數,就成為"指針變數".
定義: 一般形式:類名標識符 *指針變數名;
int *p; float *q;
- "*"是說明符,用來說明這個變數是個指針變數,是不能省略的,但不屬於變數名的一部分
前面的類型標誌符表示指針變數所只想的變數的類型,而且只能指向這種類型的變數
示例1:值交換
```c
void swap(char v1, char v2) {
// 中間變數
char temp;
// 取出v1指向的變數的值
temp = *v1;
// 取出v2指向的變數的值,然後賦值給v1指向的變數
*v1 = *v2;
// 賦值給v2指向的變數
*v2 = temp;
}
int main()
{
char a = 10, b = 9;
printf("更換前:a=%d, b=%d\n", a, b);
swap(&a, &b);
printf("更換後:a=%d, b=%d", a, b);
return 0;
}
```
示例2:函數多個返回值
```c
// 計算2個整型的和與差
int sumAndMinus(int v1, int v2, int minus) {
// 計算差,並賦值給指針指向的變數
minus = v1 - v2;
// 計算和,並返回和
return v1 + v2;
}
int main()
{
// 定義2個int型變數
int a = 6, b = 2;
// 定義2個變數來分別接收和與差
int sum, minus;
// 調用函數
sum = sumAndMinus(a, b, &minus);
// 列印和
printf("%d+%d=%d\n", a, b, sum);
// 列印差
printf("%d-%d=%d\n", a, b, minus);
return 0;
}
```
示例3:用指針遍歷字元串
// 定義一個指針p
char *p;
// 定義一個數組s存放字元串
char s[] = "mj";
// 指針p指向字元串的首字元'm'
p = s; // 或者 p = &s[0];
for (; *p != '\0'; p++) {
printf("%c \n", *p);
}
指針也是C語言中的一種數據類型,因此一個函數的返回值肯定可以是指針類型的。
返回指針的函數的一般形式為:類型名 * 函數名(參數列表)
示例4:比如下麵這個函數,返回一個指向char類型變數的指針
```c
// 將字元串str中的小寫字母變成大寫字母,並返回改變後的字元串
// 註意的是:這裡的參數要傳字元串變數,不能傳字元串常量
char * upper(char str) {
// 先保留最初的地址。因為等會str指向的位置會變來變去的。
char dest = str;
// 如果還不是空字元
while (*str != '\0') {
// 如果是小寫字母
if (*str >= 'a' && *str <= 'z') {
// 變為大寫字母。小寫和大寫字母的ASCII值有個固定的差值
*str -= 'a' - 'A';
}
// 遍歷下一個字元
str++;
}
// 返回字元串
return dest;
}
```
指向函數的指針函數作為一段程式,在記憶體中也要占據部分存儲空間,它也有一個起始地址,即函數的入口地址。函數有自己的地址,那就好辦了,我們的指針變數就是用來存儲地址的。因此,可以利用一個指針指向一個函數。其中,函數名就代表著函數的地址。
定義的一般形式:函數的返回值類型 (*指針變數名)(形式參數1, 形式參數2, ...);
#include <stdio.h>
int sum(int a, int b) {
return a + b;
}
int main()
{
// 定義一個指針變數p,指向sum函數
int (*p)(int a, int b) = sum;
// 或者 int (*p)(int, int) = sum;
// 或者 int (*p)() = sum;
// 利用指針變數p調用函數
int result = (*p)(1, 3);
// 或者 int result = p(1, 3);
printf("%d", result);
return 0;
}
指向指針的函數註意
1> 由於這類指針變數存儲的是一個函數的入口地址,所以對它們作加減運算(比如p++)是無意義的。難道p++就會指向下一個函數了?可笑至極!!沒這回事。
2> 返回指針的函數的定義char upper(char str) 和 指向函數的指針的定義int ( *p)(int a, int b)非常相似,使用時特別註意區分
3> 指向函數的指針變數主要有兩個用途:
調用函數
將函數作為參數在函數間傳遞。我這麼一說,可能還不是很明白,舉個例子。
#include <stdio.h>
// 減法運算
int minus(int a, int b) {
return a - b;
}
// 加法運算
int sum(int a, int b) {
return a + b;
}
// 這個counting函數是用來做a和b之間的計算,至於做加法還是減法運算,由函數的第1個參數決定
void counting( int (*p)(int, int) , int a, int b) {
int result = p(a, b);
printf("計算結果為:%d\n", result);
}
int main()
{
// 進行加法運算
counting(sum, 6, 4);
// 進行減法運算
counting(minus, 6, 4);
return 0;
}
每個結構體變數都有自己的存儲空間和地址,因此指針也可以指向結構體變數
結構體指針變數的定義形式:struct 結構體名稱 *指針變數名
有了指向結構體的指針,那麼就有3種訪問結構體成員的方式
結構體變數名.成員名
(*指針變數名).成員名
指針變數名->成員名
#include <stdio.h>
int main(int argc, const char * argv[]) {
// 定義一個結構體類型
struct Student {
char *name;
int age;
};
// 定義一個結構體變數
struct Student stu = {"MJ", 27};
// 定義一個指向結構體的指針變數
struct Student *p;
// 指向結構體變數stu
p = &stu;
/*
這時候可以用3種方式訪問結構體的成員
*/
// 方式1:結構體變數名.成員名
printf("name=%s, age = %d \n", stu.name, stu.age);
// 方式2:(*指針變數名).成員名
printf("name=%s, age = %d \n", (*p).name, (*p).age);
// 方式3:指針變數名->成員名
printf("name=%s, age = %d \n", p->name, p->age);
return 0;
}