欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言基础(四)(指针)

程序员文章站 2024-03-07 16:37:39
...

一、指针基础

1、定义、绑定、和解引用

  • 定义一个指针变量p,类型是int* ,指向一个int型的数据 :
int *p = NULL;///NULL代表指向空,即什么都不指向,等同于int类型的0;避免野指针。
  • 绑定一个int型变量a:
int a = 0;
int *p = &a;//指针变量内存储的是地址,故绑定非地址变量时需要使用取地址符号&
  • 指针的解引用
int a = 0;
int *p = &a;
*p = 6;     ///将p指向的地址,即a的值赋值为6。*为解引用符号。

2、指针的相减

  • 1、指针变量只能相减,不能加乘除。
  • 2、两指针变量相减,结果为int类型,数值为两指针指向的地址之差除以sizeof(变量类型),变量类型为指针所指向的数据的类型。
  • 3、若相减的两指针在同一数组中,贼相减的结果 == 两指针指向的元素的下标之差。

3、野指针

  • 野指针的危害(从低到高):
    1、直接指向内核区,即当前进程所使用的区域,可以随意修改。
    2、指向可用也没有别的数据的区域 。
    3、最严重,可用但有别的数据 ,会修改其他正在运行中的进程的数据。

在定义一个野指针时随机发生以上情况的其中一种,所以在编程中,野指针应尽量避免

二、指针的应用

1、指针函数

#include<stdio.h> 

void func(unsigned  short *a);

int main(void) 
{
    unsigned  short a = 0x11ff;
    func(&a);
    printf ("%x\n", a);
} 

void func(unsigned  short *a)
//在传输参数时,传来的是指针,即a的地址,所以在子函数中,*a的运算改变的是a所指向的地址的值,故可以影响到主函数的值(可以直接对数组进行赋值也是一个道理)。
{
    unsigned  short b = *a;
    *a = *a << 8;
    b = b >> 8;
    *a += b;
} 

2、函数指针

#include<stdio.h> 

void func(unsigned  short *a);

int main(void) 
{
    unsigned  short a = 0x11ff;
    void (*p)(unsigned  short *a) = &func;//&func 或 func都可以。
    (*p)(&a);                          //(*p)(&a) 或 p(&a)都可以。
    printf ("%x\n", a);
} 

void func(unsigned  short *a)
{
    unsigned  short b = *a;
    *a = *a << 8;
    b = b >> 8;
    *a += b;
} 

3、指针数组

  • 即定义一个数组,该数组的每一个元素都是一个指针。
#include<stdio.h> 

int main(void) 
{
    int arr[5] = {1, 2, 3, 4, 5}, i = 0;
    int *p_arr[5] = {};  ///指针数组。
    for (i=0; i<5; i++)
        p_arr[i] = &arr[i];
    printf("%d.\n", *p_arr[2]);
} 

4、数组指针

  • 定义一个指针,该指针指向的数据是一个数组型的数据。(即自加一会越过整个数组)
#include<stdio.h> 

int main(void) 
{
    int arr[2][3] = {1, 2, 3, 4, 5, 6};
    int (*p)[3] = &arr[0] + 1; ///数组指针
    printf("%d.\n", **p);     //输出为a[1][0]的值:4
} 

三、相关命令

1、malloc函数

  • 头文件: #include <stdlib.h>
  • 命令格式:int *p = (int *p)malloc(数字)//申请时默认返回void *
  • 堆内存也是内存的一种,需要程序员自己手动申请malloc,手动释放 。
    编译器不会自动回收,申请的内存伴随整个程序 。
    malloc申请的空间,默认是有最小分配的。
    流程:申请,判断成功,初始化,使用,释放,指针设置为空 。

2、typedef

  • typedef的作用是定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。
  • typedef可以在全局定义,也可以在函数中定义。
typedef int my_int//将int重命名为my_int 
typedef char * my_char_p//将char *重命名为my_char_p 
typedef (void (*p)(void)) my_func//将void * void 类型的函数重命名为my_func 

3、const 关键字

  • const 修饰的变量是常数,不可更改,只能初始化一次;但可以用指针解引用修改。
#include <stdio.h>

void main(void)
{
        const int a = 0;
        a = 3;           //错误,不可以直接修改内容
        int *p = &a;
        *p = 2;          //正确,可以通过指针更改内容
        printf ("%d", a);

        return;
}  

四、二维数组

  • 定义:
int a[2][3];   //代表定义一个int型的二行三列的数组。
  • 二维数组的变量名是首元素首地址{arr[0], arr[1]}
  • &arr代表第一维数组的首地址。
  • &arr[0]、arr 代表第一维数组的首元素首地址,第二维数组的首地址。
  • &arr[0][0]、arr[0] 代表数组的第二维数组是首元素首地址。

五、二重指针

  • 二重指针指向的是一重指针的地址,一重指针不能指向一重指针的地址。
  • 二重指针的使用:
#include <stdio.h>

void func (int **p);

void main (void)
{
    int **q = NULL, *p = NULL;
    int a = 11;
    p = &a;
    q = &p;
    func (q);
    printf("*p = %d\n", *p);   // *p = 22 
    printf("**q = %d\n", **q); // **q = 0
}

void func (int **p)
{
    int a = 22;
    *p = &a;
}
相关标签: c语言 指针