C语言整理-8

来源:互联网 发布:数据出售 编辑:程序博客网 时间:2024/05/16 03:21

指针:

存储:

字节是最小的存储单元。每一个内存单元有一个编号,这个编号就是地址。

指针:

指针就是地址。

指针变量:

指针在没有放入地址之前,叫地址;放入地址之后叫指针。

指针变量的定义:

(1)、类型:通过类型,我们知道从这个地址取出来的数据是什么类型的,也可以知道取出来多少个字节。

(2)、*:*号是一个标识作用,在定义的时候,告诉你这个变量是指针类型的。

(3)、NULL:指针变量的初值,表示空,没有指向任何内存。

通常我们再程序中,把指针变量叫做指针。

指针变量定义的形式:

int *p1 = NULL;

 

定义一个char类型、double类型、long类型、float类型的指针变量。

 

//    char *p2 = NULL;

//    double *p3 = NULL;

//    float *p4 = NULL;

//    long *p5 = NULL;

区分一下:定义时的*号和取值符*号的区别,再定义一个指针时,*号表示的意思是,这个变量是指针变量;在定义完事之后,要取出这个指针变量所指向的内存所存储的值,就用*p来取值,此时的*号为取值符。

关于指针的一些符号:

& :表示取地址符,用来取一些变量的地址。

* :取值符。用来取对应地址所存储的内容。

%p:打印地址占位符。打印地址的时候,用%p来作为占位符。

一些例子:

//    获取num1的地址

//    int num1 = 10;

//   

//    p1 = &num1;

//    打印地址 p1

//    printf("%p\n",p1);//0x7fff5fbff834

   

//    通过地址取值

//    printf("%d\n",*p1);//10

 

注意:

不要直接给变量赋地址编号,虽然不报错,但是这是不合理的,系统会判断为你访问了不该访问的内存编号,在运行的时候,会因为内存出错而导致程序崩溃。

用上面的例子来说:

 

//    int *pt = 0x1;//若把地址编号改成0x7fff5fbff834,则可以访问,因为这个地址编号,就是系统给你用的。

//    printf("%d\n",*pt);//10

若把地址编号改成0x7fff5fbff835,即把pt + 1 也能使用,因为系统给你分的内存,不仅仅是一块,而是给你4块,若是在这4块之外,即pt + 5,则会直接导致结果直接崩掉。

指针的移动:(指针的算数运算,只有+ -)

指针可以移动,但是移动多少个字节,需要根据它所指的数据的类型来决定。

例如,它指向的数据是int型(占4个字节)的,那么指针在每一次移动的时候,是移动4个字节。

例子:

//    for (int i = 0; i < 10; i ++) {

////        p1没有移动。

//        printf("%d\n",*(p1+i));

////        p1移动了。结束后,p1已经不指向原来的位置了。

//        printf("%d\n",*(p1 ++));

       

//        printf("%p\n",p1+i);

        /*

        输出:

        0x7fff5fbff854

        0x7fff5fbff858

        0x7fff5fbff85c

        0x7fff5fbff860

        0x7fff5fbff864

        0x7fff5fbff868

        0x7fff5fbff86c

        0x7fff5fbff870

        0x7fff5fbff874

        0x7fff5fbff878

        每次移动4个字节,从上到下,每次+4

        */

//    }

   

 

指针重指向:

指针重指向,即为给一个指针重新赋值。

//    int num2 = 20;

//    //指针重指向:给指针变量再赋值。

//    p1 = &num2; //p1指向了num2的地址。

指针与数组的关系:

数组:用连续的内存空间来存储数据的构造类型。

数组名本身就是整个数组的首地址,也就是第1个元素所在的地址,因此,再取地址时,不需要再用&取值符了。

    //数组名就是整个数组的首地址

    //数组名本身就是地址,不用再取地址了。

//    int array[3] = {1,3,8};

//    printf("%p\n",array);//0x7fff5fbff840

//    数组的首地址,就是数组中,第一个元素的地址

//    printf("%p\n",&array[0]);//0x7fff5fbff840

一个指向int类型数组的指针,是int类型。在一个指针指向一个什么类型的数组时,这个指针对应的就是什么类型的。

使用指针和数组名取值:

(1)、用数组名取值

//    一个指向int类型数组的指针,是int类型

//    int *pi = array;

//    printf("%d\n",*pi);//1

//    printf("%d\n",*(pi+1));//3

    //使用指针和数组名取值

    //数组名取值。

//    printf("%d\n",array[0]);//1

   

//    printf("%d\n",*array);//1

//    printf("%d\n",*(array + 2));//8

 

(2)、使用指针变量取值:

    //使用指针变量取值

//    printf("%d\n",pi[0]);//1

//    printf("%d\n",pi[2]);//8

//    printf("%d\n",*pi);//1

//    printf("%d\n",*(pi+1));//3

注意的是:

指针在取值时,可以当做数组名来使用(即可以按照数组取值那样取值)。

p[ x ] = * ( p + x ) 是等价的。(x)表示任意一个整型数,p表示指针变量或者表示数组名。

数组名和指针的区别:数组名是地址常量,指针变量是变量。常量的值是固定的,不能再改变,指针变量的值是可以改的。

    int array[3] = {1,3,8};

    int *pi = array;

//    数组名和指针的区别。

//    数组名是地址常量

//    指针变量是变量

//    pi ++;//合法

//    array ++;//报错

指针的内存空间:

指针本身占内存空间的大小,与它所指向的数据的类型无关,只与它所在的操作系统的位数有关。32位系统和64位系统的指针占内存不同。

