C语言程序设计---8:指针

指针

一个变量的地址称为该变量的“指针”。

#include<stdio.h>
void main()
{
    int a,b;
    int *pointer_1,*pointer_2;
    a=100;
    b=900;
    pointer_1=&a;
    pointer_2=&b;
    printf("a=%d,b=%d\n",a,b);
    printf("*pointer_1=%d,*pointer_2=%d\n",*pointer_1,*pointer_2);
}
  • 指针变量前面的“*”表示该变量的类型为指针型变量。
    • 可以这样理解: “int *pointer_1,*pointer_2;”定义了*pointer_1和*pointer_2是整型变量,如同“int a,b;”定义了a和b是整型变量一样。而*pointer_1*pointer_2pointer_1pointer_2所指向的变量,pointer_1pointer_2是指针变量。
  • 最后一个语句中的*pointer_1*pointer_2就是a和b。
  • 赋给指针变量的只能是变量地址,而不能是任意类型的数据,而且只能是与指针变量的基类型相同类型的变量地址。
  • 指针变量中只能存放地址(指针),不要将一个整数赋给一个指针变量。
    • *pointer_1 = 100;是错误的。

指针变量作为函数参数

函数的参数不仅可以是整型、浮点型、字符型等数据,还可以是指针类型,它的作用是将一个变量的地址传送到另一个函数中。

#include<stdio.h>
void main()
{
    void swap(int *p_1,int *p_2);
    void swap1(int *p_1,int *p_2);
    int a,b;
    int *p_1,*p_2;
    scanf("%d,%d",&a,&b);
    p_1=&a;
    p_2=&b;
    if(a<b) swap1(p_1,p_2);
    printf("a=%d,b=%d\n",a,b);
}
void swap(int *p_1,int *p_2)
{
    int temp;
    /*改变的是指向,而不是值*/
    temp = *p_1;
    *p_1 = *p_2;
    *p_2 =temp;
}
void swap1(int *p_1,int *p_2)
{
    int *temp;
    /*temp无确定的值,会报错*/
    *temp = *p_1;
    *p_1 = *p_2;
    *p_2 = *temp;
}
void swap2(int x,int y)
{
    int temp;
    temp = x;
    x = y;
    y = temp;
}
void swap3(int *p_1,int *p_2)
{
    int *p;
    p= p1;
    p1= p2;
    p2= p
}

swap1中,由于未给temp赋值,因此temp中并无确定的值(它的值是不可预见的),所以temp所指向的单元也是不可预见的。对*temp赋值就是向一个未知的存储单元赋值,而这个未知的存储单元中可能存储着一个有用的数据,这样就有肯能破坏系统的正常工作状况,应该讲*p_1的值赋给与*p_1相同类型的变量。

  • swap传递的是两个地址,然后改变两个地址指向的值,所以有效
  • swap2传递的是值,然后复制,接着互换,但原来的值和原来的指向均没有改变,所以无效
  • swap3传递的是两个地址,然后互换地址值,但原来的地址值仍然没有改变,所以仍然无效
  • C语言中实参变量和形参变量之间的数据传递是单项的“值传递”方式,用指针变量作函数参数一样的。
  • 不要试图去改变值,去改变指向
/*输入三个整数,从小到大排序*/
#include<stdio.h>
void main()
{
    void exchage(int *p1,int *p2,int *p3);
    int a,b,c,*p1,*p2,*p3;
    p1 = &a;
    p2 = &b;
    p3 = &c;
    scanf("%d,%d,%d",&a,&b,&c);
    exchage(p1,p2,p3);
    printf("*p1=%d,*p2=%d,*p3=%d\n",*p1,*p2,*p3);
}
void exchage(int *p1,int *p2,int *p3)
{
    void swap(int *p1,int *p2);
    if(*p1>*p2) swap(p1,p2);
    if(*p1>*p3) swap(p1,p3);
    if(*p2>*p3) swap(p2,p3);


}
void swap(int *p1,int *p2)
{
    int temp;
    if(*p1>*p2)
    {
        temp = *p1;
        *p1 = *p2;
        *p2 = temp;
    }
}

通过指针引用数组

#include<stdio.h>
void main()
{
    int a[10] = {12,15,12,14,18,75,14,12,22,36};
    int *p;
    p = a;      /*a代表数组首元素的地址*/
    p = &a[0];
    for(int i=0;i<10;i++)
    {
        printf("%d\t",a[i]);
    }
    printf("\n");

    for(i=0;i<10;i++)
    {
        printf("%d\t",*(a+i));
    }
    printf("\n");

    for(i=0;i<10;i++)
    {
        printf("%d\t",*(p+i));
    }
    printf("\n");

    for(p;p<a+10;p++)
    {
        printf("%d\t",*p);
    }
    printf("\n");

}

