美文网首页
指针和数组

指针和数组

作者: 漫游之光 | 来源:发表于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())[] )();

相关文章

  • C语言指针相关

    一、指针数组 和 数组指针的区别:1:指针数组,还是数组,数组每个元素是指针。2:数组指针,是指针,指向的是数组。...

  • JNI基础 -- C++基础知识(指针数组)

    数组和指针,数组指针,指针数组 数组 声明一个数组 这个比较简单,不做过多介绍 数组指针 数组指针是一个指针,指向...

  • 数组指针和指针数组

    1.数组名 数组首元素的地址和数组地址是两个不同的概念 数组名代表数组首元素的地址,它是个常量. 变量本质是内存空...

  • 数组指针和指针数组

    1.数组指针(又称行指针) 二维数组赋给一指针时: 2.指针数组 二维数组赋给一指针数组: 小结:数组指针只是个指...

  • 数组指针和指针数组

    指针*p不仅仅是地址(数据访问的位置),还包括所指向类型,即p+1移动的步长(如何访问)。数组指针,char (*...

  • 数组指针和指针数组

    输出结果:Example 数组指针:我我是是大大好人好人Example 指针数组: 我是大好人

  • 数组指针和指针数组

    https://www.cnblogs.com/mq0036/p/3382732.html 一维数组名和二维数组名...

  • 关于二维数组及数组指针和指针数组的深度思考(涉及指针)

    转载请注明在纠结指针数组和数组指针时无意发现的小细节。总算搞清数组指针和指针数组。 数组指针定义 int (*p)...

  • 指针

    指针 数组指针和指针数组 函数指针和指针函数 指针作为参数 指针多用于处理值传递,减少值复制耗费的内存

  • C语言特性(指针数组和指向指针变量的指针)

    指针数组和指向指针变量的指针 指针数组与main()函数形参 声明指针数组与声明普通数组的语法类似,其语法格式如下...

网友评论

      本文标题:指针和数组

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