美文网首页
指针和数组

指针和数组

作者: 漫游之光 | 来源:发表于2018-09-15 20:30 被阅读0次

    指针和地址

    一元运算符&可用于取一个对象的地址,因此,下列语句:

    p = &c;
    

    将把c的地址赋值给变量p,我们称p为“指向”c的指针。地址运算符&只能应用于内存中的对象,即变量与数组元素。它不能作用于表达式,常量或register类型的变量。
    一元运算符*是间接寻址或间接引用运算符。当它作用于指针时,将访问指针所指向的对象。下面是一个简单的例子。

    int x = 1,y = 2, z[10];
    int *ip; /* ip是指向int类型的指针 */
    ip = &x; /* ip指向x */
    y = *ip; /* y的值为ip指向的值,即x的值 */
    *ip = 0; /* x的值为0 */
    ip = &z[0]; /* ip指向z[0] */
    

    指针都必须指向某种特定类型的数据。void类型的指针可以存放指向任何类型的指针,但它不能间接引用其自身。

    指针与函数参数

    由于C语言是以传值得方式将参数值传递给被调用函数,因此,被调用函数不能直接修改主调函数中变量了值。如果,需要修改变量中的值,可以变量的指针传递给调用函数。如:

    void swap(int *px,int *py){
        int temp;
        temp = *px;
        *px = *py;
        *py = temp;
    }
    

    指针与数组
    在C语言中,指针和数组之间的关系十分密切,通过数组下标所能完成的任何操作都可以通过指针来实现。下面是一个例子:

    int array[] = {1,2,3,4,5,6,7,8,9,10};
    int *pa;
    pa = array; /* 等价于pa = &array[0] */
    printf("%d\n",*(pa+4)); /* 等价于p[4] */
    

    当把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址。在函数定义中,形式参数

    int arr[];
    

    int *arr;
    

    是等价的。通常更习惯于使用后面一种形式,因为它比前者更加直观地表明了该参数是一个指针。

    地址算术运算

    指针和指针的比较:如果指针p和q指向同一数组的成员,那么它们之间就可以进行类似于==,!=,<,>=的关系比较运算。
    指针和整数的加减:

    p + n
    

    表示指针p当前指向对象之后第n个对象的地址。在计算p+n时,n将根据P指向的对象的长度按比例缩放,而p指向的对象的长度取决于p的声明。
    指针和NULL:指针可以赋值为NULL(0),或和NULL进行比较运算。

    字符指针和函数

    字符串常量是一个字符数组,例如:

    "I am a string"
    

    在字符串得内部表示中,字符数组以空字符'\0'结尾,所以,程序可以通过检查空字符找到字符数组的结尾。字符串常量占据的存储单元数也因此比双引号内的字符数大1。
    下面两个定义之间的定义有很大的差别:

    char amessage[] = "hello world";
    char *pmessage = "hello world";
    

    上述声明中,amessage是一个仅仅足以存放初始化字符串以及空字符'\0'的一维数组。数组中的单个字符可以进行修改,但amessage始终指向同一存储位置。另一方面,pmessage是一个指针,其初值指向一个字符串常量,之后它可以修改以指向其他地址,但如果试图修改字符串得内容,结果是没有定义的(通常会触发段错误)。下面是两个关于字符数组作为参数的例子:

    void strcpy(char *s,char *t){
        /* 没有考虑到s的空间不够的情况 */
        while(*s++ = *t++)
            ;
    }
    
    int strcmp(char *s,char *t){
        /* 这里的写法很值得学习 */
        for(;*s == *t;s++,t++){
            if(*s == '\0'){
                return 0;
            }
        }
        return *s - *t;
    }
    

    指针数组以及指向指针的指针

    由于指针本身也是变量,所以它们也可以像其他变量一样存储在数组中。下面是一个例子:

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define MAXLINES 5000
    #define MAXLEN 1000
    
    char *lineptr[MAXLINES];
    void quicksort(char *lineptr[],int left,int right);
    void swap(char *v[],int i,int j){
        char *temp = v[i];
        v[i] = v[j];
        v[j] = temp;
    }
    
    int main(int argc, char const *argv[])
    {
        /* 把数据读到lineptr中 */
        int lines;
        char buf[MAXLEN];
        int len = 0;
        while(gets(buf) && len<MAXLINES){
            char *s = (char *)malloc(MAXLEN*sizeof(char));
            strcpy(s,buf);
            lineptr[len++] = s;
        }
    
        quicksort(lineptr,0,len-1);
        for(int i=0;i<len;i++){
            printf(lineptr[i]);
            free(lineptr[i]);
        }
        return 0;
    }
    
    void quicksort(char *lineptr[],int left,int right){
        /* 递归出口 */
        if(left >= right){
            return;
        }
        int pivot = (left + right)/2;
        swap(lineptr,pivot,left);
        int i,j;/* j指向第一个小于等于pivot的值 */
        for(i=left+1,j = left;i<=right;i++){
            if(strcmp(lineptr[i],lineptr[left])){
                swap(lineptr,++j,i);
            }
        }
        swap(lineptr,left,j);
        quicksort(lineptr,left,j-1);
        quicksort(lineptr,j+1,right);
    }
    

    这个程序是我根据书上的内容改的,可能有一些不好的地方,但是基本功能是实现了的。

    多维数组

    C语言提供了类似于矩阵的多维数组,但实际上它们并不像指针数组使用得那样广泛。下面以二维数组为例。多维数组的使用和一维数组类似:

    int array[10][10];/* 声明一个二维数组 */
    array[5][5] = 10; /* 对二维数组的元素赋值 */
    

    值得注意的是,如果将二维数组作为参数传递给函数,那么在函数的参数声明中必须指明数组的列数,如:

    void fun(int array[][10]);
    

    该声明还可以写成:

    void fun(int *array[10]);
    

    命令行参数

    在支持C语言的环境中,可以在程序开始执行时将命令行参数传递给程序。调用主函数main时,它带有两个两个参数。第一个参数(习惯上称argc,用于参数计数)的值表示运行程序时命令行中参数的数目。第二个参数(称为argv,用于参数向量)是一个指向字符串数组的指针,其中每一个字符串对应一个参数。下面是一个例子,打印出命令行中的参数:

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
        int i;
        for(i=1;i<argc;i++){
            printf("%s%s",argv[i],i<argc-1?" ":"");
        }
        printf("\n");
        getchar();
        return 0;
    }
    

    指向函数的指针

    在C语言中,函数本身不是变量,但可以定义指向函数的指针。这种类型的指针可以被赋值、存放在数组中、传递给函数以及作为函数的返回值等等。下面看一个例子:

    /* 定义函数指针,该函数的返回值是int,参数为两个int */
    typedef int (*compare)(int, int);
    
    int max(int a, int b){
        if (a > b){
            return 1;
        }
        else if (a < b) {
            return -1;
        }
        else {
            return 0;
        }
    }
    
    int min(int a, int b){
        if (a < b) {
            return 1;
        }
        else if (a > b){
            return -1;
        }
        else{
            return 0;
        }
    }
    
    void swap(int *v, int x, int y){
        int temp = v[x];
        v[x] = v[y];
        v[y] = temp;
    }
    
    void quicksort(int *v, int left, int right, compare comp){
        /* 递归出口 */
        if (left >= right){
            return;
        }
        int i, j;
        for (i = left + 1, j = left; i <= right; i++){
            if (comp(v[i], v[left]) > 0){
                swap(v, ++j, i);
            }
        }
        swap(v, left, j);
        quicksort(v, left, j - 1, comp);
        quicksort(v, j + 1, right, comp);
    }
    

    编写完了之后能运行,但我发现函数调用的时候,书上写的是(*comp)(v[i],v[left]),但我发现像我上面那样写也是可以调用起来的。这可能是C编译器做的一些优化吧,从理解上来说,还是书上的比较好。

    复杂声明

    C语言中的声明有点令人难以理解,主要原因是它是从变量开始,然后按照运算符的优先顺序,进行左右结合。因为不是从左往右或从右往左,所以令人难以理解,下面是几个例子;

    /* f先和()结合,*的优先级低于(),说明是一个函数,返回值是int * */
    int *f();
    /* pf先和*结合,说明是一个指针,然后和()结合,说明是一个函数
     *函数的原型为int ();*/
    int (*pf)();
    /* x先和()结合,说明是一个函数,然后和*结合,说明返回值是一个指针
     *然后和[]结合,说明指针指向的是一个数组,然后和()结合
     *说明数组的类型是一个函数,然后和char结合,说明函数的返回值是char
     */
    char (* (*x())[] )();
    

    相关文章

      网友评论

          本文标题:指针和数组

          本文链接:https://www.haomeiwen.com/subject/tmmtnftx.html