龙空技术网

C语言基础之指针

o一城烟雨o 44

前言:

而今大家对“指针取地址和取值”可能比较看重,小伙伴们都需要分析一些“指针取地址和取值”的相关资讯。那么小编在网上汇集了一些对于“指针取地址和取值””的相关资讯,希望朋友们能喜欢,你们一起来学习一下吧!

概述

系统为内存的每一个字节 分配一个32位的地址编号

指针 就是内存的编号

指针变量:本质是变量 只是该变量 保存的是内存的地址编号(不是普通的数值)

&为变量取地址

1、指针变量的定义(1)指针的定义

int num = 20;

p为20的内存地址即&num

*p = 20

p = &num

注意:如果对num的地址取地址,即**q == *p == 20,那么 * q == p == &num

(2)定义步骤

*修饰指针变量名( * p)

保存谁的地址 就先定义谁。

1 定义一个指针变量p 保存 int num的地址; int *p;

2 定义一个指针变量p 保存数组int arr[5]首地址; int (*p)[5]

3 定义一个指针变量p 保存函数的入口地址 int fun(int,int); int (*p)(int,int);

4 定义一个指针变量p 保存结构体变量的地址 struct stu lucy; struct stu *p;

5 定义一个指针变量p 保存指针变量int *p的地址 int **p

(3)指针变量的详解

在32位平台任何类型的指针变量 都是4字节

在64位平台任何类型的指针变量 都是8字节

p等价于&num

*p等价于num的值 表示取p保存的地址编号的内容

(4)指针使用

    int num = 10;    int *p = NULL;//定义一个指针    p = & num;
(5)指针的指针
int num = 10;int *p = #int **q = &p;

n级指针变量 可以保存 n-1级的地址

*p---->num

**q---->num

2、指针变量的初始化

(1)指针变量在操作之前必须指向合法地址空间,指针变量如果不初始化 立即操作 会出现段错误

(2)指针变量如果没有指向合法空间 建议初始化为NULL

    int *p = NULL;

(3)将指针地址变量初始化为合法地址(变量地址、动态申请的地址、函数入口地址)

int num = 10;

int *p = & num;

等价于

int num = 10, *p = & num;

3、指针变量类型(1)指针变量自身的类型

指针变量自身的类型 一般用于赋值语句的判断

char *p ---->char *

int *p ---->int *

short *p ---->short *

float *p ---->float *

double *p ---->double *

long *p ---->long *

