C语言学习与总结---第八章:指针[02]

指针[02]

  • 8.4 指针与数组
    • 8.4.1 指向数组元素的指针
    • 8.4.2 指针的算术运算
    • 8.4.3 通过指针访问数组元素
    • 8.4.5 数组名作为函数参数

8.4 指针与数组

8.4.1 指向数组元素的指针

int a[10];  //a为包含10个整型数据的数组  
int* p;     //p为指向整型变量的指针变量  
p = &a[0];  /*把a[0]元素的地址赋给指针变量p, 
             即让p指向a数组的第0号元素等价于p=a;*/  
/*也可以写作: 
    int* p = &a[0]; or 
    int* p = a;*/ 
 *p = 5;  //通过p访问a[0],将数值5存入a[0]

8.4.2 指针的算术运算

指针的算术运算有且仅有三种:
指针加上整数、指针减去整数、两个指针相减

(1)指针加上整数

int a[10], * p, * q, i;  
p = &a[2];  //p指向了a[2]  
q = p + 2;  //q指向了a[4]  
p += 3;     //p指向了a[5]

(2)指针减去整数

int a[10], * p, * q, i;  
p = &a[8];  //p指向了a[8]  
q = p - 2;  //q指向了a[6]  
p -= 3;     //p指向了a[5]  

(3)两个指针相减

int a[10], * p, * q, i, j;  
p = &a[5];  //p指向了a[5]  
q = &a[1];  //q指向了a[1]  
i = p - q;     //i=4  
j = q - p;     //j=-4  


如果p的初值为&a[0],则:

(1) p+i和a+i是a[i]的地址,即它们指向a[i]
(2) * (p+i )和 * (a+i)就是a[i]
(3) p[i]与*(p+i)等价
(4)指针可以用关系运算符和判等运算符进行比较:< <= >= >;== !=
比较的结果依赖于指针指向的元素的相对位置,例如

int a[10], * p, * q, i, j;  
p = &a[5];  //p指向了a[5]  
q = &a[1];  //q指向了a[1]  
p <= q;     //值为0  
p > q;     //值为1  

(5)指针的算术运算只有当指针指向数据元素时,才有意义,对未指向数组元素的指针执行算术运算、或者对两个并非指向同一数组的指针做减法、做比较,都将导致未定义行为!

8.4.3 通过指针访问数组元素

访问数组元素通常有两种方法:
(1)下标法:a[2];
(2)指针法:

*(a+2)或*(p+2)

例如,输出数组中的全部元素。其中整型数组a有10个元素,输出各元素的方法有三种:
(1)下标法

#include  
int main()  
{  
    int a[10], i;  
    for (i = 0; i < 10; i++)  
        scanf("%d", &a[i]);  
    for (i = 0; i < 10; i++)   
        printf("%d\n", a[i]);  
    return 0;  
} 

(2)通过数组名计算数组元素地址

#include  
int main()  
{  
    int a[10], i;  
    for (i = 0; i < 10; i++)  
        scanf("%d", &a[i]);  
    for (i = 0; i < 10; i++)  
        printf("%d  ", *(a+i));  
    return 0;  
}

上述代码第8行也可以改为

printf("%d  ", *(p+i));

(3)用指针变量指向数组元素

#include   
int  main()  
{  
    int a[10], i, * p;  
    for (i = 0; i < 10; i++)  
        scanf("%d", &a[i]);  
    for (p = a; p < a + 10; p++)  
        printf("%d  ", *p);  
    return 0;  
}  

上述代码第6行可以改为

scanf("%d", p++);

分析:下面代码问题出在哪里?

#include  
int main()  
{  
    int i, a[10], * p = a;  
    for (i = 0; i < 10; i++)  
        scanf("%d", p++);  
    for (i = 0; i < 10; i++, p++)  
        printf("%d  ", *p);  
    return 0;  
}  