例子:

//    内存空间

//    printf("%lu\n",sizeof(array));//12

//    printf("%lu\n",sizeof(pi));//8,指针本身的占内存空间的大小,不关其他类型的事。指针占内存的大小,只与操作系统的位数有关。

一个练习:

    //给你一个数组:元素都是int类型的,但是你不知道有多少个元素。

//    int array1[] = {1,2,3,4,5,6};

//   

//    int arr_length = sizeof(array1);

//    printf("%lu",arr_length / sizeof(int));//6

注意的一些问题:

不同类型的指针,相互之间相互赋值,是不合法的,虽然可能可以取到正确的值,但是很多情况下,取值会出现问题。

具体来说,若定义了一个int型的数,然后定义一个char型的指针变量p,此时通过 p 来取值,则可以取到正确的值。原因是:int类型的数据,再内存中占有4个字节32位,即系统分配了4个连续的存储空间,每个空间1个字节(8位)给这个int型的数,但是此时这个数比较小,只在第一个存储空间就可以装完,则其他三个字节空间都为0。此时,char类型占一个字节,正好可以取到int型数据的第一个字节空间的值,也正好能存完。此时取到的值是正确的。(画图便能说明白)。若定义了short型的数据(占2个字节),分配了2个连续的内存空间,此时定义的指针是int型,则指针此时取值的时候,取到的是连续4个字节空间的值,此时,就会把这4个连续的内存空间的所有2进制数加起来变成一个很大的10进制数。那么取到的值就是错误的。

例子:

//    int num1 = 3;

//    //不同类型指针,取值会出问题。

//    char *pn = &num1;

//   

//    printf("%d\n",*pn);

   

//    short a[4] = {3,7,9,1};//short类型占2个字节

//    int *p1 = a;           //int类型占4个字节

//    char *p2 = a;          //char类型占1个字节

//   

//    printf("%d\n",*p1);//458755,因为p1取了4个字节共32位的所有01,计算结果即为458755

//    printf("%d\n",*p2);//3 ,因为p2只取了一个字节的值,这个字节里正好存了3,正好可以存进char,所以可以取到3

指针和字符串的关系:

首先记住一个东西:栈区的值是可以改变的。常量是放在常量区的,常量区的所有值是不能改变的。那么就好办了。

字符指针可以操作单个字符,也可以操作字符串。

看例子就能明白了:

char string[] = iPhone; //string为数组名

char *p = string; //指向字符数组地址

*(p + 1) = v; //操作单个字符

printf(%s,p + 1); //操作整个字符串

 

////    指针和字符串的关系

////    string1再栈区存放,栈区的值是可以改的。

//    char string1[] = "Ipad";

//    char *pc = string1;

//    printf("%s\n",pc);//Ipad

////    改变字符数组的位置

////    pc[0] = 'i';

//    *(pc + 0) = 'i';

//   

//    printf("%s\n",pc);//ipad

    //常亮字符串存在常量区,常量区的所有数据只读不可写(不能改变值)

//    char *ps = "Iphone";

//    printf("%s\n",ps);//Iphone

   

//    ps[0] = 'i';

//    printf("%s\n",ps);//出错

//    printf("%c\n",ps[0]);//I

   

//    printf("%c%c%c",*(ps+3),*(ps+4),*(ps+5));//one

//    ps += 3;

    //%s要的是字符串的首地址和结束的标志"\0"

//    printf("%s",ps);//one

//    printf("%s",ps + 3);//one

  

 

一些练习:

//    练习:

//    通过指针计算字符串的长度

   

    char string2[] = "Iphone";

    char *ps = string2;

    int n = 0;

//    while (ps[n] != '\0') {

或者

    while (*(ps + n) != '\0') {

        n ++;

    }

    printf("%d\n",n);//6

指针数组:(跟那个指针与数组的关系区分一下)

指针数组就是一个数组,这个数据里的所有元素,都是指针(也就是地址,其实是每个字符串的首地址)。

注意:这些字符串,不是存在这个指针数组中,而是存在另外一个字符数组中,这个指针地址存的是那个字符数组的每一个字符串的首地址。

    //指针数组

   

    //指针数组是一个数组,数组中的元素,都是指针(地址,其实是每一个字符串的首地址)。

    //注意:这些字符串,不存在指针数组中。

//    char *strarray[3] = {"iOS","Android","Windows10"};

//   

//    for (int i = 0; i < 3; i ++) {

//        printf("%s\n",strarray[i]);/*

//                                   iOS

//                                   Android

//                                   Windows10

//                                   */

//    }

 

指针作为函数参数:

这个就是精华所在:指针作为参数,可以跨作用域取改值。

//指针作为参数。

//(重点):指针可以跨作用域改值。

 

int swap (int *n1,int *n2){

    *n1 = *n1 ^ *n2;

    *n2 = *n1 ^ *n2;

    *n1 = *n1 ^ *n2;

    return 0;

}

//函数声明:

int swap(int *num1,int *num2);

//主函数

int main(int argc,constchar * argv[])

{

//    例子:写一个函数

//    有两个参数,交换这两个参数

    int num1 = 10;

    int num2 = 20;

    printf("交换前:\n");

    printf("num1 = %d\nnum2 = %d\n",num1,num2);

    swap(&num1,&num2);

    printf("交换后:\n");

    printf("num1 = %d,num2 = %d",num1,num2);//num1 = 20,num2 = 10

    return 0;

}

 

 

 

0 0
原创粉丝点击