C语言11-指针

---恢复内容开始---

1.直接引用

在C语言中通过变量名引用变量,然后由系统自动完成变量名和其地址之间的转换称为变量的直接引用

说白了,C语言中变量对应的是一个存储数据空间的地址,在向这个变量赋值的时候,系统会自动完成变量和地址之间的转换,将数据存入到指定地址的数据存储空间

char a;
a = 'a';        //这就是直接引用,变量a对应着一个地址,在向a这个变量赋值的时候,系统会自动完成变量a和其对应地址的转换,然后将数据'a'存入到对应地址的数据          //存储空间

2.间接引用 (指针)

在C语言允许变量存储其它变量的地址,从而通过这个特殊的变量来操作其它变量,这个就是间接引用,这个能存储其它变量地址的变量就是指针

定义一个指针变量的格式:数据类型 *指针变量名 = 其它变量的地址

#include <stdio.h>

int main(int argc, const char * argv[])
{

    char a;
    char *b;        //定义一个指针变量,这里的前缀*表示b是一个指针变量,和普通变量区别开来
    b=&a;           //将变量a的地址存储到指针变量b中
    //char *b = &a; //上面两步可以写成一步
    *b='A';         //这里的前缀*表示访问指针变量b存储的地址的数据存储空间,这里表示将'A'存储到指针b存储的地址指定的数据存储空间,也就是变量a的数据存储空间
    printf("%c\n",a);
    printf("%c\n",*b);      //同样我们可以这样写
    
    return 0;
}

 

在使用指针的时候我们需要注意两点

第一点:指针是用于存储变量地址的,所以我们不能直接为其赋值,因为你赋予的值不一定是一个地址

第二点:在没有为指针变量指定地址时,系统会为这个指针随机指定一个地址,我们这个时候如果向这个指针赋值会引起数据安全问题,因为系统随机指定的地址

    中存储的数据有可能正在被使用,我们如果向这个地址赋值会导致这个数据改变,从而引起安全问题

#include <stdio.h>

int main(int argc, const char * argv[])
{

    int *a;
    a = 100;        //这样是错误的,因为指针变量是用来存储地址的,我们不能直接赋予值,因为我们赋予的值不一定是一个地址值,除非我们赋予的值是一个地址值
    *a = 100;       //这样也是错误的,因为在没有为指针变量指定一个地址之前系统会随机为这个指针变量指定一个地址,当我们向这个地址赋值的时候就会引起数据安全问题,因为当我们向
                    //这个地址赋值的时候说不定这个地址的数据正在被使用,我们赋值就会导致这个的数据被破坏,总之就是指针变量没有指定手动指定地址之前不能直接赋值
    return 0;
}

 

3.指针的应用

此处讲了两个例子

第一个例子:在一个函数中实现变量a和b的值互转

#include <stdio.h>