输出结果:
C语言学习与总结---第八章:指针[02]_第1张图片
回答:在数组输入部分结束后,指针*p的位置在a[10];所以后面输出部分p从a[11]位置开始输出,故出现问题。应如下改正:

#include  
int main()  
{  
    int i, a[10], * p = a;  
    for (i = 0; i < 10; i++)  
        scanf("%d", p++);  
    p = a;  
    for (i = 0; i < 10; i++, p++)  
        printf("%d  ", *p);  
    return 0;  
}  

*和++的几种组合(++的优先级高于*)
(1)*p++:*p++等价于*(p++);含义:自增前表达式的值为*p,然后自增p;
(2)*++p:*++p等价于*(++p);含义:先自增p,自增后表达式的值为*p;
(3)(*p)++:含义:自增前表达式的值为*p,然后自增*p;
(4)++(*p):含义:先自增*p,自增后表达式的值为*p;

区别:指针的自增 与 指针所指向的变量的自增

8.4.5 数组名作为函数参数

#include  
void f(int arr[], int n);  
int main()  
{  
    int array[15] = { 1,2,3,4,5 };  
    f(array, 2);  
    return 0;  
}  
void f(int arr[], int n)  
{  
    printf("%d\n", *arr);  
    arr += n;  
    printf("%d\n", *arr);  
} 

C编译系统将形参数组名作为指针变量来处理:

void f(int arr[], int n)

相当于

void f(int *arr, int n)  

例,数组反向输出。

#include  
void reverse(int x[], int n);  
int main()  
{  
    int i, a[10] = { 0,1,2,3,4,5,6,7,8,9 };  
    printf("数组顺序输出为:\n");  
    for (i = 0; i < 10; i++)  
        printf("%d, ", a[i]);  
    printf("\n");  
    reverse(a, 10);  
    printf("数组逆序输出为:\n");  
    for(i=0;i<10;i++)  
        printf("%d, ", a[i]);  
    printf("\n");  
    return 0;  
}  
void reverse(int x[], int n)  
{  
    int i, j, temp, m = (n - 1) / 2;  
    for (i = 0; i <= m; i++)  
    {  
        j = n - i - 1;  
        temp = x[i];  
        x[i] = x[j];  
        x[j] = temp;  
    }  
} 

上述reverse函数还可以改写为:

void reverse(int* x, int n)  
{  
    int* p, * i, * j, temp, m = (n - 1) / 2;  
    i = x;  
    j = x + n - 1;  
    p = x + m;  
    for (; i <= p; i++, j--)  
        temp = *i;  
        *i = *j;  
        *j = temp;  
} 

实参和形参的对应情况
(1)实参和形参都用数组名

void f(int x[], int n)  
{  
    ...  
}  
int main()  
{  
    int a[10];  
    ...  
    f(a, 10);  
}  

此时,数组a[i]对应x[i];

(2)实参用数组名,形参用指针变量

void f(int *x, int n)  
{  
    ...  
}  
int main()  
{  
    int a[10];  
    ...  
    f(a, 10);  
}

此时,指针x指向a[0];

(3)实参和形参都用指针变量

void f(int *x, int n)  
{  
    ...  
}  
int main()  
{  
    int a[10], * p = a;  
    ...  
    f(p, 10);  
}

此时,指针p,x指向a[0];

(4)实参用指针,形参用数组名

void f(int x[], int n)  
{  
    ...  
}  
int main()  
{  
    int a[10], * p = a;  
    ...  
    f(p, 10);  
}

此时,指针p指向a[0],x[0];

例,用选择法对10个整数按由大到小顺序排序

#include  
void sort(int x[],int n);  
int main()  
{  
    int i, * p, a[10];  
    p = a;  
    for (i = 0; i < 10; i++)  
        scanf("%d", p++);  
    p = a;  
    sort(p, 10);  
    for (p=a,i = 0; i < 10; i++, p++)  
        printf("%d, ", *p);  
    printf("\n");  
    return 0;  
}  
void sort(int x[], int n)  
{  
    int i, j, k, t;  
    for (i = 0; i < n - 1; i++)  
    {  
        k = i;  
        for (j = i + 1; j < n; j++)  
            if (x[j] < x[k]) k = j;  
         t = x[i];  
         x[i] = x[k];  
         x[k] = t;  
    }  
} 