引用一个数组元素,可以:

  • 下标法,a[i]
  • 指针法,即地址法。

    • 由于数组名代表数组首元素的地址,因此可以通过数组名计算出数组中序号为i的元素的地址,其形式为*(a+i)
    • 用一个指针变量p指向数组首元素,然后用*(p+i)调用a数组中序号为i的元素。
  • 如果指针变量p已经指向数组中的元素,则p+1指向同一数组中的下一个元素。如果数组元素是float型,每个元素占4个字节,则p+1所代表的实际地址是p+1*d,的一个数组元素所占的字节数,若p的值是2000,则p+1的值不是2001,而是2004.

  • 如果指针变量p的初值为&a[0],则p+i和a+i就是数组元素a[i]的地址,或者说,它们指向a数组的第i个元素。
  • *(p+i)*(a+i)是p+i或a+i所指向的数组元素,即a[i]。例如,*(p+5)*(a+5)就是a[5]。也就是说*(p+5)*(a+5)a[5]三者等价。实际上,在编译时,对数组元素a[i]就是按*(a+i)处理的,即按数组首元素的地址加上相对位移量得到要找的元素的地址,然后找出该单元的内容。
  • []实际上是变址运算符,即将a[i]按a+i计算地址,然后找出此单元中的值。
  • p2-p1 是两个地址之差除以数组元素的长度。

  • 如果在程序中引用数组元素a[10],虽然并不存在这个元素(最后一个元素是a[9]),但C编译程序并不认为此为非法。系统把它按*(a+10)处理,即先找出(a+10)的值(是一个地址),然后找出它指向的单元的内容。

  • 在用数组做参数的方法中,实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素地址的。因此,形参应该是一个指针变量(只有指针变量才能存放地址)。实际上,C编译都是将形参数组名作为指针变量来处理的。
  • C语言调用函数时虚实结合的方法都是采用“值传递”方式,当用变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。

通过指针引用字符串

/*用指针操作-简单*/
#include<stdio.h>
void main()
{
    char *str = "I love China!";
    /*str保存字符串的第一个字符的地址*/
    int i = 0;
    printf("%s\n",str);
    /*
    正确
    char *str;
    str = "I love China!";
    错误
    char *str;
    *str = "I love China!";
    */
    for(i=0;str[i]!='\0';i++)
        printf("%c",str[i]);
    printf("\n");

    for(i=0;*(str+i)!='\0';i++)
        printf("%c",*(str+i));
    printf("\n");

    char a[] = "I am a boy.";
    /*错误    数组可以在定义时整体赋初值,但不能在赋值语句中整体赋值。
    char a[20];
    a[] = "I love China!";
    */
    printf("%s\n",&a[0]);
    printf("%s\n",a);
    for(i=0;*(a+i)!='\0';i++)
        printf("%c",*(a+i));
    printf("\n");
}
#include<stdio.h>
void main()
{
    char *a="I love China!";
    a = a+7;
    printf("%s\n",a);
    /*错误    数组名虽然代表地址,但它是常量,它的值是不能改变的。
    char str[]="I love China!";
    str = str+7;
    printf("%s\n",a);
    */
}

指针使用的技巧

#include<stdio.h>
void main()
{
    void copy_string(char *p1,char *p2);
    char *from="I am a teacher";
    char str[]="I am a student......";
    char *to=str;

    /*一:要保证to的长度要足够*/
    /*二:to要事先分配好内存单元*/
    copy_string(to,from);
    /*错误    长度不够
    copy_string(from,to);

      错误  没分配内存单元,只是一个起始地址
    char *to="I am a student......";
    */
    printf("%s\n",from);
    printf("%s\n",str);

}
void copy_string(char *to,char *from)
{
    for(;*from!='\0';to++,from++)
        *to = *from;
    *to ='\0';
}

用while代替for

void copy_string(char *to,char *from)
{
    while(*from!='\0')
    {
        *to = *from;
        to++,from++;
    }
    *to ='\0';
}

利用操作符的执行先后顺序

void copy_string(char *to,char *from)
{
    while(*from!='\0')
        *to++ = *from++;
    *to ='\0';
}

利用操作符的执行先后顺序

void copy_string(char *to,char *from)
{
    while((*to++ = *from++)!='\0');
}

'\0'的ASCII代码为0

void copy_string(char *to,char *from)
{
    while((*to++ = *from++)!=0);
}

非0即为tue

void copy_string(char *to,char *from)
{
    while(*to++ = *from++);
}

或者

void copy_string(char *to,char *from)
{
    for(;*to++ = *from++;);
}

多维数组的指针

    int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
  • a是一个二维数组名。由3个一维数组组成。
  • a代表二维数组首元素的地址,现在首元素是由4个整型元素所组成的一维数组。
  • a即a[0],a+1即a[1];
    int (*p)[4];
  • p是指针变量,指向有4个元素的一维数组,数组元素为整型,也就是p所指向的对象是有4个整型元素的数组。
#include<stdio.h>
void main()
{
    int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
    int (*p)[4];
    int *q;
    int i;
    /*这个也可以
    p = a;
    */
    p = &a[0];
    for(i=0;i<4;i++)
        printf("%d\t",*(*p+i));
    printf("\n");


    q = a[0];
    for(i=0;i<4;i++)
        printf("%d\t",*(q+i));
    printf("\n");
}

指向函数的指针

int (*p)(int,int);
  • 指针变量p,指向的函数类型为int型,函数有两个int类型的形参。
  • 如果要用指针调用函数,必须先使指针变量指向该函数:
    • p = max;
  • 用函数指针变量调用函数时,只需将(*p)代替函数名即可:
    • c = (*p)(a,b);

返回指针值的函数

int *method(int x,int y);

指针数组

    int * p[4];
  • p[4]显然是数组形式,它有4个元素。前面的“*”表示此数组是指针类型,每个数组元素(相当于一个指针变量)都可指向一个整型变量。

多重指针-指向指针的指针

定义含义
int i;定义整型变量i
int * p;p为指向整型数据的指针变量
int a[n]定义整型数组a,它有n个元素
int * p[n];定义指针数组p,它由n个指向整型数据的指针元素组成
int (*p)[n];p为指向含n个元素的一维数组的指针变量
in f();f为返回整型函数值的函数
int * p();p为返回一个指针的函数,该指针指向整型数据
int (*p)();p为指向函数的指针,该函数返回一个整型值
int * * p;p是一个指针变量,它指向一个指向整型数据的指针变量
void * p;p是一个指针变量,基类型为void(空类型),不指向具体的数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值