首页 > 其他分享 >深入浅出_指针

深入浅出_指针

时间:2024-07-19 18:50:59浏览次数:14  
标签:int void 深入浅出 内存 printf include 指针

指针

指针基本介绍

变量在内存中的存储

如图中右侧图形表示计算机内存(memory),图形中每一个长条表示一个字节(byte),每一个字节存在对应的一个地址,如左侧0、201、202...209所标注

image-20230927215632420

对于典型的现代计算机,1个int类型变量由4个字节表示,1个char类型变量由1个字节表示,1个float类型变量由4个字节表示。对于如下代码:

int a;
char c;
a = 5;
a++;

在内存中,如内存模型所示:计算机分配地址为204-207共4个字节的存储变量a,分配地址为209的1个字节存储变量c,当给a赋值5时,将在地址204-207的内存处存储5(在计算机中数字以二进制保存),a自加1则会对地址204-207内存位置存储的5加1。

指针变量在内存中的储存

指针:指针是一个变量,存放着另外一个变量的地址

对于如下代码:

int a;
int *p; 
p = &a;
a = 5;
printf("%d\n", p); 	// 204
printf("%d\n", &a); // 204
printf("%d\n", &p); // 64
printf("%d\n", *p); // 5
*p = 8;
printf("%d\n", a); 	// 8

结合下图右侧内存模型。首先计算机分配内存地址204-207存储a,第二行定义变量p,变量p是一个 int*类型的变量,其内存地址为64-67(对于32位系统,使用4个字节表示一个内存地址),该变量存储了一个int类型变量的地址,随后&a表示获取了变量a的地址并赋值给变量p,即指针变量p中存储的值为变量a的首地址204

image-20230927220238255

  • 当我们打印p的值时输出为204
  • 当打印a的地址&a时输出为204
  • 当打印p的地址&p时输出为64
  • 当打印变量p的解引用*p时(解引用表示,取出变量p内存储的地址204所存储的变量a)输出为5
  • 当对*p赋值为8后,即修改了变量a的值,此时打印a输出为8。

指针代码示例

image-20231005091543606

示例一:注意初始化

#include <stdio.h>

int main(void)
{
    int a; 	// 未初始化自动变量,存储为垃圾值
    int *p; // 未初始化话指针,直接使用可能会导致程序崩溃
    a = 10;
    p = &a;
    printf("%d\n", p); // 3077992
    printf("%d\n", *p); // 10
    printf("%d\n", &a); // 3077992
	
    return 0;
}

示例二:通过指针变量修改指向对象的值

#include <stdio.h>

int main(void)
{
    int a = 10; 
    int *p; 
    p = &a;
    printf("%d\n", a); // 10
    int b = 12;
    *p = b;
    printf("%d\n", a); // 12
	
    return 0;
}

示例三:指针越界

#include <stdio.h>

int main(void)
{
    int a = 10; 
    int *p; 
    p = &a;
    printf("%d\n", p); // p is 2002(变量a的首地址)
    printf("%d\n", *p); // 10
    printf("size of integer is %d bytes\n", sizeof(int)); // 4个字节
    printf("%d\n", p + 1); // p+1 is 2006(变量a后面下一个int类型变量的首地址)
    printf("%d\n", *(p + 1)); // -858993460, 指针越界
	
    return 0;
}

指针的类型

image-20231005094515955

如上图所示,对于一个整型变量a(见图片右侧中间部分),当赋值1025时,其对应的四个字节200-203存储的二进制数字分别为00000000 00000000 00000100 00000001,如图中标注(小端,字幕标注为LSB)。

最高位为符号位

  • 0代表正数,1代表负数

指针是强类型

  1. 假设p为int*类型,打印p,即200(变量a的首地址)。打印*p,机器认为int为4个字节,按序读取4个字节是数据,结果为1025。
  2. 假设p为char*类型,打印p,即200。打印*p,机器认为char为1个字节,按序读取1个字节是数据,结果为1。