也可以用指针作形参:

void sort(int* x, int n)  
{  
    int i, j, k, t;  
    for (i = 0; i < n - 1; i++)  
    {  
        k = i;  
        for (j = i + 1; j < n; j++)  
            if (*(x + j) > * (x + k)) k = j;  
        t = *(x + i);  
        *(x + i) = *(x + k);  
        *(x + k) = t;  
    }  
}

8.5 指针与多维数组
设a是多维数组,则

a + i、&a[i] 第i行的首地址
a[i]、*(a + i) 第i行第0列元素的地址
* (a[i] + j)、* (*(a + i) + j) a[i][j]的值
表示形式 含义 地址
a 二维数组名,即0行首地址 2000
a[0],*(a+0),*a 0行0列元素a[0][0]的地址 2000
a+1,&a[1] 1行首地址 2016
a[1],*(a+1) 1行0列元素a[1][0]的地址 2016
a[1]+2, *(a+1)+2, &a[1][2] 1行2列元素a[1][2]的地址 2024
* (a[1]+2), * (*(a+1)+2), a[1][2] 1行2列元素a[1][2]的值 元素值为13

再看如下程序:

#include  
int main()  
{  
    int a[3][4] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 };  
    int* p;  
    for (p = a[0]; p < a[0] + 12; p++)  
    {  
        if ((p - a[0]) % 4 == 0)  
            printf("\n");  
        printf("%4d", *p);  
    }  
    return 0;  
} 

指针p不是指向一个变量,而是指向一个包含m个元素的一维 数组。如果p先指向a[0](即p = &a[0]),则p+1指向a[1],p的增值是以一维数组的长度为单位。

用指向数组的指针作函数参数:
例,有一个班,3个学生,各学4门课,计算总平均分数及第n个学生的成绩。要求:
(1)用函数average求总平均成绩
(2)用函数search找出并输出第n个学生的成绩

#include  
void average(float* p, int n);  
void search(float(*p)[4], int n);  
int main()  
{  
    float score[3][4] = { {65,67,70,60},{80,87,90,81},{90,99,100,98} };  
    average(*score, 12);  
    search(score, 2);  
    return 0;  
}  
void average(float* p, int n)  
{  
    float* p1;  
    float sum = 0, aver;  
    p1 = p + n - 1;  
    for (; p <= p1; p++)  
        sum += *p;  
    aver = sum / 12;  
    printf("average=%5.2f\n", aver);  
}  
void search(float(*p)[4], int n)  
{  
    int i;  
    printf("The score of No .%d are:\n", n);  
    for (i = 0; i < 4; i++)  
        printf("%5.2f, ", *(*(p + n) + i));  
} 

例,在上题基础上,查找有一门以上课程不及格的学生,输出其全部课程的成绩。

#include  
void search(float(*p)[4], int n);  
int main()  
{  
    float score[3][4] = { {65,57,70,60},{80,87,90,81},{90,99,100,98} };  
    search(score, 3);  
    return 0;  
}  
void search(float(*p)[4], int n)  
{  
    int i, j, flag;  
    for (j = 0; j < n; j++)  
    {  
        flag = 0;  
        for (i = 0; i < 4; i++)  
        {  
            if (*(*(p + j) + i) < 60) flag = 1;  
            if (flag == 1)  
            {  
                printf("No.%d is fails, his scores are :\n", j+1);  
                for (i = 0; i < 4; i++)  
                {  
                    printf("%5.1f ", *(*(p + j) + i));  
                }  
                printf("\n");  
            }  
                  
              
        }  
    }  
}  

你可能感兴趣的:(C语言,指针)