首页 > 其他分享 >c语言期末复习----指针

c语言期末复习----指针

时间:2024-12-26 09:30:52浏览次数:5  
标签:复习 ++ ---- int 地址 数组 printf 指针

一、指针基础知识

1指针概念:指针是一个值为内存地址的变量

2格式:指针在使用前一定要有明确指向(初始化)

1)先声明再初始化 

2)声明的同时初始化

 int a,*p=&a;

注:关于指针p的三个相关的值

1) p,p里面存放着一个地址

2)*p,p指向的对象的值

3)&p,表示变量p本身的地址

3*的作用

1)定义指针变量的标志

2)解引用,去内容(间接访问操作符)

4指针的大小

指针的大小和类型是无关的,指针类型的变量在相同的平台下大小都是相同的

x86环境(32位平台)地址是32个bit位(4个字节),指针变量的大小是4个字节

x64环境(64位平台)地址是64个bit位(8个字节),指针变量的大小是8个字节

5指针变量类型的意义

1)指针类型决定对指针解引用操作能有多大的权限(一次能操作几个字节)

例如,char*的指针解引用访问1个字节,int*的指针解引用访问4个字节

2)指针类型决定指针向前(后)走一步有多大距离

sizeof()

例如,char*类型指针+1跳过1个字节,int*类型指针+1跳过4个字节

6void*指针

void*类型指针可以用来接受任意类型的地址

但void型指针不能直接进行指针的+-整数和解引用的运算

7指针运算

1)指针+-整数:偏移

2)指针-指针:前提条件,相距元素个数

3)指针比较运算:地址值大小比较

8指针的传址调用

9二级指针 

存放指针变量的地址

 *ppa=&b//等价于pa=&b,*ppa访问的是pa

**ppa=30//等价于*pa=30,即a=30 

总结:int a,*p=&a,**pp=&p;

若pp是二级指针,*pp等价一级指针p,**pp等价*p等价于a

 

二、指针与数组 

1数组名就是数组首元素地址(除2个例外

例外:

1)sizeof(数组名)这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节

2)&数组名,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)

注:整个数组的地址和首元素地址的值在数值上通常是一样的,但二者的含义不同,所代表的类型也不同,首元素地址类型为对应元素类型的指针(比如对于 int 数组就是 int * 类型),而整个数组地址的类型是数组类型的指针(例如对于 int[5] 数组就是 int (*)[5] 类型)。

二维数组的数组名a是行地址,a+i指向第i行,a[i]是第i行首元素的地址,不是元素的引用

2使用指针访问数组

 3指针数组和数组指针

1)指针数组:存放指针类型的数组,相当于一次性声明多个指针

int* p[n]; 

2)数组指针:指向的是数组

 int(*p)[n];

a[3][2]中,a实质上就是一个数组指针

4一维数组与指针

1)指向一维数组定义格式:

int a[10],*p=a;
int a[10],*p=&a[0];

 2)注意事项

//数组名本身表示数组的首地址,是常量而不是变量,不能对数组名进行自增自减或赋值运算

//*p++和*(p++)等价【*和++同优先等级,右结合性;运算符从右往左计算】

 *p++*(p++) 在行为上是完全相同的,两者都先返回指针当前指向的值,然后递增指针。

#include <stdio.h>

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

    // 使用 *p++
    printf("Value: %d\n", *p++);  // 输出 1
    printf("Next value: %d\n", *p);  // 输出 2

    // 重置指针
    p = arr;

    // 使用 *(p++)
    printf("Value: %d\n", *(p++));  // 输出 1
    printf("Next value: %d\n", *p);  // 输出 2

    return 0;
}

//*(p++)和*( ++p)不等价

*(p++):先解引用当前的 p,然后递增 p。
*(++p):先递增 p,然后解引用新的 p。

#include <stdio.h>

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

    printf("Using p++:\n");
    printf("Value: %d\n", *(p++));  // 输出 1
    printf("Next value: %d\n", *p); // 输出 2

    // 重置指针
    p = arr;

    printf("\nUsing ++p:\n");
    printf("Value: %d\n", *(++p));  // 输出 2
    printf("Current value: %d\n", *p); // 输出 2

    return 0;
}

//(*p)++和*(p++)不等价

 (*p)++:先解引用 p 获取其指向的值,然后递增该值。指针 p 本身没有变化
*(p++):先解引用 p 当前指向的地址,获取该地址处的值,然后递增指针 p。被解引用的值不会改变,只是指针 p 移动到了下一个位置

#include <stdio.h>

int main() {
    int arr[] = { 10, 20, 30 };
    int* p = arr;

    printf("Using (*p)++:\n");
    printf("Value before: %d\n", *p); // 输出 10
    printf("Value after (*p)++: %d\n", (*p)++); // 输出 10 (后增++是返回递增前的值)
    printf("Final value: %d\n", *p); // 输出 11 (实际值已递增)
    printf("数组首元素现在的值是%d", arr[0]);//输出11
    // 重置指针
    p = arr;

    printf("\nUsing *(p++):\n");
    printf("Value before: %d\n", *p); // 输出 11【上面实际值已递增带来的影响】
    printf("Value after *(p++): %d\n", *(p++)); // 输出 11 (解引用当前地址)
    printf("Next value: %d\n", *p); // 输出 20 (指针已递增)


    return 0;
}

 3)一维数组元素输入输出

