指针基础部分

1指针基础

1.1,指针的概念

C语言里,变量存放在内存中,而内存其实就是一组有序字节组成的数组,每个字节有唯一的内存地址。在这里,数据对象是指存储在内存中的一个指定数据类型的数值或字符串,它们都有一个自己的地址,而指针便是保存这个地址的变量。也就是说:指针是一种保存变量地址的变量

这是一个 4GB 的内存,可以存放 2^32 个字节的数据。左侧的连续的十六进制编号就是内存地址,每个内存地址对应一个字节的内存空间。而指针变量保存的就是这个编号,也即内存地址。

1.2,获取变量的地址

  • 普通变量地址: &变量名

  • 一维数组首地址: 数组名或者&数组名[0]

  • 函数地址: 函数名或者&函数名

int Max(int a, int b) 
{
  return a > b ? a : b;
}
int main() 
{
  int inum = 1;
  int array[3] = { 1,2,3 };
  printf("&inum=%p\n", &inum);
  printf("array=%p\t&array[0]=%p\n", array, &array[0]);
  printf("Max=%p\t&Max=%p\n", Max, &Max);
  return 0;
}

1.3,声明指针

  • 类型* 标识符

  • int* p1;
    char* p2;
    double* p3;
    //64位占用8个字节
    //32位占用4个字节
    printf("p1=%zd\tp2=%zd\tp3=%zd\n",sizeof(p1),sizeof(p2),sizeof(p3));
    //不同类型基本指针占用的内存是一样的

int arr[4]={1,2,3,4};
printf("array:%zd\n",sizeof(arr));//打印的实际结果是数组的占用字节数
printf("arr=%p\t&arr[0]=%p",arr,&arr[0]);//打印的值一样,但是含义是不同的
//数组名可以隐式转化为指针,但并不是真正的指针

1.4,指针的常见状态

int* p1;
char* p2;
double* p3;//不知道指向哪里
//NULL 是 (void*)0 
p1 = NULL ;
P2 = NULL ;
P3 = NULL ;
int* pp = NULL;//指向空,即赋予pp地址为0
printf("p1=%p",p1);//打印结果是0x000000000000(十六进制下的零)   

1.5,常见运算

指针的类型-->去掉变量名

指针所指向的类型-->去掉变量名和*号

//指针变量的指针取值
//*指针变量 指针变量[0](取星号,取下标)
int num = 666;
int* pnum = #
printf("%d\t%d\t%d\n",num,*pnum,pnum[0]);
// p+n 或者 p-n (指针的偏移)
//int* p
//指针的类型int*
//指针所指向的类型int-->操作数据的类型要一致
int* p1;
char* p2;
double* p3;
printf("p1=%p\tp2=%p\tp3=%p\n",p1,p2,p3);
printf("p1=%p\tp2=%p\tp3=%p\n",p1+1,p2+1,p3+1);
//int 偏移1个,加4个字节 
//char 偏移1个,加一个字节
//double 偏移1个,加8个字节
int arr[2]={1,2};
printf("arr=%p\tarr+1=%p\n",arr,arr+1);
int(*p)[3]= NULL;
printf("p=%p\n",p);//int[3]
printf("p=%p\n",p+1);//int [3]+1,一次偏移3个int类型的字节

1.6,二级指针与多级指针


int num = 0;
int* p1 = # 
int** p2 = &p1;
int*** p3 = &p2;
//十级指针存放九级指针的地址
printf("%d\n",***p3);
printf("%d\n",p3[0][0][0]);
//取值运算,几级指针就取几次星号

2,const与指针变量

const int num1 = 1 ;
int const num2 = 2 ;//确定常量num1就是1,后续不能更改
//以下两种写法没区别
//指针变量,可以更改值
//const修改的的是指针所指向的内容
const int* p1 = &num1;
int const* p2 = &num2;
int data = 0 ;
p1 = &data;
pi = p2;
//不能修改,因为const修饰的是p3;
int* const p3 = &data;
const int* const p4 = &data ;

3,指针操作一维数组

int array[4] = {1,2,3,4};
int* p = array;
p = &array[0];
for(int i = 0; i < 4 : i++ )
{
    printf("%d",p[i]);//推荐
    printf("%d",(p+i)[0]);
    printf("%d",*(p+i));
}
printf("\n");
//指针遍历数组
while( p! = array+4 )
{
    printf("%d\t",p++[0]);
}
printf("\n");
//下面指针打印结果如下
int data[10] = {1,2,3,4,5,6,7,8,9,10}
int* pp = &data[5];//数组里的第6个数字赋值给指针pp,作为指针的首地址
printf("%d\n",pp[0]);
for(int i = -4;i < 0 ;i++ )
{
    printf("%d\t",pp[i]);
}