int a = 1025;
int *p;
p = &a;
printf("sizeof of integer is %d bytes\n", sizeof(int)); // 4
printf("Address = %d, value = %d\n", p, *p); // 200, 1025
printf("Address = %d, value = %d\n", p + 1, *(p + 1)); // 204, -2454153

char *p0;
p0 = (char*)p; // 强制类型转换
printf("sizeof of char is %d bytes\n", sizeof(char)); // 1
printf("Address = %d, value = %d\n", p0, *p0); // 200, 1
printf("Address = %d, value = %d\n", p0 + 1, *(p0 + 1)); // 204 4
// 1025 = 00000000 00000000 00000100 00000001
  • (char*)是一种强制类型转换,表示把int*类型变量p强制转换为char*

  • 当打印p时输出为变量a的地址200,当打印*p时输出为变量a的值1025,当打印p+1时输出为变量a下一个int类型变量地址204,当打印*(p+1)时输出为未初始化的随机int类型值比如为-2454153。当打印p0时输出变量a的首个字节的地址200,当打印*p0时输出地址200存储的数值0b00000001(0b表示二进制)即为1,当打印p0+1时输出地址200后一个char类型变量的地址201,当打印*(p0+1)时输出地址201存储的数值0b00000100即为4。

  • 关键:不同类型的指针在解引用时,所读取的字节数于指针所指向的数据类型相关。比如:如果为int*则读取该地址及后面共4个字节存储的数据,指针变量+1则地址数值+4;如果为char*则读取该地址1个字节存储的数据,指针变量+1则地址数值+1,可以通过sizeof关键字确定类型大小。

void指针

#include <stdio.h>

int main(void)
{
    int a = 1025;
    int *p;
    p = &a;
    printf("sizeof of integer is %d bytes\n", sizeof(int));
    printf("Address = %d, value = %d\n", p, *p);
    void *p0;
    p0 = p; // 合法
    //printf("Address = %d, value = %d\n", p0, *p0); // 编译出错,不能打印void*类型指针的值
    // printf("Address = %d, value = %d\n", p0 + 1, *(p0 + 1)); // 出错,void*类型的指针不能进行算术运算
    printf("Address = %d\n", p0); // 合法
    return 0;
}

如上代码所示,无需类型转换,可以将任意类型变量的地址赋值给void*类型指针,但是该类型指针只能打印地址,无法使用解引用*以及+1等运算操作。

指向指针的指针

image-20231005102544578

函数传值

#include <stdio.h>

void Increment(int a)
{
    a = a + 1;
    printf("Address of variable a in increment = %d\n", &a);
}

int main(void)
{
    int a;
    a = 10;
    Increment(a);
    printf("a = %d\n", a); // 10
    printf("Address of variable a in increment = %d\n", &a);
    
    return 0;
}

image-20231005103122898

实参:在主调函数中调用其他函数,这个参数称为实参

形参:被调函中的这个参数,被称为形参

传值调用:本质是把一个变量映射到另外一个变量,一个变量中的值拷贝到另一个函数

传引用

image-20231005105557974

#include <stdio.h>

void Increment(int *p)
{
    *p = (*p) + 1;
}

int main(void)
{
    int a;
    a = 10;
    Increment(a);
    printf("a = %d\n", a); // 11
    return 0;
}

传引用的好处:可以节省更多的内存空间,避免复杂数据类型的拷贝

应用程序内存

image-20231005103435343
  • Code(Text):存储程序指令,计算机需要将指令加载到内存,例如程序中的自增语句
  • Static/Global:存储静态或全局变量
  • Stack:存储局部变量
  • Heap:动态内存

其中前3个段,即代码段、静态/全局变量段和栈段是固定的,在应用程序开始时确定,但是在应用程序运行时,可以要求在堆中分配更多的内存

image-20231005104929608

