• C语言-指针


    1、一维数组指针
    指向一维数组的指针
    int a[5] = {1,2,3,4,5};
    int *p = a;


    2、二维数组指针
    指向二维数组的指针
    int arr[1][3] = {1,2,3};
    int (*p)[3] = arr;

    注意:
    数组名a不代表整个数组,只代表数组首元素的地址。

    3. 指针数组

    指针数组:数组的每一个元素都是一个指针
    或者存放指针的数组,就是指针数组

    int a=3,b=4,c=5;
    int *pa[3]={&a,&b,&c};

    int a[2][3]={{1,2,3},{4,5,6}};
    int *pa[2]={a[0],a[1]};

    4.指针之间的运算

    前提:两个指针必须指向同一个数组
    运算:减法
    实质:计算两个指针之间关系,判断指针的位置
    p = a; p1 =&a[3]
    p1 - p > 0 表示p1在高位置
    p1 - p < 0 表示p1在低位置
    p1 - p = 0 表示p1和p指向了同一个位置

    注意:
    指针的运算,不能有加,乘,除运算

    5.数组名访问二维数组

    int a[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
    访问 第一行的第一个元素地址表示:
    a + 1 = &a[1] = a[1] = &a[1][0] = *(a + 1)

    获取第一行的第一个元素值的方式:
    *a[1] = a[1][0] = **(a + 1)

    6.指针和字符串

    1、字符串指针,用来保存字符串
    char *s = "agadsf"; // 有
    2、用字符数组的方法保存字符串
    char ch[]="dafasdf";// 有

    3、字符串指针变量和字符数组的的区别

    a、区别一,能否重新赋值问题
    char ch[20]="xxxxx";
    ch = "asdfasdf"; // 不可以的 ch是常量,存储的是数组的首地址
    char *ss="xxxxxx"; //"xxxxxx" 0x01
    ss = "xxx"; // 可以的,ss是指针变量,

    b、区别二,存储的区别
    char ch[10]="xxxx"; 存放的是栈区(可读可写) x x x x 0 0 0 0 0 0 0
    ch[4]='A'
    char *str ="pppp";存放的是常量区(只读)

    7.字符串的存储方式

    存储字符串的几种方式
    1. 一维字符数组
    char ch[10] = "fengjie";

    2. 二维的字符数组
    char name[10][20]={
    "fengjie",
    "suibian",
    "xxxxxx" };

    3. 字符串指针变量
    char *str = “fengjie”;


    4. 指针数组 常量区
    char *name[10]={
    "fengjie",
    "suibian",
    "xxxxxx"
    }

    一、基本知识点

    Int a=10;

    Int *p;//定义一个int类型的指针

    P=&a;//指针变量p指向了变量a

    *p=20;//使用指针不通过变量直接修改变量a的值为20

    *p表示访问指针变量p指向的存储空间

    指针一个作用:能够根据一个地址值,访问(取值 | 赋值)对应的存储空间

    指针变量p前面的int,表示指针的类型

    ①. Int *p;

    ②. *p=10;

    两个*的区别:前一个起标识作用,表明定义的p是一个指针,后者的*表示通过访问p指向的地址空间

     

    二、指针使用注意

    ①. Int *p;

    double d=10.0;

    p=&d;//不建议此种做法

    ②. Int *p;

    p=200;//指针变量只能存储地址

    ③. Int *p;

    printf(“%d ”,*p);//指针变量未经初始化,不要拿来间接访问其他的存储空间

    ④. Int *p=&a;但是不能写成 int *p;*p=&a;这种写法没有任何的意义,可以认为*是和类型符一起使用的。

    ⑤. *是指针运算符,访问指针指向的空间

     

    三、指向指针的指针

    Int a=10;

    Int *p=&a;//指向int型的指针

    Int **p1=&p;//指向指针的指针

    Int ***p2=&p1;//三级指针

     

    *p2相当于访问p1;

    **p2相当于访问p;

    ***p2相当于访问a;

    *p1相当于访问p;

    一颗星一条线。

     

    四、指针练习

    编写一个函数,计算a和b的和与差(一个函数返回两个值)

    提示:指针的作用之一:实现让函数拥有多个返回值

    View Code

    五、有关指针的疑问

    注意:任何类型的指针都占据8个字节的存储空间,那么为什么还要为指针加上类型呢?

    对下面一段代码进行内存分析,可以证明指针类型不正确带来的严重后果。

    Int i=2;

    Char c=1;

    Int *p=&c;//本应该是char类型的,写成了int类型

    Printf(“c的值是%d ”,*p);//打印结果为513,而非1

    Printf(“c的值是%d ”,c);//值为1

    下面是上述代码的结果的内存分析:

     

    指针p访问的本应该是1个字节空间的数据,此时因为指针的类型是int型的,因此程序自然的从指向的地址0x0a开始读取了4个字节的数据,访问的数据从1变成了513。

    提示:明确了指针的数据类型,指针才能够正确的访问应该访问的空间数据。

     

    六、指针和数组

    Int ages[5]={10,9,8,7,6};

    遍历数组

    For(int i=0;i<5;i++)

    Printf(“%d ”,ages[i]);

    使用指针遍历数组

    Int *p;

    P=ages;//也可以写成p=&ages[0];,指针变量p指向了数组的首元素

    元素的地址:

    第一个元素的地址p    &ages[0]

    第二个元素的地址p+1    &ages[1]

    第三个元素的地址p+2    &ages[2]

    元素的值

    *p        ages[0]

    *(p+1) ages[1]

    *(p+2) ages[2]

    把指针当做数组来用:

    For(int i=0;i<5;i++)

    Printf(“%d ”,*(p+i));

     

      (1)数组元素的三种访问形式:

    ①. 数组名[下标]

    ②. 指针变量名[下标]

    ③. *(p+1)

    (2)指针变量的+1究竟是加多少?这取决于指针的类型,如果是char类型则加1个字节,如果是int类型的,则加4个字节。

      (3)利用指针来接收一个数组,指针变量指向了数组的首元素。

    Void change(int array[])等价于void change(int *array)。

    前者存储的虽然是数组元素的首地址,但是在传递时就已经变成指针了。

    示例:

    Void change(int *array)

    {

    //Printf(“%d ”,array[2]);

    Printf(“%d ”,*(array+2));

    }

    Int main()

    {

    Int ages[5]={1,2,3,4,5};

    Change(ages);

    }

    调用的结果为:数组的第三个元素3

    若改给change(&ages[2]);则调用的结果为5,因为此时array指向的是ages[2],把ages[2]当做了array的首元素

     

    七、指针和字符串

    (一)基础知识

    下面两行代码有着本质的区别:

    ①. Char name[]=“it”;

    ②. Char *name2=“it”;//指针变量name2指向了字符串的首字符i

     

    Char name[0]=‘y’;//改变第一个元素的值

    Printf(“%s ”,name);//打印结果为yt

     

     *name2=‘y’;

    Printf(“%s ”,name2);//此时程序崩溃

    这是因为,两者一个是字符串变量,一个是字符串常量。C语言的数组元素存放于栈,里面的元素可以随便修改,称为字符串变量。而字符串常量存放于常量区,会缓存起来是不可更改的。

    Char *name1=“it”;

    Char *name2=“it”;

    Printf(“%p %p”,name1,name2);//地址是一样的,说明name1和name2指向的是同一个字符串。

     

    掌握字符串定义的两种方式:

    ①. 利用数组

    特点:字符串里边的字符是可以修改的,适用于内容需要经常修改时。

    ②. 利用指针

    特点:其实是一个常量字符串,里面的字符不能修改,适用于字符串的内容不需要修改,且这个字符串经常被使用时。

     

    (二)指针数组

    整型数组:这个数组中存放的都是整型数组

    指针数组:这个数组中存放的都是指针

    Int ages[5];

    Char *name[5]={“jack”,“rose”,“yang”};//字符串数组的常见写法

    对应于:

    Char name2[3][10]={“jack”,“rose”,“yang”};

    保存字符串数组的两种方式:

    ①. 指针数组(字符串数组)

    ②. 二维字符数组(字符串数组)

    如何输入字符串?(使用数组——因其可变)

    Int main()

    {

    Char name[20];

    Printf(“请输入姓名: ”);

    Scanf(“%s”,name);

    Printf(“%s”,name);

    }

     

    八、返回指针的函数

    程序示例:

    #include<stdio.h>

    Char *test();

    Int main()

    {

    Char *name=test();

    Printf(“name=%s ”,name);

    Return 0;

    }

     

    Char *test() //返回指针的函数

    {

    Return “rose”;

    }

     

    九、指向函数的指针

    数组名即数组的地址,函数名即函数的地址。

    假设有函数:

    Void Test ()

    {

    Printf(“调用了test函数 ”);

    }

    Void (*p)();  //void指针变量指向的函数没有返回值,()表示p指向的函数没有形参

    P=test; //有指针p,把指针p指向函数

    有三种方式可以操纵函数:

    ①. 直接调用test();

    ②. 利用指针变量简介调用  (*p)();

    ③. 简化使用p()

     

    练习:

    假设有函数声明为 int sum(int a,int b)

    则相对应的指向该函数的指针应该定义为:int (*p)(int ,int);

    把指针变量p指向函数:p=sum;

    调用该函数的三种方式:

    (1)int c=p(10,12);

    (2)Int c=sum(10,12);

    (3)Int c=(*p)(10,12);

     

    假设函数声明为:double haha(double a,char *b,int c);

    则定义一个指向haha函数的指针应该为:double (*p)(double,char *,int)=haha;

  • 相关阅读:
    WPF Prefix 'attach' does not map to a namespace.
    C# 用ManulResetEvent 控制Thread的 Suspend、Resume
    C# 监控Windows睡眠与恢复
    c# DataTable to Object Mapping
    C# DispatcherTimer Start之后立即执行
    Visual studio 编译时copy文件、文件夹
    c# 无法加载xxx.dll 找不到指定的模块(如何指定文件夹)
    EntityFramework 找不到方法:“Void System.Data.Entity.DbModelBuilder.RegisterEntityType
    wpf 全局异常捕获处理
    pandas入门
  • 原文地址:https://www.cnblogs.com/jiayongqiang/p/5094013.html
Copyright © 2020-2023  润新知