void test() { int num = 10; int *p = # //在使用中 //num 为int &num 为int * ‐‐‐‐>对变量名 取地址 整体类型加一个* //p 为int * *p 为int ‐‐‐‐>对指针变量 取* 整体类型减一个*  //在使用中 &和*相遇 从右往左 依次抵消  *&p == p  } 
(2)指针变量指向的类型

指针类型指向类型决定取值宽度

char *p ----->char 1B

int *p ----->int 4B

short *p ---->short 2B

float *p ---->float 4B

double *p ---->double 8B

long *p ---->long 4B

案例:

定义一个变量 num = 0x01020304 ,取出其中的02(内容的存取是倒着存倒着取)

#include <stdio.h>int main(int argc, char const *argv[]){    int num = 0x01020304;    char *p = (char *)#    printf(“%#x\n”,*(p+2));    return 0;}

取出0203

#include <stdio.h>int main(int argc, char const *argv[]){    int num = 0x01020304;    char *p = (char *)#    printf(“%#x\n”,*(short *)(p+1));    return 0;}
(3)*p等价于num
#include <stdio.h>int main(int argc, char const *argv[]){    int num = 0;    int *p = #        scanf("%d",p);    printf("num=%d\n",num);    *p = 10;    printf("num=%d\n",num);    (*p)++;    printf("num=%d\n",num);    return 0;}
(4)指针变量的注意事项①void不能定义普通变量

void num;错误

②void *可以定义指针

    void *p;//可以定义

p自身类型为void *,在32为平台任意类型的指针 为4B那么系统知道P开辟4B空间,所以定义成功

p就是万能的一级指针变量,可保存任何一级指针地址

万能指针一般用于函数的形参 达到算法操作多种数据类型的目的

注:不要直接对void p的指针变量 取

int num = 10;

void *p = & num;

*p;//错误 p指向的类型为void 无法确定p的取值宽度

对p取*之前对p先进行指针类型强转

强转*(int *)p

#include <stdio.h>int main(int argc, char const *argv[]){    int num = 10;    void *p = #    //*p;错误    printf("%d",*(int *)p);//使用前进行强转}
③指针变量 未初始化 不要取*
    int *p = NULL;    *p;错误
④指针变量不要越界访问
#include <stdio.h>int main(int argc, char const *argv[]){    int arr[5] = {1,2,3,4,5};    int *p = arr;    printf(“%d\n”,*(p+6));//越界    return 0;}
⑤数组元素的指针变量

p = &arr[0];取第0个元素地址

p = arr;取数组首地址 等价于第0个元素地址

#include <stdio.h>int main(int argc, char const *argv[]){    int arr[5] = {1,2,3,4,5};    int n = sizeof(arr)/sizeof(arr[0]);    int i = 0;    for(i=0;i<n;i++)//遍历数组    {        printf("%d",arr[i]);    }    int *p = arr;        for(i=0;i<n;i++)//遍历数组    {        printf("%d",*(p+i));    }    for(i=0;i<n;i++)//遍历数组    {        printf("%d",*(arr+i));    }    return 0;}
⑥在使用中 [] 就是 *() 的缩写

[]是* ()的缩写 []左边的值放在+的左边 []里面的值 放在+右边 整体取*

arr[6] == *(arr+6)

arr[ 5 ] [ 6 ] == * (arr[5] + 6) ==* ( * (arr + 5 ) + 6)

#include <stdio.h>int main(int argc, char const *argv[]){    int arr[5] = {1,2,3,4,5,7,8,9};    int n = sizeof(arr)/sizeof(arr[0]);        printf("%d\n",arr[6]);    printf("%d\n",*(arr+6));}

& arr[0] == & *(arr+0) == arr+0 == arr

⑦扩展

指向同一数组,两指针变量相减 等于他们间的元素个数

        int *p1 =arr;  int *p2 = arr+4;        p2-p1=4;

两指针变量赋值= p2=p1它们指向同一处

两指针变量判断相等 == p2==p1 他们是否相等

两指针变量判断大小 > < >= <= !=

p1>p2 p1!=p2判断位置关系

两指针不能相加(重要)

4、指针数组

指针数组:本质是数组 只是数组的每个元素为 指针。

(1)数值的指针数组

#include <stdio.h>int main(int argc, char const *argv[]){    int num1 = 1;    int num2 = 2;    int num3 = 3;    int num4 = 4;    int *arr[5] = {&num1, &num2, &num3, &num4};    int n = sizeof(arr)/sizeof(arr[0]);    int i = 0;    for (i = 0; i < n; i++)    {        printf("%d\n",*arr[i]);    }    return 0;}
(2)字符的指针数组
#include <stdio.h>int main(int argc, char const *argv[]){    char *str[] = {"haha","lala","xixi","hehe"};    int n = sizeof(str)/sizeof(str[0]);    int i = 0;    for (i = 0; i < n; i++)    {        printf("%s\n",str[i]);    }    return 0;}

字符串存放在文字常量区,数组内是每个字符串的地址,存放在栈区或全局区

(3)二维字符数组

char *arr1[4]={"hehe", "xixi", "lala", "haha"};char arr2[4][128]={"hehe", "xixi", "lala", "haha"};

arr1是在指针数组 存放的是每个字符串的首元素的地址

arr2是二维字符数组 存放的是每个字符串

5、数组指针

数组指针本质是指针变量保存的是数组的首地址。

(1)数组元素地址 和 数组首地址

数组首元素地址:&arr[0] == arr ,+1跳过一个元素

数组的首地址:&arr ,+1跳过整个数组

数组元素地址与数组首地址相等

(2)int (*p)[5] = NULL; 数组指针

    int arr[5] = {1,2,3,4,5};    int (*p)[5] = &arr;

访问第3个元素

arr[2] == *(arr+2) == * ( * p+2) == * ( * (p+0)+2) ==*(p[0]+2) ==p [ 0 ] [ 2 ]

#include <stdio.h>int main(int argc, char const *argv[]){    int arr[5] = {1,2,3,4,5};    int (*p)[5] = &arr;    printf("%d\n",arr[2]);    printf("%d\n",*(arr+2));    printf("%d\n",*(*p+2));    printf("%d\n",*(*(p+0)+2));    printf("%d\n",*(p[0]+2));    printf("%d\n",p [0][2]);    return 0;}
(6)总结

int *arr[5];//指针数组 本质是数组 每个元素为int *

int (*arr)[5];//数组指针 本质是指针变量 保存的是数组的首地址(该数组必须5个元素

每个元素为int)