每个函数都有一个单独的栈帧

  • 执行到Increment函数,暂停主程序,执行Increment函数,为其单独开辟一块栈帧,传进来的a会被拷贝到新的内存中,不能访问自己栈帧之外的变量,执行完成后,清除Increment函数,并且返回主程序继续执行
  • 栈空间在程序开始时确定,假设一个函数无限次调用另一个函数,即无限递归,那么栈将会溢出,程序会崩溃

指针和数组

image-20231005110607613

数组名:指向数组首元素的指针常量(不可修改指向的地址),即数组的基地址

地址:&A[i] == (A +i),二者等价

值:A[i] == *(A + i),二者等价

#include <stdio.h>

int main()
{
    int A[] = {2, 4, 5, 8, 1};
    int i;
    // A++; // 非法,数组名为指针常量
    int *p = A; // 合法
    for(i = 0; i < 5; i++)
    {
        printf("Address = %d\n", &A[i]);
        printf("Address = %d\n", A + i);
        printf("value = %d\n", A[i]);
        printf("value = %d\n", *(A + i));
    }
}
image-20231005111049329

数组作为函数参数

#include <stdio.h>

int SumOFElements(int A[], int size)
{
    int i, sum = 0;
    for(i = 0; i < size; i++)
    {
        sum += A[i];
    }
    return sum;
}

int main(void)
{
    int A[] = {1, 2, 3, 4, 5};
    int size = sizeof(A) / sizeof(A[0]); // 获取数组元素个数
    int total = SumOFElements(A, size);
    printf("Sum of elements = %d\n", total);
}

image-20231005112143746

下面程序在函数内部计算数组大小,结果出错

#include <stdio.h>