指针移动法

请注意第二个for循环要重置指针让它指到a,因为在第一个 for 循环结束后,p 已经指向 a + 10,即数组 a 的末尾。如果不加上p=a则第二个 for 循环的条件 p < a + 10 永远为假,循环体不会执行。

5二维数组与指针 

1)指向二维数组定义格式:

int a[3][4],*p;
p=&a[0][0];
或者
p=a[0];

2)行指针:指向行数组的指针变量

int a[3][4];
int (*p)[4]=a;

行指针p被赋予a后,p可以当作二维数组名p[i][j]使用

3)二维数组的元素地址

二维数组a[m][n]中:

元素a[i][j]的几种表示形式

//&a[i][j]

//a[0]+n(具体看几列)*i+j【依赖于数组的实际布局。

//a[i]+j

//*(*(a + i) + j)

*(a + i):解引用 a + i,得到第 i 行的地址。

【二维数组中a[i]表示第i行首元素的地址】

*(a + i) + j:将第 i 行的指针向前移动 j 个位置,指向第 i 行第 j 列元素。

*(*(a + i) + j):最终解引用 *(a + i) + j,得到第 i 行第 j 列的元素值。

三、函数与指针(主要是函数参数传递)

传数组xx xxx(int *arr)或者xx xxx(int arr[])

四、字符串与指针

1字符指针变量

char *str2="abc";

定义一个字符型指针变量,占用1个指针型存储单元,另分配4个连续的字符型存储单元存放“abc”,其首地址存放在指针变量str2中 

2字符指针数组和二维字符数组

 

标签:复习,++,----,int,地址,数组,printf,指针
From: https://blog.csdn.net/2401_86517033/article/details/144625646

相关文章

  • linux中redis服务搭建
    1.redis基础 1.redis介绍 1.键值对存储数据 2.将数据存储在内存,减少对后端的频繁请求,支持数据持久化存储,默认16个库,从0-15 2.专业术语 1.redis雪崩:redis集群缓存的大量key过期或者失效 解决:过期时间+随机数 2.redis击穿:某一个特别热点的key过期 ......
  • css权重优先级用来做什么的?
    CSS权重优先级在前端开发中起着至关重要的作用,它决定了当多个样式规则应用于同一个HTML元素时,哪个规则将最终生效。通过合理地设置权重优先级,开发者可以更加精确地控制页面的样式表现。以下是关于CSS权重优先级作用的详细解释:解决样式冲突:在复杂的网页中,同一个元素可能被多个CS......
  • 乐观锁,悲观锁
    乐观锁和悲观锁是两种常见的并发控制机制,主要用于解决并发操作中的数据一致性问题。它们的应用场景和实现方式各有特点:1.乐观锁定义:乐观锁基于乐观的并发控制思想,假设事务间的冲突概率较低,因此不对资源加锁。在更新数据时,通过某种机制(如版本号或时间戳)来检测是否发生了冲突......
  • 学生通讯录管理系统
    importos#加载通讯录数据defload_contacts():  contacts=[]  file_path="通讯录.txt"  ifos.path.exists(file_path):    withopen(file_path,'r',encoding='utf-8')asf:      lines=f.readlines()      ......
  • 网络编程学习笔记
    1.网络编程1.1.介绍(IO)怎么学:理解(应用层)、多回顾、多练、自主要求:互动、认真听、互相尊重1.1.1.认识网络网络:多设备通信认识网络1.2.IP地址1.2.1.基本概念1.IP地址是Internet中主机的标识2.Internet中的主机要与别的机器通信必须具有一个IP地址3.IP地址为32......
  • redis中,msyql数据库读写分离搭建
    一.mysql读写分离:缓解主服务器的压力 1.概念:主服务器写数据,从服务器读数据 2.实现方法: 客户端分离:开发手动分离地址 服务端分离:数据库与应用之间加一个中间件,分离读写请求 mysql-proxy,mysql-route,maxscale amoeba,cobar,mycat2 atlas,k......
  • C# 异步编程模型【代码之美系列】
    ......
  • 掌握Linux命令行的艺术:从入门到精通
    本章目录掌握Linux命令行的艺术:从入门到精通3.1终端介绍与常用命令终端是什么?常用命令速览3.2文件与目录操作文件操作命令目录操作命令文件操作示例图3.3用户与权限管理查看权限修改权限更改所有者创建新用户3.4文本处理工具3.5管道与重定向管道示例重定向示例3......
  • 线性筛与埃氏筛算法详解
    目录线性筛与埃氏筛算法详解第一部分:线性筛与埃氏筛算法概述1.1什么是埃氏筛算法?1.2什么是线性筛算法?1.3埃氏筛与线性筛的比较1.4应用场景第二部分:埃氏筛算法原理与实现2.1埃氏筛算法原理2.2埃氏筛算法的步骤2.3埃氏筛的Python实现2.4代码解释第三部分:线性筛算......
  • 图像边缘检测与轮廓提取详解及python实现
    目录图像边缘检测与轮廓提取详解第一部分:图像边缘检测与轮廓提取概述1.1什么是边缘检测和轮廓提取?1.2边缘检测与轮廓提取的应用领域1.3为什么需要边缘检测和轮廓提取?第二部分:常见的图像边缘检测算法2.1Sobel算子2.2Canny边缘检测2.3拉普拉斯算子(LaplacianofGaus......