6、二维数组和数组指针的关系

int arr[5][5] =     {{1,2,3,4,5},{6,7.8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25}};

arr既是数组的地址也是数组首元素地址

arr+1表示第二行地址

示例:

arr[1] => *(arr+1) 第一行第0列的列地址&arr[1] => &*(arr+1)=>arr+1 第1行的行地址*arr+1 => 第0行第1列的列地址arr[1]+2 =>*(arr+1)+2 =>第1行第2列的列地址**arr ==*(*(arr+0)+0) == arr[0][0]

案例:访问第19个元素

#include <stdio.h>int main(int argc, char const *argv[]){    int arr[5][5] = {{1,2,3,4,5},{6,7.8,9,10},{11,12,13,14,15},                 {16,17,18,19,20},{21,22,23,24,25}};    printf("%d\n",arr[3][4]);    printf("%d\n",*(*(arr+3)+4));    printf("%d\n",*(arr[3]+4));    return 0;}
7、多维数组的物理存储

不管几维数组在物理上 都是一维存储

将二维数组当成一维数组访问

#include <stdio.h>int main(int argc, char const *argv[]){    int arr[5][5] = {{1,2,3,4,5},{6,7.8,9,10},{11,12,13,14,15},                     {16,17,18,19,20},{21,22,23,24,25}};    int row = sizeof(arr)/sizeof(arr[0]);    int col = sizeof(arr[0])/sizeof(arr[0][0]);    int *p = &arr[0][0];    int i = 0;    for (i = 0; i < row * col; i++)    {        printf("%d ",p[i]);    }    printf("\n");    return 0;}
8、指针作为函数参数(1)指针变量作为函数的参数

如果直接将变量的值传递到函数内部修改不能改变变量的值。

int a = 1;int b = 2;void my_swap(int x, int y){    int tmp = a;    a = b;    b = tmp;}my_swap(a,b);//此代码不能交换a,b的值

如果想在函数内部修改外部变量的值 需要将外部变量的地址 传递给函数。

#include <stdio.h>void set_num(int *d){    *d=100;    return;}int main(int argc, char const *argv[]){    int num = 0;    set_num(&num);    printf("num = %d\n",num);    return 0;}
(2)数组作为函数的参数

函数内部想操作外部数组元素,将数组名传递给函数。

#include <stdio.h>void printf_int_array(int *p,int n){    printf("sizeof(arr)=%lu\n",sizeof(p));//首元素地址大小8B    printf("arr[2]=%d\n",p[2]);}int main(int argc, char const *argv[]){    int arr[4] = {2,3,4,5};    int n = sizeof(arr)/sizeof(arr[0]);    printf("sizeof(arr)=%lu\n",sizeof(arr));//数组大小4*4B    printf_int_array(arr,n);    return 0;}

案例:键盘输入数组,输出最大值最小值(指针数组作为函数)

#include <stdio.h>void input_int_array(int *p,int n){    printf("请输入%d个int数据:",n);    int i = 0;    for ( i = 0; i < n; i++)    {        scanf("%d",p+i);    }}void get_max_min(int *p,int *max_array,int *min_array,int n){    int max= p[0],min = p[0];    int i = 0;    for ( i = 0; i < n; i++)    {        if (max < p[i])        {            max = p[i];        }        if (min > p[i])        {            min = p[i];        }        *max_array = max;        *min_array = min;    }    return;}int main(int argc, char const *argv[]){    int arr[5] = {0};    int n = sizeof(arr)/sizeof(arr[0]);    int max=0,min=0;    input_int_array(arr,n);//键盘输入    get_max_min(arr,&max,&min,n);    printf("max=%d \nmin=%d\n",max,min);    return 0;}
(3)二维数组作为函数的参数