int SumOFElements(int A[])
{
    int i, sum = 0;
    int size = sizeof(A) / sizeof(A[0]); 
    printf("SOE - Size of A = %d, size of A[0] = %d", sizeof(A), sizeof(a[0]);
    for(i = 0; i < size; i++)
    {
        sum += A[i];
    }
    return sum;
}

int main(void)
{
    int A[] = {1, 2, 3, 4, 5};
    int total = SumOFElements(A); // 此处传A等价于传&A[0]
    printf("Sum of elements = %d\n", total);
    printf("SOE - Size of A = %d, size of A[0] = %d", sizeof(A), sizeof(a[0]);
}

image-20231005112018995

理想状态下,函数栈帧中的A为一个数组,其中元素和主调函数中的元素相同,占据4个int类型的空间

image-20231005112803763

事实上,编译器看到数组作为参数,不会拷贝整个数组,实际仅仅创建一个同名指针(而不是创建整个数组),指向主调函数的数组首元素的地址,编译器隐式的将int A[]转换为了int *A,即被调函数中的A不是被解释成一个数组,而是解释成一个整型指针

数组名作为参数,仅仅拷贝变量的地址,而不是变量的值,即传引用,防止每次拷贝整个数组浪费大量的内存

image-20231005113026979

指针和字符数组

字符数组以空字符'\0'结束,所以需要预留结尾的空字符的位置

#include <stdio.h>
#include <string.h>

int main(void)
{
    // 方法一
    // char C[5] = {'J', 'O', 'H', 'N', '\0'}; 
    
    /* 方法二
    char C[5];
    C[0] = 'J';
    C[1] = 'O';
    C[2] = 'H';
    C[3] = 'N';
    C[4] = '\0';
    */
    
    // 方法三
    char C[] = "JOHN"; // 自动计算大小
    
    /* 非法,必须写在一行
    char C[20];
    C = "JOHN"; // 出现const char[] 到 char[]的类型转换,不允许const转为非const
    */
    
    int len = strlen(C); // 不会计算末尾的空字符
    printf("Length = %d\n", len);
}

image-20231005170330617

指针和字符数组的不同之处:

  • 字符数组名为指针常量,不允许指向别处

    C1 = C2; // 不允许

    C1++; // 不允许

指针常量和常量指针

const int *c; // 常量指针,只读
int *const c; // 指针常量,不可修改指针指向的地址 

指针和二维数组

image-20231005212006605

int B[2][3];
// B返回一个指向一维数组(其中包含3个整型元素)的指针
int *p = B; // 错误,指针类型不匹配
  1. 打印 B 或 &B[0] // 400, 类型为int (*)[3]

  2. 打印 *B 或 B[0] 或 &B[0][0] // 400, 类型为int

  3. *打印 (B + 1) + 2 或 B[1] + 2 或 &B[1][2] // 412 + 8

    *(B + 1)的类型为int*,+2就是移动到下下个整型类型,跳过8个字节

  4. 打印 * (*B + 1) 或 B[0][1] // 3

image-20231005213807684

指针和多维数组

  • 多维数组本质上就是数组的数组
  • 多维数组可以理解为数组的合集

image-20231005215225387

image-20231005220726668

int C[3][2][2];
int (*p)[2][2] = C;
打印 C  // 800, 类型为 int (*)[2][2]
打印 *C 或 C[0] 或 &C[0][0] // 800,类型为 int (*)[2]

image-20231005222053558

*(C[0][1] + 1) == C[0][1][1]; // 9, C[0][1]类型为int*
*(C[1] + 1) == C[1][1] == &C[1][1][0]; // 824,C[1]类型为int (*)[2]
#include <stdio.h>

int main()
{
    int C[3][2][2] = {{{2, 5}, {7, 9}}, 
                      {{3, 4}, {6, 1}},
                      {{0, 8}, {11, 13}}};
    printf("%d %d %d %d", C, *C, C[0], &C[0][0]);
    printf("%d", *(C[0][0] + 1));
}

image-20231005222724858

多维数组传参

#include <stdio.h>

// 错误的形参
// void Func(int **A) 对二维数组,传一个指针的指针
// void Func(int (*A)[2][2]) 对三位数组,传一个指针的指针的指针
void Func(int (*A)[2][2]) // 数组的第一维可以省略,其他维必须指定
{
    
}

int main()
{
    int C[3][2][2] = {{{2, 5}, {7, 9}}, 
                      {{3, 4}, {6, 1}},
                      {{0, 8}, {11, 13}}};
    int A[2] = {1, 2};
    int B[2][3] = {{2, 4, 6}, {5, 7, 8}};
    /*
    int X[3][2][3]; // 维度不匹配,报错
    Func(X);
    */
    Func(C);
}

指针和动态内存 - 栈 vs 堆

执行square函数

image-20231005224653269

square函数执行完毕,占用的栈上的内存被清除(销毁),进而执行SquareOfSum函数

image-20231005224833517

重复上述步骤,直到栈空

image-20231005224919130

内存在栈上分配和销毁的规则:

  1. 当一个函数被调用,它被压入栈中
  2. 结束时,弹出堆栈

image-20231005225835730

  • 动态内存,对比栈来说,内存大小不固定
  • 没有特定的规则来分配和销毁相应内存
  • 自由分配内存大小,注意不要超出系统内存范围
  • 此处的堆特指“空闲的内存池”(与数据结构中的堆进行区分)
  • 需要手动释放内存空间,否则会导致内存泄漏
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int a; // goes on stack
    int *p;
    p = (int*)malloc(sizeof(int));
    *p = 10;
    free(p); // 释放malloc分配的内存,防止内存泄漏
    p = (int*)malloc(sizeof(int));
    *p = 20;
}

如果malloc找不到空闲的内存块,即不能在堆上成功分配内存,返回NULL

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

int main()
{
    int a; // goes on stack
    int *p;
    p = new int; // new和delete操作符是类型安全的
    *p = 10;
    delete p;
    p = new int[20];
    delete[] p;
}

malloc, calloc, realloc, free

malloc

image-20231006091359765

作用:

  • 在堆中分配内存

函数原型:

void* malloc(size_t size) // size_t可以理解为unsigned int类型

函数用法:

int *p = (int*)malloc(3 * sizeof(int));

calloc

作用:

  • 在堆中分配内存

函数原型:

void* malloc(size_t num, size_t size) // 第一个参数用于指定类型的元素的数量,第二个参数用于指定类型的大小

函数用法:

int *p = (int*)malloc(3, sizeof(int));

malloc和calloc的区别:

  • 使用calloc函数,元素会自动初始化为0
  • 使用malloc函数,元素不会初始化,而是随机值

realloc

作用:

  • 在堆中分配内存

函数原型:

void* malloc(void* Ptr, size_t size) // 第一个参数用于指向已分配内存的起始地址,第二个参数用于指定新内存块的大小

函数用法:

int *p = (int*)malloc(3, sizeof(int));

例子:

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

int main()
{
    int n;
    printf("Enter size of array\n");
    scanf("%d", &n);
    int *A = (int*)malloc(n * sizeof(int));
    for(int i = 0; i < n; i++)
    {
        A[i] = i + 1;
    }
    int *B = (int*)realloc(A, 2*n*sizeof(int));
    printf("Prev block address = %d, new address = %d\n", A, B);
    for(int i = 0; i < 2 * n; i++)
    {
        printf("%d\n", B[i]);
    }
}

image-20231006093340053

动态分配 - 内存泄漏

// "Simple Betting game'
// "Jack Queen King" - computer shuffles these cards
// player has to guess the position of queen.
// if he wins, he takes 3*bet
// if he looses, he looses the bet amount .
// player has $100 initially
#include<stdio.h>
#include<stdlib.h>
int Cash = 100;
void Play(int bet)
{
    /* 方式一:
    char C[3] = {'J', 'Q', 'K'};
    */
    /* 方式二:
    char* C = (char*)malloc(3 * sizeof(char));
    C[0] = 'J'; C[1] = 'Q'; C[2] = 'K';
    */
    printf("Shuffling ...");
    srand(time(NULL));
    int i;
    for(i = 0; i < 5; i++)
    {
        int x = rand() % 3;
        int y = rand() % 3;
        int temp = C[x];
        C[x] = C[y];
        C[y] = temp;
    }
    int PlayerGuess;
    printf("What's the position queen 1, 2, 3");
    scanf("%d", &PlayerGuess);
    if(C[PlayerGuess - 1] == 'Q')
    {
        Cash += 3 * bet;
        printf("You Win ! Result = %c%c%c Total Cash = %d", C[0], C[1], C[2]);
    }
    else
    {
        Cash -= bet;
        printf("You Loose ! Result = %c%c%c Total Cash = %d", C[0], C[1], C[2]);
    }
    free(C); // 回收堆上的内存
}
int main() 
{
    int bet;
    while(cash > 0)
    {
        printf("What's your bet? $");
        scanf("%d", &bet);
        if(bet == 0 || bet > cash) break;
        Play(bet);
        printf("\n****************\n");
    }
}

方式一:函数中的局部变量在栈中分配内存,每次调用会自动回收内存,不会导致内存泄漏

image-20231006101247904

方式二:函数中的局部变量在堆中分配内存,如果不手动释放,每次调用函数都会导致程序占用内存空间增大,即内存泄漏

image-20231006101418284

image-20231006101436434

总结:内存泄漏是因为堆中未使用和未引用的内存块,栈上的内存是自动回收的,栈的大小是固定的,最多发生栈溢出

函数返回指针

函数返回指针常用于:指向堆中分配的内存空间

// Pointers as function returns
#include <stdio.h>
#include <stdlib.h>
void PrintHelloWorld()
{
    printf("Hello World\n");
}
int* Add(int* a, int* b) // 被调函数
{
    int c = (*a) + (*b);
    return &c;
}
int main() // 主调函数
{
    int a = 2, b = 4;
    int* ptr = Add(&a, &b);
    PrintHelloWorld();
    printf("Sum = %d\n", *ptr);
}

image-20231006105821226

修改Add函数

int* Add(int* a, int* b) // 被调函数
{
    int* c = (int*)malloc(sizeof(int)); 
    *c = (*a) + (*b);
    return &c;
}

image-20231006110350288

函数指针

程序执行过程:将源代码作为编译器的输入,再由编译器编译出机器代码

内存:一般指程序运行的上下文

主存:随机存储器RAM

image-20231006112116633

在内存中,一个函数就是一块连续的内存(里面是指令),函数的地址,也称为函数的入口点,是函数的第一条指令的地址

#include <stdio.h>

int Add(int a, int b)
{
    return a + b;
}
int main()
{
    int c;
    int (*p)(int, int); // ()优先级高于*
    /* 方式一
    p = &Add;
    c = (*p)(2, 3);
    */
    // 方式二
    p = Add;
    c = p(2, 3);
    printf("%d", c); // 5
}

错误用法一:

void (*p)(int, int); // 类型不匹配

错误用法二:

int (*p)(int); // 参数个数不匹配

函数指针的使用案例(回调函数)

示例一:

//Function Pointers and callbacks
#include <stdio.h>
void A() 
{
    printf("He1lo");
}

void B(void (*ptr)()) // function pointer as argument
{
    ptr(); //call-back function that "ptr" points to
}

int main()
{
    void (*p)() = A;
	B(p);
}

示例二:

#include <stdio.h>
#include <math.h> // 包含abs函数

int compare(int a, int b)
{
    if(a > b) return 1;
    else return -1;
}

int absolute_compare(int a, int b)
{
    if(abs(a) > abs(b)) return 1;
    else return -1;
}

void BubbleSort(int *A, int n, int (*compare)(int, int))
{
    int i, j, temp;
    for(i = 0; i < n; i++)
        for(j = 0; j < n - 1; j++)
            if(compare(A[j], A[j + 1] > 0) 
                swap(A[j], A[j + 1]);
}

int main()
{
    int i, A[] = {3, 2, 1, 5, 6, 4};
    BubbleSort(A, 6, compare);
    for(i = 0; i < 6; i++) printf("%d ", A[i]);
}

示例三:

#include <stdio.h>
#include <stdlib.h> // 包含qsort函数

int compare(const void* a, const void* b)
{
    // a是一个整型列表,首先需要将通用指针转换为整型指针,再通过*解引用得到a的值
    int A = *((int*)a);
    int B = *((int*)b);
    return A - B; // 升序排列
    // return B - A; 降序排列
}

int main()
{
    int i, A[] = {3, 2, 1, 5, 6, 4};
    qsort(A, 6, sizeof(int), compare);
    for(i = 0; i < 6; i++) printf("%d ", A[i]);
}

指针及其应用

image-20231006143337959

内存是可寻址的字节

  • 内存是一个字节数组
  • 每个字节都有一个唯一的地址(字节可寻址)
  • 寻址的最小数据对象是一个字节
  • 对于ARM Cortex-M微处理器,每个内存地址都有32位,可以寻址4GB

一个对象可能占用多个字节

  • 一个字占4个字节
  • 字分为小端存储和大端存储
    • 以小端格式存储一个字时,最高有效字节存储在高位地址,最低有效字节存储在低地址
    • 以大端格式存储一个字时,最高有效字节存储在低位地址,最低有效字节存储在高地址

指针

  • 指针的值是计算机中存储的某些变量的内存地址

image-20231006143432756

指针加加(假设按照小端序方式存储)

  • 加1,具体是内存地址增加多少,由指针的类型决定

image-20231006143948825

image-20231006144119374

硬编程指针

image-20231006145220218

volatile关键字

image-20231006145332200

  • 强制编译器每次读取新值,而不是从寄存器中读取,防止编译器在编译过程中进行错误的优化

STM32中的GPIO指针

在STM32 Cortex-M处理器的设备头文件中,外设的内存地址被强制转换为指向一个结构体

例如,GPIO端口A的存储器基地址为48000000(十六进制),使用宏指针将此地址转换为指针,该指针可以指向GPIO类型的结构体,即可通过结构体,软件可以轻松访问外设的所有寄存器

标签:int,void,深入浅出,内存,printf,include,指针
From: https://www.cnblogs.com/General-xd/p/18312149

相关文章

  • C++ 智能指针
    一、为什么需要智能指针看如下代码有什么问题:intdiv(){ inta,b; cin>>a>>b; if(b==0) throwinvalid_argument("除0错误"); returna/b;}voidFunc(){ //1、如果p1这里new抛异常会如何? //2、如果p2这里new抛异常会如何? //3、如果div调用这里又......
  • 15 指针 · 其三 · 进阶
    目录一、字符指针变量(一)字符指针与字符串数组区别二、数组指针变量(一)数组指针介绍(二)数组指针初始化(三)数组指针的使用三、二维数组传参的本质四、函数指针变量(一)函数指针介绍1、函数的地址2、函数指针的写法(二)函数指针的使用(三)两段有趣的代码(四)typedef五、函数......
  • C/C++ 《二级指针浅拷贝》
    背景A对象内部属性a属于int,动态分配内存回收,析构函数deleteA**aptr=newA[10]申请10个空间长度的A*类型测试浅拷贝测试代码#include<iostream>usingnamespacestd;classA{public:int*a;A(inti){//构造函数a=newint(i);}~A(......
  • C++ 智能指针简单实现
    #pragmaoncetemplate<typenameTR>classjoker_shared_ptr{private:TR*ptr;size_t*count;public:constexprjoker_shared_ptr(/*args*/)noexcept{}constexprjoker_shared_ptr(std::nullptr_t)noexcept{}explicitjoker_sha......
  • C++(指针函数、函数指针)
    目录1.指针函数2.函数指针3.区别总结在C++中,指针函数和函数指针是两个不同的概念,尽管它们的名字非常相似。以下是详细的介绍和区别:1.指针函数指针函数(Pointertoafunction)是返回类型为指针的函数。它的返回值是一个指向某种数据类型的指针。以下是一个示例:int*get......
  • C语言指针笔记
    该笔记整理自阮一峰老师的《C语言教程》和部分网上资料什么是指针指针就是一个代表某个内存地址的值声明和初始化指针变量inta=10;//声明一个指针变量p,并将a的地址赋给pint*p=&a;//输出p的值(地址值)printf("%p",p);//输出p所指向的值printf("%d",*p);这......
  • c++ primer plus 第16章string 类和标准模板库,16.2.1 使用智能指针
    c++primerplus第16章string类和标准模板库,16.2.1使用智能指针c++primerplus第16章string类和标准模板库,16.2.1使用智能指针文章目录c++primerplus第16章string类和标准模板库,16.2.1使用智能指针16.2.3uniqueptr为何优于autoptr16.2.3unique......
  • c++ primer plus 第16章string 类和标准模板库,16.2.2 有关智能指针的注意事项
    c++primerplus第16章string类和标准模板库,16.2.2有关智能指针的注意事项c++primerplus第16章string类和标准模板库,16.2.2有关智能指针的注意事项文章目录c++primerplus第16章string类和标准模板库,16.2.2有关智能指针的注意事项16.2.2有关智能指针的......
  • C语言 指针方法 输入10个整数,将其中最小的数与第一个数对换,把最大的数与最后一个数对
    输入10个整数,将其中最小的数与第一个数对换,把最大的数与最后一个数对换。写3个函数:第一个:输入10个数;第二个:进行处理;第三个:输出10个数。#include<stdio.h>voidinputNumbers(int*arr){printf("Enter10integers:");for(inti=0;i<10;i++){......
  • C语言 指针方法 输入3个整数,按由小到大的顺序输出
    输入3个整数,按由小到大的顺序输出#include<stdio.h>voidsortIntegers(int*a,int*b,int*c){if(*a>*b){inttemp=*a;*a=*b;*b=temp;}if(*a>*c){inttemp=*a;*a=*c;*c=temp......