我的网站域名上海电子商务网站制作
news/
2025/10/6 21:41:15/
文章来源:
我的网站域名,上海电子商务网站制作,asp网站实例,网站建设万禾指针#xff08;1#xff09;学习流程 —————————————————————————————————————————————————————————————————————————————————————————————————————————————… 指针1学习流程 ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
内存和地址
内存
所谓的指针就是为了管理内存空间划分的一个内存一个单元。
内存单元是计算机内存中的最小存储单位通常以字节(Byte)为单位。每个内存单元都有一个独特的地址以便CPU可以准确地找到并读写数据。 指针在C语言或其他允许指针操作的编程语言中非常重要因为它们提供了直接访问和操作内存的能力。使用指针程序可以避免数据复制从而提高效率尤其是在处理大型数据结构如数组和复杂的数据结构时。 地址
内存单元的编号就是地址 就是指针
首先必须理解计算机内是有很多的硬件单元而硬件单元是要互相协同工作的。所谓的协同至少相互之间要能够进行数据传递。 但是硬件与硬件之间是互相独立的那么如何通信呢?答案很简单用线连起来 而CPU和内存之间也是有大量的数据交互的所以两者必须也用线连起来。
CPU访问内存中的某个字节空间必须知道这个字节空间在内存的什么位置而因为内存中字节很多所以需要给内存进行编址(就如同宿舍很多需要给宿舍编号样)。 计算机中的编址并不是把每个字节的地址记录下来而是通过硬件设计完成的。 钢琴、吉他 上面没有写上“剁、来、咪、发、唆、拉、西”这样的信息但演奏者照样能够准确找到每一个琴弦的每一个位置这是为何?因为制造商已经在乐器硬件层面上设计好了并且所有的演奏者都知道。本质是一种约定出来的共识! 硬件编址也是如此 我们可以简单理解32位机器有32根地址总线每根线只有两态表示0,1【电脉冲有无】那么一根线就能表示2种含义2根线就能表示4种含义依次类推。32根地址线就能表示2^32种含义每一种含义都代表一个地址。 地址信息被下达给内存在内存上就可以找到该地址对应的数据将数据在通过数据总线传入CPU内寄存器。 cpu内部寄存器地址线和数据线的布局。具体来说在cpu的左边有8个地址线从0到7用于指定内存中的地址。每个地址线对应一个数据线用于读写内存的数据。此外还有一个控制总线R/W用于控制数据的读写操作。在cpu的右边是内核Kernel部分它与地址线和数据线相连用于接收来自内存的数据或指令。 通过物理线传到某一个过程 访问那个数据的内存
这里也有物理地址和虚拟地址 ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
指针变量和地址 指针变量是什么
1.指针是内存单元中一个最小的单元编号也就是地址
2.平时口语说的指针通常指的是指针变量是用来存放内存地址的变量
总结指针就是地址口语中说的指针通常指的是指针变量是用来存放内存地址的变量。 地址大小决定指针变量的大小
这里我们就明白: 在32位的机器上地址是32个0或者1组成二进制序列那地址就得用4个字节的空间来存储所以. 一个指针变量的大小就应该是4个字节。 那如果在64位机器上如果有64个地址线那一个指针变量的大小是8个字节才能存放一个地址
总结: 指针变量是用来存放地址的地址是唯一标示一个内存单元的,指针的大小在32位平台是4个字节在64位平台是8个字节。
指针变量的举例
这里我们需要知道创建了变量的本质是申请一块空间
当然这里可以看见在系统申请空间的时候是随机给一个地址的
也就是
在C语言中变量的内存分配通常是在程序的堆栈stack或堆heap上进行的。堆栈通常用于存储局部变量而堆则用于存储动态分配的内存。当程序执行到声明变量的语句时系统会为该变量分配一块内存空间并将其地址赋给变量。 关于地址的选择现代操作系统和编译器通常会使用一种称为“地址空间布局随机化”Address Space Layout Randomization, ASLR的技术来提高安全性。ASLR会确保每个进程的内存地址空间是随机的这样就增加了攻击者利用内存漏洞的难度。因此每次程序运行时即使它申请的内存空间大小相同分配的内存地址也可能不同。 这里引入
单目操作符取地址操作符
#define _CRT_SECURE_NO_WARNINGS 1
int main()
{int a 100;int arr[10];return 0;
}%p打印地址
单目操作符取地址操作符
取地址 取出来的是较小的地址 当知道较小的地址后 顺藤摸瓜就找到了
#define _CRT_SECURE_NO_WARNINGS 1
#includestdio.h
int main()
{int a 100;int arr[10];printf(%p\n, a);return 0;
}此时p也就是一个指针变量
当然 此时的语法还不对 但是此时取出的a的地址 给到了p 此时p也就是我们口中说的指针变量 这里平时说的p是指针 其实说的p是指针变量 取出来的地址 放到p里面 所以p是指针 也就是指针变量
#define _CRT_SECURE_NO_WARNINGS 1
#includestdio.h
int main()
{int a 100;int *p a;//int arr[10];//printf(%p\n, a);return 0;
}p是指向a的
因为p可以找到a
所以p是指向a的
*说明是指针变量 int 说明p指向的对象是int类型的 指针变量就是存放地址所以引用指针变量
任何东西只要放到指针里面 就呗指针认为是指针变量
这里不仅仅只是为了存放地址
此时p可以很好的找到a的地址
此时*p叫解引用操作符 或者间接访问操作符
这里需要知道
对p解引用 找到的结果找到的是a 取出a的地址 解引用 然后此时a就等于赋值的数值 关于指针变量大小
等同于找老莫我想吃鱼一样 老大不方便动手 小弟动手
地址是由地址线传入 一个地址线产生一个二进制位数 32个地址线产生2的32次方位地址线 所以在平台上面 x86的环境下面
一个指针的大小需要四个字节
所以地址长度决定指针变量的长度
所以64位就是一个指针就是8个字节
举例 32位的情况下 都是四个字节 和类型无关
这里插入两个内容 关于环境和计算 有利于指针的学习
计算机基础( 计算机里面为什么是32位指的是什么)C语言代码举例画图超详细解析_c语言中32位是什么意思-CSDN博客
计算机基础知识讲解原码反码补码以及在C语言里面是如何计算和运用的-CSDN博客
这里需要知道x86 是32位的环境
至于是为什么
x86这个名称来源于Intel在1978年推出的8086处理器它是第一个真正意义上的16位微处理器。后来Intel和AMD等公司推出了基于8086架构的扩展和改进型号如80286、80386和80486等。这些处理器虽然技术上仍然是16位的但它们引入了扩展寄存器和指令使得它们能够处理32位数据。 由于这些处理器在市场上获得了巨大成功人们开始将它们统称为x86架构。这个名称并没有明确指出它是16位还是32位但实际上从80386开始x86架构就已经支持32位操作了。 因此x86这个名称并不是指32位环境而是指一系列基于8086架构的处理器。不过由于这些处理器在32位时代获得了广泛应用人们往往用x86来指代32位环境。这种用法虽然不太准确但在实际应用中却是普遍接受的。
回归正题 x64 就是八个字节 这里需要知道
指针里面存方的一般是16进制
至于为什么是16进制 往往是因为16进制计算范围较大 比较方便
但是需要知道的是
存放的二进制 显示的16进制 简单说就是方便
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
指针类型
没有解引用之前 a的地址确实给到pa 但是当解引用的时候只改变了第一个字节 说明 指针类型决定指针的权限
整形指针一次只能访问四个字节
这就是指针类型的意义
如果你想访问一个字节 char
如果是四个字节 用int
再多就是float等等
因为这里你需要知道在初始化的时候分配内存和数值是随机分配的你进行指针的访问也只是根据类型来进行访问 指针类型的意义 指针类型决定了指针在进行解引用操作符的时候访问几个字节也就是决定指针的权限 加上数字 发现不一样 int*和char*每次跳过的也不一样 指针类型的计算
指针类型决定1 -1的时候一次走的距离
指针类型决定向前或者向后走一步 多少距离 简单的说就就是此时打印出来的地址减去之前的地址是大四个字节的 从而引出指针类型的意义
根据上述我们反过来讲解指针类型的意义
从而引出指针类型的意义 此时是短整型char 前后差距是一个字节
但是是int的情况下 前后差距就是四个字节 解引用不同的类型之间转化
对于指针解引用不同的类型访问不同的字节长度
取出的类型是一个整形的类型
但是放到了短整型里面
此时就会导致数据的丢失 void可以存放任何类型的地址 因为没有具体类型
在C或C等编程语言中
void 指针是一种特殊的指针类型它不代表任何具体的内存地址类型。
void 指针可以用来存放任何数据类型的地址因为它是所有类型的基类型。
但是需要注意的是虽然 void 指针可以存储任何类型的地址
但是不能直接使用它来访问或操作这些地址所指向的数据因为编译器不知道具体的数据类型也就无法进行正确的类型匹配和内存布局。
在实际应用中如果想要通过 void 指针访问具体类型的数据需要进行类型转换即将 void 指针强制转换为相应的类型指针。
例如
c
int a 10;
void* void_ptr a;
int* int_ptr (int*)void_ptr;
*int_ptr 20; // 现在 a 的值变为 20在这个例子中void_ptr 存储了 int 类型变量 a 的地址
但是不能直接通过 void_ptr 来修改 a 的值。我们通过类型转换得到了 int 指针 int_ptr
然后就可以通过 int_ptr 来修改 a 的值了。使用 void 指针时需要格外小心
因为错误的类型转换会导致未定义行为比如内存访问越界这可能会导致程序崩溃或产生不可预测的结果。
因此在使用 void 指针时确保进行正确的类型转换和内存管理是非常重要的。 所以在不确定是什么类型的时候 用void类型的接受 不过需要知道的是
void具有局限性 因为没有具体类型
所以无法运算访问字节
如图 这里显示的是未知的大小
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
const
首先解释一下const 在C语言中const用于声明一个只读的变量。这意味着该变量一旦被初始化其值就不能被改变。常量通常用于表示某些固定的、不变的值例如物理地址、尺寸或数学常数等。
在C语言中const 是一个关键字用于修饰变量以表明它们的值在定义之后不能被改变。const 关键字具有以下两个主要属性 1. 只读属性被 const 修饰的变量在初始化之后其值不能被修改。这意味着一旦你给一个 const 变量赋了一个值你就不能再次给它赋一个新值。 2. 类型安全const 关键字告诉编译器该变量是一个常量因此在程序执行期间试图修改这样一个变量的值会导致编译错误或运行时错误取决于如何尝试修改它。 const 可以用在变量声明的任何位置具有不同的含义 - const 在变量类型之前表示变量是一个只读的常量不能被赋予初始值必须在声明时初始化并且它的值在程序的整个运行期间都不可更改。 - const 在变量类型之后表示变量本身是可变的但其指向的数据是只读的。这在指针中非常有用可以确保指针指向的数据不被修改但指针本身即内存地址可以改变。 例如 c const int a 10; // 声明一个常整型变量初始化为10之后不能更改 int const b 20; // 同上这两种声明方式等效 int arr[10]; const int n 5; // 声明一个常整型变量表示数组的大小 int* ptr arr; const int* const ptr_to_const arr; // 声明一个指向常量的常量指针 // ptr_to_const指向的arr数组元素是常量不能被修改同时ptr_to_const本身的值也不能被改变 使用 const 可以提高代码的可读性和可维护性同时也帮助编译器进行更好的优化。此外const 关键字在C中还有更多的用途例如用来定义常量对象和成员函数但在C语言中它的使用主要局限于变量声明。
简单的说 可以片面的理解为就是他存在的意义就是防止新手修改老手的代码的时候不小心吧东西修改错误
const 本质
下面我会介绍什么时候回进行修改 以及范围 当然在这之前先介绍完const本身的属性
const 本质 是不能修改 此时用const修饰a之后
这里的a具有了长属性 长属性就是不能被修改的属性 这里需要知道
虽然a不能被修改但是本质还是变量 就是常变量 但是在c和c里面const是不一样d
在c里面 const修饰的是变量
在c里面则是常量 所以写C语言的话 后缀就要写c 但是这样是不符合规则的 为什么是不合规的前面已经说明 这里再详细的说一下
const int a 10; 声明了一个常量 a它的值不能被改变。接着int* p a; 声明了一个指向 a 的指针 p。 然后*p 0; 这行代码试图修改通过指针 p 所指向的内存位置的值。由于 a 是一个 const 变量它的值不能被改变所以这行代码是不正确的会导致编译错误。 在 C 语言中const 关键字的作用是确保变量在其生命周期内不被修改。尝试修改一个 const 变量的值会导致编译错误。因此如果您尝试执行 *p 0;编译器会报错因为它不允许您通过指针 p 来修改 a 的值。 正确的做法是只读取 a 的值而不是尝试修改它。例如 c const int a 10; int* p a; // 正确的使用方式是读取a的值而不是修改它 printf(%d\n, *p); // 输出 10 如果想要修改 a 的值需要首先取消 const 限制或者使用另一个变量来存储 a 的值然后修改那个变量的值。例如 c int a 10; int* p a; *p 0; // 正确修改了a的值 或者 c const int a 10; int b a; // b 是一个普通变量可以被修改 b 0; // 正确修改了b的值而不是a
const的使用规则 所以此时p指向的是a的地址 所以这个时候可以理解为 p本身就有一个地址 然后p指向了一个地址 p里面存放了a的地址
所以
p指向一个地址
p本身有一个地址
p存放一个地址 数值出来是100 const修饰指针变量的时候放到*的右边 限制的是指针变量本身指针变量不能指向其他变量 但是可以修改指针变量指向的内容
p不能修改 但是*p指向的内容可以进行修改 const放到*左边
修饰指针变量的时候
此时限制的是*p
但是可以修改指针变量本身
也就是此时 指针指向的内容是不能发生变化的 但是指针也就是指针变量本身是可以发生变化的 const生动举例
当const在*左边的时候、const* 这里假设有一对男女朋友这个有一天女孩说我想吃雪糕需要五十块 这个男孩说那我没钱一共十块钱买不起那女孩就不高兴了说那你的钱本身的变量不发生变化的话那我只能变化换男朋友了。
当const在*右边的时候、*const 这里假设还是这一对男女朋友还是这个场景这个有一天女孩说我想吃雪糕需要五十块 这个男孩说那我没钱一共十块钱但是没事我借钱40男孩这个指针指向的变量发生了变化买了一个雪糕还有0元那女孩就继续跟着你了也就是指针变量本身没有发生变化 const在*左边指针变量本身的地址变化 但是指向的内容不变化
所以这里就是你不给我花钱 指针女孩换男朋友m-n 女孩本身变化 男朋友的钱m数值不变化 此时m愿意花钱 然后等于把const放到右边 等于m愿意花钱 女孩指针p本身不变化 不换男朋友但是男朋友m的钱发生变化 也就是指针变量本身不发生变化但是指向的变量可以发生变化 当然两边也都可以加上const数值 总结
想搞定变量*const int
想搞定指针变量本身 const * int ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
assert断言
这里先简单讲一下assert的断言下面会有assert断言和野指针的结合使用
测试和写代码直接转换问题
这里链接一下 relase和debue的区别关于Visual Studio Installer总是出现LNK1168无法打开 不需要关机直接处理好_vs installer打不开-CSDN博客
测试和写代码直接转换问题
这里讲一下为什么在这个测试和写代码直接转换的时候会不一样
C语言在测试和写代码时可能会出现不一样的结果这主要是由于以下几个原因 1. **浮点数精度问题**C语言中的浮点数计算通常不会得到精确的结果因为计算机内部用二进制表示浮点数时无法精确表示所有的小数。所以在不同平台或者不同编译器上运行时浮点数的运算结果可能会有细微的差异。 2. **Endianness字节序**字节序是指计算机中字节存储的顺序。C语言中没有明确指定字节序这可能导致在不同硬件平台上多字节数据如整数、浮点数的存储顺序不同从而影响数据的解析和运算。 3. **编译器和运行时的优化**编译器在将C代码编译成机器码时可能会进行各种优化。这些优化可能会改变代码的执行逻辑或者运算结果。另外运行时的库函数也可能对输入数据进行不同的处理。 4. **测试环境和写代码的环境差异**如果在不同的环境如不同的操作系统、硬件平台、编译器版本等中进行测试和编写代码可能会因为环境的差异导致结果不同。 5. **代码的实现细节**在编写代码时可能会因为实现的细节不同例如算法效率、边界条件处理等而在测试时得到不同的结果。 为了减少这些差异通常需要在代码中加入适当的注释说明可能存在的差异并在文档中详细描述测试环境。此外也可以使用标准库函数如stdint.h中定义的固定宽度整数类型来避免因为浮点数精度和字节序引起的问题。在编写和测试代码时应尽可能在相同的环境中进行以确保结果的一致性。 assert 存在的意义 assert可以确保传过来的指针不是空指针
assert是一个在C语言中广泛使用的宏它的存在主要有以下意义 1. **调试辅助**在开发过程中assert用于在运行时检查程序的假设是否成立。如果assert语句的条件评估为假则程序会抛出一个断言失败异常通常会导致程序终止并输出错误信息这样可以帮助开发者快速定位问题所在。 2. **静态代码分析**在编译时assert可以作为静态代码分析的工具。通过检查assert语句编译器可以确保程序在运行之前满足一定的条件。这有助于在编译阶段发现潜在的错误而不是在运行时才暴露出来。 3. **文档和代码的同步**assert的使用可以在一定程度上作为代码注释它表明了程序员对程序某一部分的预期。这样其他阅读代码的人可以更清楚地理解代码的假设和约束。 4. **性能分析**在某些情况下assert可以用来测试代码路径是否应该被执行。如果assert失败这意味着程序处于一个不应该到达的状态这可能有助于发现性能瓶颈或逻辑错误。 5. **代码简洁性**使用assert可以避免在代码中充斥着大量的错误检查和异常处理代码使得正常逻辑更加清晰。 6. **沙盒环境的创建**在某些安全敏感的应用中assert可以用来创建沙盒环境确保程序在特定的安全边界内运行。 总之assert是C语言中一个非常有用的工具它有助于提高代码的质量和开发效率同时也使得代码更加健壮。然而需要注意的是assert不应该用于修复错误而应该仅用于检测错误。在生产环境中应该确保assert语句在编译时被正确处理或者在运行时不会对程序的稳定性产生影响。
assert具体举例
需要包含头文件assert.h 这个代码的健壮性更好 限制了所改变的内容 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
strlen
strlen存在的意义
strlen是C语言标准库函数之一它的作用是计算字符串的长度不包括终止符\0空字符。strlen函数在string.h或stdlib.h头文件中定义。 strlen的意义和用途包括 1. **获取字符串长度**strlen函数可以方便地获取一个字符串的长度这对于许多字符串操作如字符串比较、复制、连接等是非常必要的。 2. **内存分配**在动态分配内存时通常需要知道字符串的长度以便为字符串加上结束符\0并分配足够的空间。strlen可以提供这个长度信息。 3. **字符串处理**在进行字符串处理时如搜索、替换、截断等操作需要知道字符串的实际长度。strlen函数提供了这个信息。 4. **安全性**在使用字符串时strlen可以帮助避免缓冲区溢出等安全问题。例如在复制字符串时知道目标缓冲区的大小和源字符串的长度可以确保不会超出缓冲区的边界。 5. **跨平台兼容性**strlen是C语言标准库的一部分因此它在不同的操作系统和编译器之间具有很好的兼容性。 使用strlen时需要注意的是由于strlen不考虑字符串中的宽字符或多字节字符它只计算单字节字符的长度因此在处理非ASCII字符串时可能不够准确。对于宽字符或多字节字符串的长度计算应使用相应的库函数如wcslen宽字符串长度或strlen的变体这些函数能够正确处理多字节字符。 具体的举例
这里是和assert进行了一个结合
利用assert代码加入到代码 里面会减少出错性这里涉及野指针的下面会讲到 包含头文件
string.h或stdlib.h头文件中定义
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
指针的基本算法
指针的作用就是访问内存 指针的加法运算
指针的运算和访问内存息息相关下面会讲到 这里是整形一个整形是四个字节在指针的类型里面已经讲到
当然不能搞混 所以逻辑就是 代码举例
指针版本1
下标方式访问 指针方式访问
指针加减 整数
解引用
每次指针1
每次加一之后则变化指向的数值 如图 指针版本2
这个运行的前提条件是数组在内存里面是连续存放的 指针的减法运算指针-指针
指针的运算
指针-指针
指针-指针绝对值
得到是两个指针之间的元素个数 没有意义
不是所有的计算都是有意义的
而指针的计算应该是有意义的 指针-指针的运算 低地址和高地址的区别 指针-指针限制条件必须指向同一空间 所以计算出的结果是空间的长度 但是像这个计算出的结果 因为不是一个空间所以计算出的结果不是中间的长度而是没有意义的运算 指针里面strlen的运算
统计的是\0之前出现的个数
包含头文件 strlen头文件string 数组名相当于首元素地址
字符的地址用字符指针接收 strlen 指针的运算方式1
这里是数组名每次进行 然后最后求出总的字符的长度 strlen指针的运算方式2
这个采取的是指针-指针的运算方式
也就是同一空间 startstr 这里的str是首元素地址 也就是指向的是首元素
然后每次进行str再减去首元素地址 也就是指针-指针的运算
因为
这里str最后指向的是str这个空间的最后一个元素
start指向的是身str的首元素地址 也就是这个空间的第一个元素 指针的关系大小的运算
区分 运算的代码 这里是首元素的地址 sz是长度parrsz意思就是循环条件就是小于首元素地址加上整体长度
此时是不存在越界访问的情况的因为是小于而不是是小于等于
然后打印*p
每次P
从而实现代码 ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
野指针以及越界访问的问题
野指针的定义
野指针Wild Pointer是指向未知或者不可访问内存地址的指针。在C或C编程语言中野指针通常是由于指针没有被正确初始化而产生的。这意味着指针不指向任何有效的内存地址而是可能指向堆、栈或者代码区的任意位置。 定义 野指针是一种不安全指针它的值没有指向程序中已知地址的任何有效内存。这种指针的值可能是任意地址也可能是一个随机的旧值。在野指针上进行解引用操作即通过指针访问它所指向的内存会导致未定义行为Undefined Behavior这通常会导致程序崩溃或者产生错误的结果。 野指针的常见来源包括 1. 指针声明后没有立即初始化。 2. 指针释放后没有重新初始化。 3. 指针通过局部变量返回函数外而该局部变量已经超出作用域。 4. 在动态内存分配失败时忽略错误并将指针置为NULL以外的值。 为了避免野指针程序员应该遵循以下最佳实践 - 总是初始化指针使其指向一个有效的内存地址或者明确地将其设置为NULL。 - 在使用指针之前检查它是否为NULL。 - 避免指针的悬挂dangling pointer现象即指针指向的内存已经被释放。 - 使用现代C特性如智能指针可以自动管理内存减少野指针的风险。
指针正确代码和错误代码的对比
正确代码 错误代码 也就是烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫
这里为什么会产生烫这个字和函数栈有关因为函数栈溢出的时候就会产生烫这个字
烫烫烫的问题
这里为什么会产生烫这个字和函数栈有关因为函数栈溢出的时候就会产生烫这个字
在C语言编程中栈溢出stack overflow是一个常见的问题它发生在程序的栈空间被耗尽的时候。栈是用来存储局部变量和函数调用的上下文信息如返回地址、函数参数等的区域。当一个函数调用自身或其他函数时这些信息会被推入栈中。如果函数调用层次太深或者递归调用的深度超过了栈的大小限制就会导致栈溢出。 栈溢出时程序会出现未定义行为undefined behavior这可能导致程序崩溃、数据损坏或其他不可预测的结果。在中文里并没有“烫”这个字与栈溢出直接相关的说法。如果您在某个特定的上下文或方言中遇到了“烫”这个词与编程错误或异常相关联那可能是一个特殊的用法或者是某个特定社群的俚语而不是一个标准的计算机科学术语。 为了避免栈溢出程序员应该 1. 限制递归的深度确保递归调用的层级不会超过栈的最大容量。 2. 使用尾递归优化tail recursion optimization如果编译器或语言支持这可以避免栈空间的增加。 3. 避免在栈上分配大量内存特别是在递归函数中。 4. 使用堆heap来存储较大的数据结构而不是栈因为堆的容量远大于栈。 如果您在某个特定的文档、教程或者社区中看到了“烫”这个词与栈溢出相关的解释那么它可能是一个特定的术语或者是一个翻译错误。在这种情况下建议您查找更多的信息或者向该社区的成员澄清这个问题。
野指针造成的问题
野指针容易造成的问题 野指针Wild Pointer是指向未知或者不可访问内存地址的指针。在C或C编程中野指针通常是由于指针没有被正确初始化而产生的。使用野指针进行解引用dereferencing会导致未定义行为Undefined Behavior这可能导致程序崩溃、数据损坏或其他不可预测的结果。 野指针造成的问题主要包括以下几点 1. **程序崩溃**野指针可能指向内存中的任何位置包括操作系统或其他程序的内存区域。解引用野指针可能会读取或修改这些位置的内容导致程序崩溃。 2. **数据损坏**野指针可能导致对程序其他部分数据的意外修改这种修改可能是不可逆的从而导致程序行为变得不可预测。 3. **安全问题**野指针可能被用于发起缓冲区溢出攻击Buffer Overflow Attack。攻击者可以利用野指针向程序中写入恶意数据从而覆盖返回地址或其他关键数据导致程序执行意外的代码。 4. **性能下降**野指针可能导致程序在运行时产生意外的分支从而影响程序的性能。 5. **调试困难**由于野指针导致的问题通常是未定义行为因此在出现问题时调试和定位错误可能会非常困难。 为了避免野指针造成的问题程序员应该遵循以下最佳实践 - 总是初始化指针使其指向一个有效的内存地址或者明确地将其设置为NULL。 - 在使用指针之前检查它是否为NULL。 - 避免指针的悬挂dangling pointer现象即指针指向的内存已经被释放。 - 使用现代C特性如智能指针可以自动管理内存减少野指针的风险。 正确管理指针是确保软件质量和稳定性的重要方面也是避免野指针问题的关键。
野指针的非法访问问题
形成非法访问
可以看到每次的数值是随机的 野指针的越界访问问题
这里是10个元素循环11次
循环第十一次的时候就已经造成越界访问
所以此时的指针就变成了野指针 指针指向的空间释放 越界和传址问题图解 野指针的寻址的问题
但是遗憾的是a的空间运行结束进行释放 a的空间还给操作系统了 但是下面的空间还是进行寻址 也就是此时找的是空地址 此时这个指针就是野指针 此时野指针再访问空间 就是非法访问 这里不能指向这个空间 因为这里创建的空间最后会进行销毁
也就是说如果指向这个空间的haul最后指向的是一个空的地址
最后导致野指针的发生 简单的举例就是小敏今天开了一个房间是901准备进行诈骗。然后让小帅第二天来小帅第一天吧钱交出去之后第二天来到这个酒店说我要进去901但是酒店说了这个人退房了已经没有这个房间了。
这个就是指针的寻址问题
因为在另外一个函数里面进行运算的事情只能返回一个数值而不是整个地址这个函数需要进行运算的时候或者需要进行诈骗的时候会开辟一块空间不需要进行诈骗会吧这个空间关闭。但是如果你还是需要回去那个空间自然就找不到这个空间了。
越界和传址问题图解
如何避免野指针 本来就是拴着的狗 你还去里面 肯定咬你 避免指针越界访问 更加安全 assert断言和野指针的使用
包含头文件 assert.h 也就是assert进行断言 如果p不等于空指针 则没事
如果等于空指针 则 断言失败 报错 直接报错了 如果不满足条件
这里是满足条件才继续往下走 断言成功 继续运行 断言只要是表达式就可以 不一定非得说是指针 禁用很简单
assert对程序员很友好
所以在写代码的时候适当assert一下 对你是刮目相看的
release是发布版本 发布出去 还断言干什么 ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
传值调用 传址调用
两者区别
首先就是顾名思义
传值调用传过去的是数值
传址调用传过去的是地址
在C语言中函数对参数的传递有两种方式传值调用Pass by Value和传址调用Pass by Reference。 传值调用 在传值调用中函数接收的是实际参数值的一个副本。 这意味着在函数内部对参数的任何操作都不会影响原始的变量。 传值调用适用于基本数据类型如int、float等因为这些数据类型可以轻松地通过值传递来复制。 传址调用 在传址调用中函数接收的是实际参数地址即变量的内存地址。 这意味着在函数内部对参数的任何操作都会直接影响原始的变量。 传址调用通常用于指针类型或数组因为这些数据类型无法简单地通过值传递来复制而是需要传递它们的地址。 简单来说传值调用是传递数据的副本而传址调用是传递数据所在内存的地址。下面是一个示例展示两种调用方式的差异
#include stdio.h// 传值调用示例
void modifyValue(int value) {value 50;
}// 传址调用示例
void modifyReference(int *ptr) {*ptr 50;
}int main() {int a 25;// 使用传值调用modifyValue(a);printf(After modifyValue: a %d\n, a); // a 仍为 25// 使用传址调用modifyReference(a);printf(After modifyReference: a %d\n, a); // a 变为 50return 0;
}在上述代码中通过传值调用修改的变量 a 的值没有被改变因为传递的是 a 的副本。而通过传址调用修改的是变量 a 的值因为传递的是 a 的地址。
两者的情况分析
不是所有情况都适合 xy都有自己的空间 所以实际是xy进行交换半天 但是ab没有进行交换
虽然形参得到了实参的数值 但是实参有自己的空间 对形参的修改不会影响实参
所以没有达到最终的效果 怎么解决 所以此时就是间接找到了ab的地址
因为此时指针指向的是地址 此时是直接找到地址 画图解释‘ 如果不指向地址的情况下 形参是开辟自己的空间 但是指向的是ab的地址从而对ab的地址进行操作
所以最终还是三个变量之间的交换 相当于就是直接对a b 操作
传址调用 总结 也就是主要是函数内部可以操作外面 就需要传址调用
如果只是接收数值 需要传值调用
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
补充
指针类型和C语言编程语言环境的区别
指针类型是C语言编程中的一个核心概念而C语言编程语言环境则是指C语言本身及其相关的编译器、运行时库、操作系统等软件和硬件环境的总和。下面分别解释这两者的区别### 指针类型 指针类型是指在C语言中用于存储和管理内存地址的数据类型。指针本身是一个变量其值是另一个变量的内存地址。通过指针可以间接访问和操作内存中的数据。 指针类型包括以下几个方面 1. **基本指针类型**如int *p;中的p是一个指向整型的指针。 2. **空指针**在C中NULL是一个定义在stddef.h中的空指针常量表示没有指向任何有效内存地址的指针。 3. **指向指针的指针**如int **pp;中的pp是一个指向整型指针的指针。 4. **函数指针**指向函数的指针可以用来调用函数如void (*fp)(int);。 5. **数组指针**指针可以指向数组如int (*arr)[10];中的arr是一个指向含有10个整数的数组的指针。 指针类型在C语言中的使用非常广泛因为它们提供了内存操作的高效途径并且是实现数据结构如链表、树、图等的基础。### C语言编程语言环境 C语言编程语言环境包括了C语言本身以及使用C语言进行编程时所依赖的所有外部资源。这些资源可以包括 1. **编译器**将C源代码转换为机器代码的工具如GCC、Clang等。 2. **运行时库**在程序运行时提供额外功能的库如标准库libc它包含了像printf、malloc这样的函数。 3. **操作系统**提供程序执行和管理硬件资源的平台如Linux、Windows等。 4. **开发工具**包括编辑器、调试器、性能分析工具等如Vim、Emacs、GDB等。 5. **硬件平台**指针类型和C语言的其他特性在不同的硬件平台上可能有所不同因为硬件架构会影响内存管理方式和指针的实现。 总结来说指针类型是C语言中的一个语言特性而C语言编程语言环境则是一个更为广泛的概念包括了C语言本身以及用于编写和执行C程序的所有工具和平台。
指针类型1增加四个字节和编程环境1增加四个字节的区别
在C语言中指针类型1增加四个字节和编程环境1增加四个字节这两者之间的区别在于它们所指的具体内容和上下文。### 指针类型1增加四个字节 1. **指针自增操作**当你对一个指针进行操作时例如int *p; p;如果int类型占用四个字节那么指针p的内容将增加四个字节指向下一个int类型的位置。这是指针操作的一种是指针本身值的改变。 2. **指针的移动**这里的增加四个字节是指指针的数值增加了sizeof(int)的大小。sizeof(int)在大多数现代平台上的确是四个字节但这并不是固定的它取决于编译器和操作系统。### 编程环境1增加四个字节 1. **数据大小的变化**在编程环境的上下文中1增加四个字节可能指的是在某个上下文中数据类型的大小增加了。例如如果编程环境从32位升级到64位那么通常整数类型的大小会从四个字节增加到八个字节。 2. **性能优化或需求**在某些情况下编程环境的更新可能不会改变数据类型的大小但可能会引入新的数据类型或者优化以满足更高的性能需求或者更好的兼容性。 3. **内存管理的变化**在更广泛的上下文中增加四个字节也可能指的是内存管理策略的变化比如操作系统或编译器可能会在指针周围增加额外的元数据以支持更高级的内存分配或优化技术。 总的来说指针类型1增加四个字节是指针操作的直接结果而编程环境1增加四个字节是指整个编程语言和运行时环境的改变这些改变可能影响数据类型的大小、内存布局、性能特性等多个方面。这两者是不同层次的概念一个是语言层面的操作另一个是整个环境层面的变化。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/929732.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!