指针的一些常见使用

一、介绍

指针是编程语言中一种重要的数据类型,它存储了一个变量的内存地址。通过使用指针,程序可以直接访问和操作内存中的数据,这在某些情况下可以提高程序的效率和灵活性。在C、C++等编程语言中,指针是一个非常基本且强大的概念。

1、以下是指针的一些基本概念和操作:

(1)、内存地址

指针存储的是变量在计算机内存中的地址。这个地址可以通过取地址运算符(&)来获取。

Copy code
int x = 10;
int *ptr = &x; // ptr存储了变量x的地址
指针声明: 指针的声明需要指定它所指向的变量类型。例如,int *ptr 表示ptr是一个指向整数的指针。

注: 虽然是int型的指针,但该变量是存储地址的,他所占的内存跟什么类型无关。
例如你电脑或者编译器设置成32位的,就相当于他的地址是32的bit,他是4B,也就是4个字节
(因为指针是用来存储内存地址的数据类型,指针需要多大空间,取决于地址的存储需要多大空间

printf("%d\n",sizeof(char*));
printf("%d\n",sizeof(short*));
j结果都为4

(2)、指针解引用

使用解引用运算符(*),可以访问指针所指向地址上的值。

#include <stdio.h>
int main()
{
	int num=10;
	int* other = &num;// other指向变量num的地址
	printf("other=%d\n", *other);
	*other = 20;//指针的重新赋值
	printf("other2=%d\n", *other);
	return 0;
}
结果:
other=10
other2=20
num=20//可以通过指向它的指针直接修改他的值

二、算术运算

1、指针可以进行算术运算,例如递增(++)和递减(–),以在数组和其他数据结构中移动。

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // 指向数组的第一个元素
printf("Value at first index: %d\n", *ptr);
ptr++; // 移动到数组的下一个元素
printf("Value at second index: %d\n", *ptr);

2、指针-指针,得到的是两个指针之间的元素个数(要对两个指针指向同一块空间来说,且还是同类型的指针)

int arr[5] = {1, 2, 3, 4, 5};
int *start = arr; // 指向数组的第一个元素
int *end = arr + 4; // 指向数组的最后一个元素
int count = end - start + 1; // 得到数组中的元素数量

3、指针移动,可以移动到数组最后那位的后面,但是不能指向数组最前指针的前面

(1)指针递增:指针递增操作是合法的,通过 ptr++ 或 ptr += n,可以将指针移动到数组或缓冲区的下一个位置。
(2)指针递减:指针递减操作也是合法的,通过 ptr-- 或 ptr -= n,可以将指针移动到数组或缓冲区的前一个位置。然而,在执行递减操作之前,指针应该指向有效的内存地址,否则会导致未定义的行为

三、容易造成野指针:

1、开始没有初始化,没有初始化的指针是随机访问内存(非法访问),初始化int* P=NULL;

2、代码空间已经释放

如下:代码a已经释放了,就不能让它再赋值20。

int* test()
{
	int a = 10;
	return &a;
}

int main()
{
	int* p = test();
	*p = 20;
	printf("p=%p\n", p);//%p打印地址
	return 0;
}

3、小心指针越界

4、空间释放立即置NULL

5、指针使用之前检查他的有效性

int* p=NULL;
*p=10;

上述这样是错误的,一开始初始化为NULL,但是你要 再赋值完地址 才能进行赋值,一开始是NULL地址时不能进行赋值。

四、 指针数组,数组指针

1、指针数组

指针数组是一个数组,其中的每个元素都是一个指针。这意味着数组中的每个元素都存储着一个地址,通常指向相同类型的变量。以下是一个简单的指针数组的例子:

int a = 10, b = 20, c = 30;
int *ptrArr[3];  // 声明一个包含3个指针的数组

ptrArr[0] = &a;
ptrArr[1] = &b;
ptrArr[2] = &c;
// 现在ptrArr包含三个指向整数的指针
在上面的例子中,ptrArr 是一个包含3个指针的数组,每个指针分别指向变量 a、b 和 c。

2、数组指针

数组指针是一个指针,它指向一个数组。这意味着它存储着数组的起始地址。以下是一个简单的数组指针的例子:
int arr[5] = {1, 2, 3, 4, 5};
int (*ptrArr)[5];  // 声明一个指向包含5个整数的数组的指针
ptrArr = &arr;
printf("%d\n", (*ptrArr)[2]);  // 输出数组的第三个元素,结果为3
// 现在ptrArr指向数组arr
在上面的例子中,ptrArr 是一个指向包含5个整数的数组的指针,它指向数组 arr 的起始地址。
1*ptrArr: 这是对指针 ptrArr 进行解引用操作。解引用操作返回指针所指向的值,而在这个情况下,该值是一个数组。
(*ptrArr)[5]: 这表示解引用后的值是一个包含5个元素的数组。它是一个长度为5的数组,包含相应的数据类型。
2int *ptrArr[5],这样也不行,因为他首先和方块结合,表示他是一个数组,而我们要实现的是一个指针。
3、不可以int *ptrArr=&arr这个表示指针指向的是int

五、函数指针,指针函数

1、函数指针(Function Pointer):

函数指针是一个指针,其指向函数而不是变量。通过使用函数指针,可以在运行时动态地选择调用哪个函数。
以下是一个简单的函数指针的例子:

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int main() {
    int (*operation)(int, int); // 声明一个函数指针

    operation = add; // 指向add函数
    printf("Addition: %d\n", operation(5, 3));

    operation = subtract; // 指向subtract函数
    printf("Subtraction: %d\n", operation(5, 3));

    return 0;
}

2、指针函数(Pointer Function):

指针函数是一个返回指针的函数。这意味着函数的返回类型是一个指针类型。以下是一个简单的指针函数的例子:

#include <stdio.h>
int* createArray(int size) {
    int *arr = (int *)malloc(size * sizeof(int));
    return arr;
}

int main() {
    int *dynamicArray;
    dynamicArray = createArray(5);
    // 现在dynamicArray是指向动态分配的整数数组的指针

    // 在使用完动态分配的数组后,不要忘记释放内存
    free(dynamicArray);

    return 0;
}

六、二级指针

二级指针是指指针指向的内容本身是一个指针。在C和C++等编程语言中,可以通过使用二级指针来操作指针的指针。这种概念在处理动态分配的内存和多级数据结构时非常有用。
以下是一个简单的例子,说明了如何声明、分配内存和使用二级指针:

#include <stdio.h>
#include <stdlib.h>

// 函数原型,用于动态分配二维数组
int** allocate2DArray(int rows, int cols) {
    int** array = (int**)malloc(rows * sizeof(int*));//给第一维分配存储空间
    for (int i = 0; i < rows; i++) {
        array[i] = (int*)malloc(cols * sizeof(int));//给第二维分配存储空间
    }
    return array;
}

// 函数原型,用于释放动态分配的二维数组
void deallocate2DArray(int** array, int rows) {
    for (int i = 0; i < rows; i++) {
        free(array[i]);
    }
    free(array);
}

// 函数原型,用于填充二维数组
void fill2DArray(int** array, int rows, int cols) {
    int count = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            array[i][j] = count++;
        }
    }
}