函数内部 想操作 函数外部的二维数组 需要将二维数组名 传递给函数。

#include <stdio.h>void look_array(int (*p)[4],int row,int col){    int i=0,j=0;    for ( i = 0; i < row; i++)    {        for ( j = 0; j < col; j++)        {            printf("%d ",p[i][j]);        }        printf("\n");    } }int main(int argc, char const *argv[]){    int arr[3][4] = {{1,2,3,4},{2,5,6,34},{4,8,9,2}};    int row = sizeof(arr)/sizeof(arr[0]);    int col = sizeof(arr[0])/sizeof(arr[0][0]);     look_array(arr,row,col);    return 0;}
(4)函数的返回值类型为指针类型

将函数内部的合法地址 通过返回值 返回给函数外部使用

注意:函数不要返回 普通局部变量的地址

#include <stdio.h>int* get_add(void){    static int data = 10;//静态局部变量,作用于整个进程    return &data;}int main(int argc, char const *argv[]){    int *p;    p = get_add();    printf("%d\n",*p);    return 0;}
(5)函数指针作为指针类型

函数名 代表函数的入口地址;

函数指针:本质是一个指针变量 只是该变量 保存的是函数的入口地址

函数指针p只能保存 有两个int形参以及int返回值 的函数入口地址

int (*p)(int ,int) = NULL;

#include <stdio.h>int my_add(int x,int y){    return x + y;}int main(int argc, char const *argv[]){    int (*p)(int ,int);    p = my_add;    printf("%d\n",p(10,20));    return 0;}
9、总结

数值指针:

  int num = 10;  int *p = NULL;

p = #

p = #

*p = num;

*p + 1 ==num + 1

一维指针数组:

  int arr[4] = {1,6,9,3};  int *p = NULL;  p = arr;

p = arr; //数组名等价于元素首地址

p =arr =*(arr+0)= arr[0];

p+1 =arr+1==arr[0]+1;

(p+1) =(arr+1)==arr[1];

arr+1 //第1个元素地址

一维数组指针:

  int arr[4] = {12,45,2,78};  int (*p)[4] = NULL;  p = &arr;

p = &arr;

p //第0个元素地址,数组首地址

p+1 //跳过整个数组,跳过的地址为数组元素个数*一个数组所占字节

arr //第0个元素地址

arr+1 //第1个元素地址

*(arr+1) //第1个元素

二位指针数组:

  int arr[3][4] = {{2,6,3,8},{0,12,6,89},{12,35,98,36}};  int *p = NULL;  p = &arr[0][0];

p //首元素地址

p+1 //第1个元素地址

(p+1) //第0行第1个元素(*(p+0)+1)

arr //首元素地址

*arr //首元素地址

*arr+1 //第1个元素地址

(arr+1)//跳到下一行,跳过的地址为第一行元素个数一个元素所占字节

arr+1 //跳到下一行,跳过的地址为第一行元素个数*一个元素所占字节

arr[1] //第1行元素首地址

arr[1]+3 //第1行第3列地址

二位数组指针:

 int arr[3][4] = {{2,6,3,8},{0,12,6,89},{12,35,98,36}};  int (*p)[4] = NULL;  p = arr;

p , arr //首行地址

p+1 , arr+1 //第1行地址

*p+1 , *arr+1 //第1个元素地址

*(p+1) , *(arr+1) //第1行地址

arr[1] , p[1] //第1行地址

arr[1]+1 , p[1]+1 //第1行第1列地址

*arr[1] , * p[1] //第1行第0列元素

*arr[1]+1 , *p[1]+1 //第1行第0列元素+1

*(arr[1]+1) , *(p[1]+1) //第1行第1列元素

10、如有错误欢迎指正

标签: #指针取地址和取值