void swap(char *a,char *b)
{
    char temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

int main(int argc, const char * argv[])
{

    char a = 'A';
    char b = 'B';
    printf("a=%c,b=%c\n",a,b);
    swap(&a,&b);
    printf("a=%c,b=%c\n",a,b);
    return 0;
}

 

第二个例子:在一个函数中实现多个返回值

#include <stdio.h>

int sumAndMinuse(int v1,int v2,int *minuse)
{
    *minuse = v1-v2;
    return v1+v2;
    
}
int main(int argc, const char * argv[])
{

    int a = 8;
    int b = 6;
    int min;
    int sum = sumAndMinuse(a, b, &min);
    printf("a+b=%d\n",sum);
    printf("a-b=%d\n",min);

    return 0;
}

 

4.指针的类型和所占的字节数

指针所占字节数在不同的编译环境下是固定的,在16位编译环境下占2位,32位编译环境下占4位,64位编译环境下占8个位

指针的类型必须要和指定地址变量的类型相同否则会出错,原因是在你声明指针类型的时候指定了数据类型,那么这个指针变量就会从指定的地址开始扩展到数据类型所占字节数

例如下面这个例子

int main(int argc, const char * argv[])
{

    int a = 2;
    char b=1;
    //char b;
    int *c = &b;        //这里指针的类型为int,但是它保存的地址确实char b的地址,所以,它会从b这个地址开始扩展到int类型所占字节数,又由于a变量比b变量先定义,所以在内存中a占2个两个字节
                        //b占一个字节,由于*c类型为int所以它会从b这个字节到a字节的第一个字节,读取数据的时会从高位到低位
    //*c = 1;
    printf("%d\n",*c);      //这里一个字节8位,所以结果为:0000 0010 0000 0001,结果就是513
    return 0;
}

 

 这个练习有个问题,当我们先声明b变量,然后通过指针赋值为1时,打印的结果为1,为什么???

 

5.当函数的形参是数组或者指针 

当一个函数的形参是一个数组时,我们可以传入数组名,也可以传入指针,当一个函数的形参是一个指针时,我们可以传入数组名也可以传入指针,总而言之,当函数的形参是数组或者是指针时

我们传入的实参必须是一个地址,数组和指针的关系很密切,当一个函数的形参是指针时,我们可以把它当做数组使用

#include <stdio.h>

void change(char a[])       //当函数的形式参数是数组时,实参可以掺入数组或者指针,总而言之传入的是地址
{
    a[0]=10;
}
void method(char *a)        //当函数的形式参数是指针时,实参可以传入指针或者数组,总而言之传入的是地址
{
    *(a+1) =11;
    a[2] =12;               //这里同样可以把指针当做数组用,可见指针和数组之间的关系多么密切
}

int main(int argc, const char * argv[])
{
    char a[3];
    char *b = a;
    change(a);
    change(b);
    printf("%d\n",a[0]);
    
    method(a);
    method(b);
    printf("%d\n",a[1]);
    
      printf("%d\n",a[2]);
    return 0;
}

 

6.指针和字符串的关系 

前面我们知道字符串其实就是字符数组加一个结束标记\0,既然指针和数组之间的关系密切,那么指针和字符串之间的关系也会密切的

这里我们通过便利一个字符串来说明指针和字符串的关系

#include <stdio.h>
#include <string.h>

void foreach1(char arr[])
{
    int i;
    for (i=0; i<strlen(arr); i++) {
        printf("a[%d]=%c\n",i,arr[i]);
    }
}
void foreach2(char arr[])
{
    int i;
    for (i=0; arr[i]!='\0'; i++) {      //通过便利的字符不等于结束表示\0为条件
        printf("a[%d]=%c\n",i,arr[i]);
    }
}
void foreach3(char arr[])
{
    char *p = arr;                      //注意这里的指针指向的是字符串名arr变量,注意是字符串变量,对于字符串变量中的每个字符都可以改变
    int i;
    for (i=0; *(p+i)!='\0'; i++) {      //通过指针增加,并判断便利到的字符不等于字符串结束表示\0为条件
        printf("a[%d]=%c\n",i,arr[i]);
    }
}
void foreach4()
{
    char *p = "itcast";                 //注意这里的指针指向的是字符串常量的第一个字符的地址,注意是字符串常量,所以我们不能改变常量中的任何值
    for (; *p!='\0'; p++) {             //这种方式也是通过指针来便利字符串的
        printf("%c\n",*p);
    }
}
int main(int argc, const char * argv[])
{
    char a[] = "itcast";
    foreach1(a);
    foreach2(a);
    foreach3(a);
    foreach4();
    return 0;
}

 

 便利字符串就由上面四种方式,但是我们第四种是最简单的这里我们还引入一个问题,当指针变量被赋予一个字符串变量和被赋予一个字符串常量的区别

当指针变量被赋予一个字符串变量的时候,我们可以更改字符串变量中的每个字符,而当指针变量被赋予一个字符串常量时我们就不能改变字符串常量中的任何字符

#include <stdio.h>

int main(int argc, const char * argv[])
{
    char a[] = "itcast";
    char *p = a;            //指针被赋予一个字符串变量,所以我们可以改变字符串中的字符
    *(p+1) = 'T';
    printf("%s\n",a);
    
    char *b = "ios";        //指针被赋予一个字符串常量第一个地址,由于是字符串常量,所以我们不能改变字符串常量中的任何字符
    //*b = 'I';             //虽然语法是正确的,但是却是错误的
    //printf("%c\n",*b);
    return 0;
}

 7.返回指针的函数以及指向函数的指针

C语言中的函数的返回值可以是指针数据类型,下面我们举一个例子,这个例子是讲小写字符串转换成大写字符串

返回指针函数的格式:数据类型 * 函数名(参数1,参数2,...)

#include <stdio.h>

char * upstr(char *arr)
{
    //先通过一个指针变量记住传进来的指针的地址,因为在后面我们会改变arr的地址以及地址中的值
    char *point = arr;
    while (*arr!='\0') {
        //我这个函数的作用就是将小写字符串转换成大写字符串,所以我这里必须保证转换的是小写字符串,所以我这里要判断
        if (*arr>='a' && *arr<='z') {
            //小写字符减去32就是大写字符,这里用'a'-'A',也就是97-65=32,这样就讲小写字符改变成了大写字符
            *arr -= 'a'-'A';
        }
        //地址加一,继续转换下一个地址的字符,知道字符为字符串结束标记\0为止
        arr++;
    }
    return point;
}

int main(int argc, const char * argv[])
{
    char str[] = "ios";
    //这里我们打印的时一个字符串,它会从返回的指针地址开始打印字符,直到遇到\0结束标记
    printf("%s\n",upstr(str));
    return 0;
}

 

在C语言中函数也会占有一片内存,函数的地址就是函数名,那么我们也可以通过指针来保存函数地址

首先是申明一个函数指针:指针数据类型 (*指针名)(参数类型1,参数类型2,...),这里说的不明白,其实就是将函数名改成(*指针名),而参数只保留参数类型或者可以直接省略参数类型

函数指针的初始化:指针名=函数名 或者 指针数据类型 (*指针名)(参数类型1,参数类型2,...)=函数名

函数指针的调用:*指针名(实参1,实参2,...) 或者省略*

函数指针的最大用处就是可以将函数指针作为参数在其它函数中传递,比如下面这个例子 

#include <stdio.h>

int add(int v1,int v2)
{
    return v1+v2;
}
int minus(int v1,int v2)
{
    return v1-v2;
}
int multip(int v1,int v2)
{
    return v1*v2;
}
int calculate(int v1,int v2, int (*p)(int,int))    //函数指针作为参数在其它参数中传递
{
    //return (*p)(v1,v2);       //调用函数指针的时候可以用(*指针名)(实参1,实参2,...),当然也可以省略*
    return p(v1,v2);
}
int main(int argc, const char * argv[])
{
    int a = 6;
    int b = 8;
    int c = calculate(a, b, multip);            //当我这里改变函数指针的地址就可以改变各种算法
    printf("%d\n",c);
    return 0;
}

 

 

总结:本节课主要讲解了7点,这节课比较多,需要注意

  1.C语言中的直接引用就是由变量名引用变量,然后由系统自动在变量名和地址之间转换

  2.C语言中的间接引用就是将变量的地址存储到指针变量中,然后通过指针变量去操作变量,这里引入了指针

    指针的申明:数据类型 *指针名;

    指针的初始化: 指针名 = 变量地址 或者 数据类型 *指针名 = 变量地址

    访问指针地址指向的存储空间的格式: *指针名

    为指针地址所指向的存储空间保存数据: *指针名 = 对应类型数据

    使用指针的两点注意实现,

      第一:指针变量只能保存变量地址,所以我们不能直接给它赋值,因为我们赋予的值不一定是一个地址

      第二:指针变量在没有指定变量地址之前我们不能直接为指针的存储空间存数据,因为在没有为指针变量指定地址之前系统会为其随机指定一个地址,我们如果这个时候改变这个地址中         的数据容易导致数据安全问题,因为这个地址的数据可能正在被使用,如果我们随便更改数据就会破坏这个地址中的数据

  3.指针的两个例子,第一个例子是在函数中交换两个变量的值,第二个例子在一个函数中实现多个返回值

  4.指针所占字节数和指针数据类型:在不同的编译环境下不同指针所占字节数不同,16位编译环境占2位,32位环境占4位,64位环境占8位,指针的数据类型是确保指针变量从指定地址开始扩展   对应数据类型字节

  5.当函数的形参是数组或者是指针时,我们在调用函数的时候传入的实参可以是数组也可以指针,并且当函数的形参是指针的时候,我们可以把指针当做数组使用,这说明了函数和指针关系密切

  6.指针和字符串的关系,C语言中字符串就是字符数组加结尾标记\0,既然指针和数组关系密切,那么指针和字符串的关系也密切,我们这里通过遍历字符串的四种方式来说明指针和字符串之间的     关系,特别值得说明的是最后一种方式通过指针自增,并且以指针地址所存储的数据不为\0为条件来遍历出字符串,然后另一个问题就是当指针变量被赋予字符串变量和字符串常量的区别,如   果是字符串变量,我们则可以改变字符串变量中的字符,如果是字符串常量,则我们不能改变字符串常量中的字符

  7.返回指针的函数,以及指向函数的指针,返回指针的函数通过将小写字符串转换成大写字符串的例子来说明的,实际上返回指针的函数其实返回的时一个地址值,然后指向函数的指针可以作为   其他函数的参数传递,比如这里在函数中通过传递不同的函数指针实现不同的算法,得到不同的结果

 

——————————————————————————————————————————————————————————————————————————————————————— 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2014-02-26 01:37  ysfox  阅读(167)  评论(0)    收藏  举报