// 函数原型,用于打印二维数组
void print2DArray(int** array, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%4d ", array[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int rows = 3;
    int cols = 4;

    // 使用二级指针动态分配二维数组
    int** twoDArray = allocate2DArray(rows, cols);

    // 填充和打印二维数组
    fill2DArray(twoDArray, rows, cols);
    printf("Original 2D Array:\n");
    print2DArray(twoDArray, rows, cols);

    // 释放动态分配的内存
    deallocate2DArray(twoDArray, rows);

    return 0;
}

七、C语言的指针和C++的引用的区别

1、语法和声明:

指针: 在C中,指针使用 * 运算符进行声明和操作。例如,int *ptr; 表示声明了一个指向整数的指针。
引用: 在C++中,引用是通过 & 运算符进行声明的。例如,int &ref = x; 表示声明了一个整数引用 ref,它引用变量 x。

2、空指针和野指针:

指针: C中的指针可以是空指针(NULL 或 nullptr)或者指向任何地方的野指针。
引用: C++中的引用在声明时必须初始化,并且不会产生空引用的概念。引用在其生命周期内总是引用同一个对象。

3、指针的重新赋值:

指针: 指针可以在其生命周期内指向不同的地址。
引用: 引用在初始化后不能改变引用的目标,因此不允许对引用重新赋值。

4、运算符重载:

指针: 指针不支持运算符重载。
引用: 引用可以通过运算符重载来实现自定义的行为。

5、传递给函数的方式:

指针: 指针作为参数传递给函数时,函数可以修改指针所指向的值。
引用: 引用作为参数传递给函数时,函数可以修改引用所引用的对象。

6、指针和数组:

指针: 指针与数组有密切的关系,指针可以用于遍历数组元素。
引用: 引用没有直接的数组概念,引用通常用于表示单一对象的别名。
例如:

#include <iostream>
void modifyValue1(int *ptr) {
    *ptr = 50;
}

void modifyValue2(int &ref) {
    ref = 50;
}

int main() {
    int x1 = 10;
    int X2=10;
    modifyValue1(&x1);  // 通过指针修改x的值
    modifyValue2(x2);  // 通过引用修改x的值
    printf("x1=%d\n",x1);
     printf("x2=%d\n",x2);
    return 0;
}

八、 与数组的一些区别

1、数组定义一个常量后,后期是可以修改的;
指针定义常量后是不可以修改的(他会报访问冲突),因为他已经指向常量hello bit的储存地址,所以为了严谨一般会在char*指针前加一个 const(强调他是不能修改的)
在这里插入图片描述
2、数组名与&数组名
1、
在这里插入图片描述

虽然arr和&arr输出的结果是一样的,但是意义不一样。
arr是指向元素的首地址,&arr是数组的首地址
p1+1他跳的是一个int型(因为是int型指针),P2+1他跳的是一个数组的大小(所以上面打印地址插了40)。
2、其他:
sizeof(数组名)-数组名表示整个数组,计算的是整个数组大小
&数组名-数组名表示整个数组,取出的是整个数组的地址

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值