//下面两个效果是一样的
void print_array(int array[],int arraynum)
{
    for(int i = 0; i<arraynum ; i++ )
    {
        printf("%d\t",array[i]);
    }
    printf("\n");
}
void print_array2(int *array,int arraynum)
{
    for(int i = 0; i<arraynum ; i++ )
    {
        printf("%d\t",array[i]);
    }
    printf("\n");
}
int my_strlen(const char* str)//一定要写const
{
    int count = 0;
    while(str[count]!='\0')
        count++;
    return count;
}

4,指针操作二维数组

void tese_one()
{
    int array[12] = {1,2,3,4,5,6,7,8,9,10,11,12}
    int* p =&array[0][0];
    for(int i = 0 ; i<3 ; i++ )
    {
        for(int j = 0 ; j<4; j++ )
        {
            printf("%d\t", p[i*4+j] );
        }
    }
}
void test_two() 
{
    int array[3][4] = { 1,2,3,4,5,6,7,8,9,10,12 };
    //二维数组名偏移的一行
    printf("array:%p\n", array);
    printf("array+1:%p\n", array+1);  //16
    //二维数组名+一个下标 转换为一个一级指针
    printf("array[0]:%p\n", array[0]);
    printf("array[0]+1:%p\n", array[0]+1); //4;
​
    //推荐用法
    //数组指针操作二维数组
    int(*p)[4] = array;
    for (int i = 0; i < 3; i++) 
    {
        for (int j = 0; j < 4; j++) 
        {
            printf("%d\t", p[i][j]);
        }
        printf("\n");
    }
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            printf("%d\t", *(*(p+i)+j));
            //p[i]==>A  A[j]==>*(A+j)
            //p[i]==>*(p+i)==>A
        }
        printf("\n");
    }
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            printf("%d\t", *(p[i] + j));
            //p[i]==>A  A[j]==>*(A+j)
            //p[i]==>A
        }
        printf("\n");
    }
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            printf("%d\t", ((p + i)[0] + j)[0]);
            //p[i]==>A  A[j]==>*(A+j)==>(A+j)[0]
            //p[i]==>(p+i)[0]==>A
        }
        printf("\n");
    }
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            printf("%d\t", (p[i] + j)[0]);
            //p[i]==>A  A[j]==>*(A+j)==>(A+j)[0]
            //p[i]==>(p+i)[0]==>A
        }
        printf("\n");
    }
}

5,万能指针 (void* p = NULL)

void* p = NULL;//可以存储任何类型的数据
int num = 999;
p = &num;
printf("%d\n",*(int *)p);//万能指针使用:数据访问的时候要做目标数据的强制转换
double dnum = 8.98;
p = &pnum;
printf("%0.2lf\n",*(double *)p);

6,指针函数

函数里用到指针

//传指针的问题(所以的传参方式都是赋值)
void modify_one(int a)
{
    a = 100;
}
void modify_two(int* p)//修改实参值,传入实参地址,修改的是(*地址)
{
    *p = 100;
}
int g_num = 999;
void modify_three(int** p)//地址传递
{
    *p = &g_num;//对应的是*p的值,对这个值进行修改,*p是g_num的地址。p指向g_num
}
int main()
{
    int num = 0;
    modify_one(num);
    printf("%d\n",num);//函数的内存和和实参的内存不一样,只能进行拷贝操作,无法完成赋值操作,传进来的是a = 0,无法进行赋值
    modify_two(&num);
    printf("%d\n", num);//传进来的是num的地址,通过这种方式寻址,通过地址进行值的修改
    int* p = &num;
    modify_three(&p);//传进来的是p的地址,p本身就是指针变量,对其取址的值
    printf("%d\n", *p);
    *get_one(p)=199;
    return 0;
}
//返回指针问题,C语言不允许返回局部变量或者临时变量的地址,使用一次函数后函数内存会被释放掉
int get_one(int* p)
{
    return p;
}//传参进来后,值仍然存在
//返回一个数组函数,返回数组首地址就可以了
int array[3] = {1,2,3};
int* get_array()
{
    return array;
}

#

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值