Linux C语言高级学习第六天(指针初高级)

一、指针操作数组(通过指针操作数组中的元素)

1.一维数组

int a[10];
int *p;
p = &a[0];//或者 p = a;
*(p+i);    //-->a[i];

*p++;    <==>    *(p+i);

p在变化,输入结束后p指向了数组最后;    <==>    p没有变化,输入结束也在数组开头;

*p++;如何运算:

1)复制一个p指向对象的副本;

2)让指针p指向后偏移一格;

3)返回副本p的值。

2.二维数组

int a[][4];

int a[3][];    //错误

可以省略第一个,但是不可以省略第二个。

为什么二维数组和一维数组在内存中的存储方式一样

因此可以像操作一维数组一样操作二维数组:

二维数组是通过不同的基准点和不同的偏移量-->使用一位数组的方法是一个基准点不同的偏移量。

选好基准点数组下边也可以是负数

------------------------------------------------

int a[3][4];
int (*p)[4];//哪一个都不能少,确定 p+1 这加1会移动多少字节    变相的二级指针

p = a;

如何通过p访问a[i][j]

p+i    -->    指针指向第i行

*(p+i)    -->    将第i行内容取出来,此时指针指向第i行的首地址

*(p+i)+j    -->    在第二步的基础上,获取a[i][j]元素的地址

*(*(p+i)+j)    -->    在第三步的基础上,取出a[i][j]元素的值

3.字符数组

char str[]="HelloWorld";
char *p;
p = str;

char str[]="HelloWorld";==>char *str="HelloWorld";

如果这么写就会出现:段错误-->不是编译错误,是运行错误,问题是当前程序操作了非法内存

char str[]="HelloWorld";

将“HelloWorld”存入数组str内;

char *str="HelloWorld";

在内存的某块区域存储着“HelloWorld”,指针str指向了该内存

字符串是常量,字符数组是存储和处理字符串的变量==>在不影响语义的情况下可以混为一谈

PS:流    和    文件        -->        FILE*    流指针

二、指针高级语法:

1.野指针与空指针

int a;
int *p;
p = &a;

野指针:定义指针未指向有效对象-->没有办法在编译的时候检测出来(危害还特别大)

空指针:没有指向任何一块内存的指针

int *p = NULL;//可以用来防范野指针

2.返回值是指针的函数(指针函数)

#include<stdio.h>
int *ser(int score[][4],int n)        //指针函数
{
    return *(score+n);                 //返回第n行的首地址
}
int main()
{
    int score[3][4] = {
        99,88,77,66,
        88,77,66,55,
        77,66,55,44,
    };
    int n;
    int *a;
    scanf("%d",&n);
    if(n>=1 && n<=3)        //判断输入是否正确
    {
        n--;                                //二维数组是从第 0 行开始的:输入1-->变为 0
        a = ser(score,n);            //将第n行的首地址返回给指针 a
        for(n = 0; n < 4; n++)    //循环输出这一行的每一个数
        {
            printf("%3d",a[n]);
        }
        printf("\n");
    }
    else                                    //输入错误的行,报错
    printf("erro\n");
    return 0;
}

#include<stdio.h>
char *getmermory()                //指针函数
{
    char *p="Hello World";
    return p;
}
int main()
{
    char *str = getmermory();
    printf("str is %s\n",str);
    return 0;
}

3.指向函数的指针

函数的类型是由函数返回值与函数参数列表共同决定

返回值类型 ( * 指针变量名) ([形参列表]);

int sub(int x,int y)
{
    return x-y;
}
int (*p)(int,int); //定义函数指针
p = sub;
sub(x,y);<==>p(x,y);

发明函数指针的目的:将函数作为参数传递给被调函数(用来构建回调函数)

回调函数-->以下三个会用到

1.创建线程pthread_creat()

2.信号处理函数signal()

3.操作数据库获取数据sqlite3_exec()

特点:

1.事件触发    2.自动运行    3.使用函数指针传参            1.2.是功能特点    3.是代码特点

处理信号的方式

1.忽略

2.默认

3.捕捉(信号处理函数)

#include<stdio.h>
#include<signal.h>
void fun1(int sig)
{
    printf("Ctrl+c\n");//输入 Ctrl+c 时的响应
}
void fun2()
{
    printf("Ctrl+\\\n");//输入 Ctrl+\ 时的响应
}
void fun3()
{
    printf("Ctrl+z\n");//输入 Ctrl+z 时的响应
}
int main()
{
    signal(SIGINT,fun1);
    signal(SIGQUIT,fun2);
    signal(SIGTSTP,fun3);
    while(1)
    {
        printf("好好学习,天天向上\n");
        sleep(1);
    }
    return 0;
}

4.const修饰指针

const int *a;

    可以更改指针的指向,但无法通过指针修改指针指向的对象(但是可以直接通过变量修改)

    使用地址传递的时候,主调函数不希望被调函数修改主调函数的值的时候,就可以通过定义const来达到这个目的

int *const a;

    无法改变指针的指向,但是可以通过指针修改指针指向的对象

const int *const a;、

    指针的指向和指针指向的对象都无法修改

5.指针数组 与 main()传参

指针数组:存放指针的数组

char *str1 = "apple";
char *str2 = "orange";
char *str3 = "banana";
char *str4 = "watermelon";
char *str5 = "lemon";
//相当于:
char *str[5];
str[0] = "apple";
str[1] = "orange";
str[2] = "banana";
str[3] = "watermelon";
str[4] = "lemon";

main()函数的参数有两个

1.argc(argument count) :命令行参数个数

2.argv(argument vector) :命令行参数向量表

有参数证明有主调函数-->内核是main函数的主调函数-->因此main函数的return 0;也是给内核看的 -->0真;1假

             shell编程-->$0;$#;……

命令行传参:

#include<stdio.h>
int main(int argc,const char *argv[])    //argc:输入命令行的条数,每条命令以空格为分界
{                                                            //argv[]:记录每条命令的内容
    printf("argc is %d\n",argc);
    int i;
    for(i = 0; i < argc; i++)                    //循环,显示出所有命令行的内容
    {
        printf("*argv[%d] is %s\n",i,argv[i]);
    }
    return 0;
}

6.动态内存分配

前提:空类型指针:void *p    -->    未指向特定类型的指针  泛指所有数据类型的指针

          -->不能直接使用,使用时必须强转为特定的指针类型

1.动态内存分配(堆区)

memory allocation

头文件:#include<stdlib.h>

void *malloc(unsigned int size)

功能:使用malloc()在堆区开辟内存空间,申请内存空间的大小由malloc()参数决定

若malloc()申请内存成功,则返回内存的首地址(这时返回的是空类型指针);若申请内存失败-->则返回NULL

注意:使用malloc()申请内存空间需要进行成功/失败的判定

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int len,i;
    printf("请输入学生的人数:");
    scanf("%d",&len);                                                //输入数量,申请一定大小的空间
    int *p;
    if((p = (int *)malloc(sizeof(int)*len))==NULL)    //malloc申请空间,并判断是否申请成功
    {
        perror("Can't malloc");
        return 0;
    }
    for(i = 0; i < len; i++)                                        //循环输入每一个人的信息
    {
        printf("请输入第%d个学生的成绩:",i+1);
        scanf("%d",&p[i]);
    }
    for(i = 0; i < len; i++)                                        //不做处理,直接循环输出输入的信息
    {
        printf("%d  ",p[i]);
    }
    printf("\n");
    return 0;
}

#include<stdio.h>
#include<stdlib.h>
void bubble(int a[],int len)                  //传入带有数据的数组,按照从小到大顺序,进行冒泡排序
{
    int i,j;
    for(i = 0; i < len; i++)
    {
        for(j = 0; j < len-i-1; j++)
        {
            if(a[j] > a[j+1])
            {
                a[j] ^= a[j+1];
                a[j+1] ^= a[j];
                a[j] ^= a[j+1];
            }
        }
    }
}
void print(int a[],int len)                                //输出函数,输入数组及数组长度
{
    int i;
    for(i = 0; i < len; i++)
    {
        printf("%d  ",a[i]);
    }
    printf("\n");
}
int *getmemory(int len)                                        //malloc 申请堆区空间
{
    int *p;
    int i;
    if((p = (int *)malloc(sizeof(int)*len))==NULL)    //申请并判断是否申请成功
    {
        perror("Can't malloc");
        return NULL;
    }
    return p;                                                                //返回申请空间的首地址
}
int main()
{
    int i,j,len;
    printf("请输入学生的人数:");
    scanf("%d",&len);                                //根据输入,计算需要申请空间的大小(人数)
    int *p;
    p = getmemory(len);                            //指针 p 接收malloc申请的空间首地址
    for(i = 0; i < len; i++)                           //循环输入每个学生的数据
    {
        printf("请输入第%d个学生的成绩:",i+1);
        scanf("%d",&p[i]);
    }
    bubble(p,len);                                        //冒泡排序(小-->大)
    print(p,len);                                           //输出函数
    return 0;
}

2.使用free()回收malloc()申请的内存

    申请的是使用权,free时归还的也是使用权,拥有权一直属于操作系统

    原型:void free(void *p);

    free(p);

    绝对不可以free两次-->free掉一次后,原来的指针就变成了野指针,绝对不能操作野指针

    free掉一次后,把原来的指针置空  =NULL

猜你喜欢

转载自blog.csdn.net/nan_lei/article/details/81189840