常见的C语言内存错误及对策
C语言技术中常见的问题及解决方法

C语言技术中常见的问题及解决方法C语言作为一门广泛应用于软件开发领域的编程语言,常常会遇到一些常见的问题。
本文将探讨一些常见的C语言技术问题,并提供相应的解决方法。
一、内存泄漏内存泄漏是C语言开发中常见的问题之一。
当程序在运行过程中分配了内存空间,但未能正确释放时,就会导致内存泄漏。
长时间运行的程序可能会消耗大量的内存,最终导致系统崩溃。
解决方法:1. 确保每次分配内存后都能正确释放,使用free()函数来释放动态分配的内存。
2. 避免重复分配内存,可以使用指针变量来保存已分配的内存地址,并在不再需要时进行释放。
3. 使用内存管理工具,如Valgrind等,来检测内存泄漏问题。
二、空指针引用在C语言中,当一个指针变量没有被初始化或者指向了一个无效的内存地址时,就会出现空指针引用的问题。
空指针引用可能导致程序崩溃或者产生未定义的行为。
解决方法:1. 在使用指针变量之前,始终确保它指向了有效的内存地址。
可以通过将指针初始化为NULL来避免空指针引用。
2. 在使用指针变量之前,进行有效性检查,可以使用条件语句来判断指针是否为空。
3. 使用断言来检测指针是否为空,如果为空则终止程序执行。
三、数组越界访问在C语言中,数组越界访问是一种常见的错误。
当程序试图访问数组范围之外的元素时,就会导致未定义的行为,可能会破坏其他内存区域或者导致程序崩溃。
解决方法:1. 确保数组索引在有效范围内,可以使用条件语句来判断索引是否越界。
2. 使用循环结构来遍历数组,确保不会越界访问。
3. 使用编译器提供的警告功能,如gcc的-Warray-bounds选项,来检测数组越界访问问题。
四、类型不匹配在C语言中,类型不匹配是常见的错误之一。
当程序试图将一个类型的值赋给另一个不兼容的类型时,就会出现类型不匹配的问题。
解决方法:1. 确保变量的类型和赋值的值类型匹配,可以使用强制类型转换来进行类型转换。
2. 使用正确的格式化字符串来打印不同类型的值,如使用%d来打印整数,%f 来打印浮点数等。
C语言技术使用中常见问题解决方案精选

C语言技术使用中常见问题解决方案精选C语言作为一种通用的编程语言,广泛应用于各个领域中。
然而,在使用过程中,我们常常会遇到一些问题,影响我们的编程效率和质量。
本文将为大家分享一些常见的C语言技术问题,并提供解决方案,帮助大家更好地使用C语言进行编程。
一、内存泄漏问题及解决方案在C语言中,内存泄漏是一个常见的问题。
当我们动态分配了内存空间后,如果没有及时释放,就会导致内存的浪费和不必要的性能损失。
以下是一些常见的内存泄漏问题及解决方案:1.未释放堆内存:在使用malloc()函数动态分配内存后,要确保使用free()函数及时释放内存空间。
```c// 未释放堆内存示例int* p = (int*)malloc(sizeof(int));// 其他代码```解决方案:添加释放内存的语句```cfree(p);```2.循环中频繁动态分配内存:在循环体中频繁地使用malloc()函数动态分配内存,会导致内存的频繁分配和释放,影响性能。
解决方案:在循环体外部使用一次性分配内存的方式,尽量避免循环内部频繁动态分配内存。
二、指针问题及解决方案指针是C语言中重要的概念,也是初学者容易出现问题的地方。
以下是一些常见的指针问题及解决方案:1.野指针:当指针指向一个无效的内存地址时,称之为野指针。
对野指针进行操作会导致程序异常或崩溃。
解决方案:在使用指针之前,要确保指针指向一个有效的内存地址,或者使用NULL对指针进行初始化。
```cint* p = NULL; // 初始化指针为NULL```2.空指针:空指针是指未被初始化的指针,在使用空指针时,会导致程序异常或崩溃。
解决方案:在使用指针之前,要确保指针已经被正确初始化。
三、数组越界问题及解决方案在使用数组时,越界访问是一个常见的错误。
越界访问会导致程序出现未定义行为或崩溃。
以下是一些常见的数组越界问题及解决方案:1.数组下标越界访问:当我们使用一个超过数组长度的下标访问数组元素时,会导致越界访问。
C语言技术使用中的常见问题及解决方案

C语言技术使用中的常见问题及解决方案在计算机科学领域,C语言是一种广泛应用的编程语言。
然而,即使对于经验丰富的程序员来说,使用C语言时也可能遇到一些常见问题。
本文将讨论一些常见问题,并提供解决方案,以帮助读者更好地应对这些挑战。
问题一:内存泄漏在C语言中,手动管理内存是一项重要任务。
如果程序员忘记释放已经分配的内存,就会导致内存泄漏。
这可能会导致程序运行缓慢,甚至崩溃。
为了解决这个问题,程序员应该养成良好的内存管理习惯。
及时释放不再使用的内存是一种有效的方法。
此外,使用内存分配和释放的工具,如malloc和free函数,可以帮助程序员更好地管理内存。
问题二:指针错误指针是C语言中的重要概念,但也容易出错。
常见的指针错误包括空指针引用和越界访问。
为了避免这些错误,程序员应该始终检查指针是否为空,然后再进行操作。
此外,使用合适的数据结构和算法可以减少指针错误的发生。
例如,使用链表来管理数据可以避免越界访问的问题。
问题三:缓冲区溢出缓冲区溢出是一种常见的安全漏洞,也是C语言中的常见问题之一。
当程序试图写入超出缓冲区大小的数据时,就会发生缓冲区溢出。
为了解决这个问题,程序员应该使用安全的字符串函数,如strncpy和snprintf,来确保写入的数据不会超出缓冲区的大小。
此外,程序员还应该注意使用动态分配内存时的边界检查,以防止缓冲区溢出。
问题四:死锁在多线程编程中,死锁是一个常见的问题。
当两个或多个线程相互等待对方释放资源时,就会发生死锁。
为了避免死锁,程序员应该遵循一些最佳实践。
例如,使用互斥锁和条件变量来管理共享资源的访问,并确保线程按照正确的顺序获取和释放锁。
此外,程序员还应该避免使用过多的锁,以减少死锁的可能性。
问题五:性能优化在一些应用中,性能是至关重要的。
然而,C语言的性能优化可能会变得复杂和困难。
为了解决这个问题,程序员应该使用一些性能分析工具,如gprof和Valgrind,来找出程序的瓶颈。
掌握C语言技术的常见问题解决方案

掌握C语言技术的常见问题解决方案C语言作为一门广泛应用于软件开发和系统编程的编程语言,常常会遇到一些问题。
在这篇文章中,我们将探讨一些常见的C语言技术问题,并提供相应的解决方案。
1. 内存泄漏内存泄漏是C语言中常见的问题之一。
它指的是程序在动态分配内存后,没有正确释放这些内存,导致内存资源无法被再次使用。
为了避免内存泄漏,我们应该养成良好的编程习惯,及时释放不再使用的内存。
可以使用free()函数来释放动态分配的内存,确保在不需要使用时将其释放。
2. 数组越界数组越界是指在访问数组元素时超出了数组的边界。
这可能导致程序崩溃或产生不可预测的结果。
为了避免数组越界问题,我们应该始终确保在访问数组元素之前检查数组的边界。
可以使用条件语句或循环来检查数组索引是否有效,并在索引无效时采取相应的措施,如打印错误信息或终止程序的执行。
3. 指针问题指针是C语言中的重要概念,但也容易引发一些问题。
常见的指针问题包括空指针引用、野指针和指针未初始化等。
为了避免这些问题,我们应该始终确保指针在使用之前被正确初始化,并在不再使用时将其置为NULL。
此外,还应该避免对空指针进行解引用操作,以防止程序崩溃。
4. 死循环死循环是指程序中的一个循环结构无法正常终止,导致程序无法继续执行下去。
死循环可能是由于循环条件错误或循环体中的控制语句错误引起的。
为了避免死循环问题,我们应该仔细检查循环条件,并确保在循环体中有正确的控制语句,如break或return,以便在满足某个条件时终止循环。
5. 编译错误编译错误是指在编译程序时出现的错误,常常是由于语法错误、拼写错误或缺少必要的库文件等引起的。
为了解决编译错误,我们应该仔细检查程序代码,确保语法正确无误,并确保所需的库文件已正确链接。
此外,编译器通常会提供详细的错误信息,我们应该仔细阅读并理解这些错误信息,以便更好地定位和解决问题。
6. 调试技巧调试是解决问题的关键步骤之一。
在C语言中,我们可以使用调试器来逐行执行程序代码,查看变量的值和程序的执行流程,以便更好地理解程序的行为并找出问题所在。
C语言常见错误与调试方法

C语言常见错误与调试方法在学习和使用C语言的过程中,出现错误是很常见的。
这些错误可能会导致程序无法正常运行或产生不符合预期的结果。
为了提高代码的质量和效率,我们需要了解常见的C语言错误,并学会相应的调试方法。
1. 语法错误语法错误是最常见的错误类型之一。
它们通常是由于拼写错误、标点符号的错误、缺少分号以及错误的语法结构等问题导致的。
为了避免语法错误,我们应该养成良好的编程习惯,例如检查拼写和标点符号、使用代码缩进和注释来提高代码的可读性。
当遇到语法错误时,我们应该仔细检查所在代码行及其前后的语句,查找可能存在的拼写错误或语法结构错误。
有时,观察编译器给出的错误提示信息也是解决语法错误的关键。
2. 逻辑错误逻辑错误是指程序运行时产生错误结果、逻辑混乱或无法按照预期执行的情况。
这些错误通常是由于程序员的思考不清晰或对问题理解不准确导致的。
要避免逻辑错误,我们需要仔细分析和推理代码的逻辑,确保我们的代码能够完整地涵盖目标问题。
此外,我们还可以使用调试工具来帮助捕捉逻辑错误,例如使用调试器逐步跟踪代码的执行路径、使用断点来观察变量值等。
当遇到逻辑错误时,我们可以尝试使用输出语句在关键位置输出变量的值,以便观察程序的执行情况。
另外,调试工具提供了代码的逐行执行功能,我们可以逐步检查代码并观察变量的值,从而找出逻辑错误的根源。
3. 数组越界错误数组越界错误是指在访问数组元素时超出了数组的范围。
这样的错误可能会导致程序崩溃或者产生不可预测的结果。
为了避免数组越界错误,我们需要确保在访问数组元素之前检查数组的边界。
此外,我们还可以使用循环结构来遍历数组,并通过循环变量来控制访问数组的索引。
当遇到数组越界错误时,我们应该检查涉及的所有循环和条件语句,确定数组索引的范围是否正确。
此外,一些编译器会提供工具来检测数组越界错误,我们可以使用这些工具来优化代码和修复错误。
4. 内存泄漏错误内存泄漏错误是指在程序运行过程中未正确释放不再使用的内存。
C语言技术的常见问题解析及解决方案

C语言技术的常见问题解析及解决方案C语言作为一种广泛应用于软件开发和系统编程的编程语言,常常面临各种技术问题。
本文将探讨一些常见的C语言技术问题,并提供解决方案。
一、内存管理问题在C语言中,内存管理是一个常见的问题。
其中最常见的问题是内存泄漏和内存溢出。
内存泄漏指的是程序在分配内存后,没有正确释放该内存,导致内存资源的浪费。
解决内存泄漏的方法是在每次分配内存后,确保在不再使用时释放该内存。
另一个问题是内存溢出,它发生在程序试图分配超过其可用内存的情况下。
解决内存溢出的方法是在分配内存前,检查该内存是否足够,并在不足时采取相应措施,如调整内存大小或释放其他不必要的内存。
二、指针问题指针是C语言中一个强大而复杂的概念。
常见的指针问题包括空指针引用和野指针引用。
空指针引用指的是程序试图访问一个未初始化的指针,而野指针引用指的是程序试图访问一个已经释放的指针。
为了解决这些问题,我们可以在使用指针之前,确保指针已经被正确初始化。
另外,在释放指针后,应该将其设置为NULL,以避免野指针引用。
三、数组越界问题数组越界是C语言中常见的错误之一。
它发生在程序试图访问数组的越界元素时。
这可能导致程序崩溃或产生不可预测的结果。
为了解决这个问题,我们应该在访问数组元素之前,确保索引值在合法范围内。
另外,可以使用循环结构来遍历数组,以确保不会越界访问。
四、字符串处理问题字符串处理是C语言中常见的任务之一。
然而,由于C语言中没有内置的字符串类型,所以字符串处理常常面临一些问题,如缓冲区溢出和字符串拷贝错误。
为了解决这些问题,我们可以使用安全的字符串函数,如strncpy()和strncat(),来确保字符串操作不会导致缓冲区溢出。
此外,还可以使用指针和循环结构来逐个字符地处理字符串,以避免错误。
五、性能优化问题在C语言中,性能优化是一个重要的考虑因素。
常见的性能问题包括循环结构的效率和函数调用的开销。
为了提高循环结构的效率,我们可以使用适当的循环条件和循环变量更新方式,以减少循环次数。
常见的内存错误及其对策.ppt
错在哪里!
warning C4172: returning address of local variable or temporary
输出乱码
void GetInput(char* s) { scanf("%s", s); 2}019/11/16
不能把局部变量的地址作为返 回值返回
函数返回后,局部变量被释放 ,该地址的内存会被挪做它用
常见的内存错误及其对策
常见错误5解决对策 – 尽量把malloc集中在函数的入口处,free集
中在函数的出口处
– 如果free不能放在函数出口处,则指针free后
立即设置为NULL
– 不要把局部变量的地址作为返回值返回,因为
该内存在函数体结束时被自动销毁
– 指针要么初始化为NULL,要么是其指向合法的
常见的内存错误及其对策
#include <stdio.h> #include <stdlib.h>
void GetInput(char *p) {
p = (char *)malloc(100); }
程序崩溃,函数不能传递动态分配的内存?
void GetInput(char **p) {
*p = (char *)malloc(100); }2019/11/16
2019/11/16
常见的内存错误及其对策
常见错误1: – 内存分配未成功,却使用பைடு நூலகம்它
起因 – 没有意识到内存分配会不成功 – 编程新手容易犯
解决对策 – 在使用内存之前,检查指针是否为空指针(NULL)
if (p == NULL)
{ printf("No enough memory!\n"); exit(0);
C语言编程中常见的五种错误及对应解决方案
C语⾔编程中常见的五种错误及对应解决⽅案⽬录1. 未初始化的变量2. 数组越界3. 字符串溢出4. 重复释放内存5. 使⽤⽆效的⽂件指针前⾔:C 语⾔有时名声不太好,因为它不像近期的编程语⾔(⽐如 Rust)那样具有内存安全性。
但是通过额外的代码,⼀些最常见和严重的 C 语⾔错误是可以避免的。
即使是最好的程序员也⽆法完全避免错误。
这些错误可能会引⼊安全漏洞、导致程序崩溃或产⽣意外操作,具体影响要取决于程序的运⾏逻辑。
下⽂讲解了可能影响应⽤程序的五个错误以及避免它们的⽅法:1. 未初始化的变量程序启动时,系统会为其分配⼀块内存以供存储数据。
这意味着程序启动时,变量将获得内存中的⼀个随机值。
有些编程环境会在程序启动时特意将内存“清零”,因此每个变量都得以有初始的零值。
程序中的变量都以零值作为初始值,听上去是很不错的。
但是在 C 编程规范中,系统并不会初始化变量。
看⼀下这个使⽤了若⼲变量和两个数组的⽰例程序:#include <stdio.h>#include <stdlib.h>intmain(){int i, j, k;int numbers[5];int *array;puts("These variables are not initialized:");printf(" i = %d\n", i);printf(" j = %d\n", j);printf(" k = %d\n", k);puts("This array is not initialized:");for (i = 0; i < 5; i++) {printf(" numbers[%d] = %d\n", i, numbers[i]);}puts("malloc an array ...");array = malloc(sizeof(int) * 5);if (array) {puts("This malloc'ed array is not initialized:");for (i = 0; i < 5; i++) {printf(" array[%d] = %d\n", i, array[i]);}free(array);}/* done */puts("Ok");return 0;}这个程序不会初始化变量,所以变量以系统内存中的随机值作为初始值。
常见C语言内存错误
常见C语⾔内存错误前⾔C语⾔强⼤的原因之⼀在于⼏乎能掌控所有的细节,包括对内存的处理,什么时候使⽤内存,使⽤了多少内存,什么时候该释放内存,这都在程序员的掌控之中。
⽽不像Java中,程序员是不需要花太多精⼒去处理垃圾回收的事情,因为有JVM在背后做着这⼀切。
但是同样地,能⼒越⼤,责任越⼤。
不恰当地操作内存,经常会引起难以定位的灾难性问题。
今天我们就来看看有哪些常见的内存问题。
初始化堆栈中的数据对申请的内存或⾃动变量进⾏初始化是⼀个好习惯,例如:int test(){int *a = (int*) malloc(10);/*判断是否申请成功*/if(NULL == a){return -1;}/*将其初始化为0*/memset(a,0,10);/*do something*/return 0;}我们经常需要在使⽤前将其初始化为0或使⽤calloc申请内存。
关于初始化,在《》⼀⽂中,有更详细的阐述。
缓冲区溢出缓冲区溢出通常指的是向缓冲区写⼊了超过缓冲区所能保存的最⼤数据量的数据。
同样的,缓冲区溢出通常也伴随着难以定位的问题。
例如下⾯的代码就存在缓冲区溢出的可能:/*bad code*/#include <stdio.h>#include <string.h>int main(void){char buff[8] = {0};char *p = "0123456789";strcpy(buff,p);printf("%s\n",buff);return 0;}关于缓冲区溢出,可以通过《》⼀⽂了解更多。
指针不等同于其指向的对象我们可能常常错误性地认为指针对象的⼤⼩就是数据本⾝的⼤⼩,最常错误使⽤的就是下⾯的情况:/*bad code*/int test(int a[]){size_t len = sizeof(a)/sizeof(int);/*do something*/}这⾥计算数组a的长度偶尔能够如愿,但实际上是错误的,因为数组名作为参数时,是指向该数组下标为0的元素的指针。
C语言技术中的常见问题及解决方案
C语言技术中的常见问题及解决方案在学习和使用C语言的过程中,我们经常会遇到各种问题。
这些问题可能会让我们感到困惑和挫败,但是只要我们能够找到合适的解决方案,就能够克服这些困难,继续向前发展。
本文将介绍一些常见的C语言问题,并提供相应的解决方案。
1. 编译错误在编写C代码时,经常会遇到编译错误。
这些错误可能是因为语法错误、拼写错误、缺少头文件等原因造成的。
解决这些问题的关键在于仔细检查错误信息,并逐个排查可能的原因。
在编写代码时,可以使用一些集成开发环境(IDE)或文本编辑器,它们通常会在代码中标记出错误,并提供相应的建议。
2. 内存泄漏内存泄漏是指在程序中动态分配的内存没有被正确释放,导致内存资源的浪费。
这种问题可能会导致程序运行变慢,甚至崩溃。
为了避免内存泄漏,我们应该养成良好的内存管理习惯。
在使用malloc()或calloc()函数分配内存后,一定要记得使用free()函数释放内存。
另外,可以使用一些内存泄漏检测工具来帮助我们发现潜在的问题。
3. 数组越界在C语言中,数组越界是一个常见的错误。
当我们访问数组元素时,如果超出了数组的范围,就会导致程序出错。
为了避免数组越界问题,我们应该始终注意数组的大小,并在访问数组元素之前进行边界检查。
另外,可以使用一些静态分析工具来帮助我们检测潜在的数组越界问题。
4. 逻辑错误逻辑错误是指程序在逻辑上存在错误,导致程序输出与预期不符。
解决逻辑错误的关键在于仔细分析程序的逻辑,找出错误的原因。
可以使用调试器来逐步执行程序,并观察程序的行为。
另外,可以使用一些单元测试框架来帮助我们验证程序的逻辑是否正确。
5. 效率问题在编写C代码时,我们经常需要考虑程序的效率。
如果程序运行速度过慢,可能会影响用户体验。
为了提高程序的效率,我们可以采取一些优化措施,例如使用更高效的算法、减少不必要的计算和内存访问等。
另外,可以使用一些性能分析工具来帮助我们找出程序的瓶颈,并进行相应的优化。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
常见的C语言内存错误及对策一、指针没有指向一块合法的内存定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内存。浅显的例子就不举了,这里举几个比较隐蔽的例子。
1、结构体成员指针未初始化structstudent{char*name;intscore;}stu,*pstu;intmain(){strcpy(stu.name,"Jimy");stu.score=99;return0;}很多初学者犯了这个错误还不知道是怎么回事。这里定义了结构体变量stu,但是他没想到这个结构体内部char*name这成员在定义结构体变量stu时,只是给name这个指针变量本身分配了4个字节。name指针并没有指向一个合法的地址,这时候其内部存的只是一些乱码。所以在调用strcpy函数时,会将字符串"Jimy"往乱码所指的内存上拷贝,而这块内存name指针根本就无权访问,导致出错。解决的办法是为name指针malloc一块空间。
同样,也有人犯如下错误:intmain(){pstu=(structstudent*)malloc(sizeof(structstudent));strcpy(pstu->name,"Jimy");pstu->score=99;free(pstu);return0;}为指针变量pstu分配了内存,但是同样没有给name指针分配内存。错误与上面第一种情况一样,解决的办法也一样。这里用了一个malloc给人一种错觉,以为也给name指针分配了内存。
2、没有为结构体指针分配足够的内存intmain(){pstu=(structstudent*)malloc(sizeof(structstudent*));strcpy(pstu->name,"Jimy");pstu->score=99;free(pstu);return0;}为pstu分配内存的时候,分配的内存大小不合适。这里把sizeof(structstudent)误写为sizeof(structstudent*)。当然name指针同样没有被分配内存。解决办法同上。
3、函数的入口校验不管什么时候,我们使用指针之前一定要确保指针是有效的。
一般在函数入口处使用assert(NULL!=p)对参数进行校验。在非参数的地方使用if(NULL!=p)来校验。但这都有一个要求,即p在定义的同时被初始化为NULL了。比如上面的例子,即使用if(NULL!=p)校验也起不了作用,因为name指针并没有被初始化为NULL,其内部是一个非NULL的乱码。
assert是一个宏,而不是函数,包含在assert.h头文件中。如果其后面括号里的值为假,则程序终止运行,并提示出错;如果后面括号里的值为真,则继续运行后面的代码。这个宏只在Debug版本上起作用,而在Release版本被编译器完全优化掉,这样就不会影响代码的性能。
有人也许会问,既然在Release版本被编译器完全优化掉,那Release版本是不是就完全没有这个参数入口校验了呢?这样的话那不就跟不使用它效果一样吗?
是的,使用assert宏的地方在Release版本里面确实没有了这些校验。但是我们要知道,assert宏只是帮助我们调试代码用的,它的一切作用就是让我们尽可能的在调试函数的时候把错误排除掉,而不是等到Release之后。它本身并没有除错功能。再有一点就是,参数出现错误并非本函数有问题,而是调用者传过来的实参有问题。assert宏可以帮助我们定位错误,而不是排除错误。
二、为指针分配的内存太小为指针分配了内存,但是内存大小不够,导致出现越界错误。char*p1=“abcdefg”;char*p2=(char*)malloc(sizeof(char)*strlen(p1));strcpy(p2,p1);p1是字符串常量,其长度为7个字符,但其所占内存大小为8个byte。初学者往往忘了字符串常量的结束标志“\0”。这样的话将导致p1字符串中最后一个空字符“\0”没有被拷贝到p2中。解决的办法是加上这个字符串结束标志符:char*p2=(char*)malloc(sizeof(char)*strlen(p1)+1*sizeof(char));这里需要注意的是,只有字符串常量才有结束标志符。比如下面这种写法就没有结束标志符了:chara[7]={‘a’,’b’,’c’,’d’,’e’,’f’,’g’};另外,不要因为char类型大小为1个byte就省略sizof(char)这种写法。这样只会使你的代码可移植性下降。三、内存分配成功,但并未初始化犯这个错误往往是由于没有初始化的概念或者是以为内存分配好之后其值自然为0。未初始化指针变量也许看起来不那么严重,但是它确确实实是个非常严重的问题,而且往往出现这种错误很难找到原因。
曾经有一个学生在写一个windows程序时,想调用字库的某个字体。而调用这个字库需要填充一个结构体。他很自然的定义了一个结构体变量,然后把他想要的字库代码赋值给了相关的变量。但是,问题就来了,不管怎么调试,他所需要的这种字体效果总是不出来。我在检查了他的代码之后,没有发现什么问题,于是单步调试。在观察这个结构体变量的内存时,发现有几个成员的值为乱码。就是其中某一个乱码惹得祸!因为系统会按照这个结构体中的某些特定成员的值去字库中寻找匹配的字体,当这些值与字库中某种字体的某些项匹配时,就调用这种字体。但是很不幸,正是因为这几个乱码,导致没有找到相匹配的字体!因为系统并无法区分什么数据是乱码,什么数据是有效的数据。只要有数据,系统就理所当然的认为它是有效的。
也许这种严重的问题并不多见,但是也绝不能掉以轻心。所以在定义一个变量时,第一件事就是初始化。你可以把它初始化为一个有效的值,比如:inti=10;char*p=(char*)malloc(sizeof(char));但是往往这个时候我们还不确定这个变量的初值,这样的话可以初始化为0或NULL。inti=0;char*p=NULL;如果定义的是数组的话,可以这样初始化:inta[10]={0};或者用memset函数来初始化为0:memset(a,0,sizeof(a));memset函数有三个参数,第一个是要被设置的内存起始地址;第二个参数是要被设置的值;第三个参数是要被设置的内存大小,单位为byte。这里并不想过多的讨论memset函数的用法,如果想了解更多,请参考相关资料。
至于指针变量如果未被初始化,会导致if语句或assert宏校验失败。这一点,上面已有分析。
四、内存越界内存分配成功,且已经初始化,但是操作越过了内存的边界。这种错误经常是由于操作数组或指针时出现“多1”或“少1”。比如:inta[10]={0};for(i=0;i<=10;i++){a[i]=i;}所以,for循环的循环变量一定要使用半开半闭的区间,而且如果不是特殊情况,循环变量尽量从0开始。
五、内存泄漏内存泄漏几乎是很难避免的,不管是老手还是新手,都存在这个问题。甚至包括windows,Linux这类软件,都或多或少有内存泄漏。也许对于一般的应用软件来说,这个问题似乎不是那么突出,重启一下也不会造成太大损失。但是如果你开发的是嵌入式系统软件呢?比如汽车制动系统,心脏起搏器等对安全要求非常高的系统。你总不能让心脏起搏器重启吧,人家阎王老爷是非常好客的。
会产生泄漏的内存就是堆上的内存(这里不讨论资源或句柄等泄漏情况),也就是说由malloc系列函数或new操作符分配的内存。如果用完之后没有及时free或delete,这块内存就无法释放,直到整个程序终止。
1、告老还乡求良田
怎么去理解这个内存分配和释放过程呢?先看下面这段对话:万岁爷:爱卿,你为朕立下了汗马功劳,想要何赏赐啊?某功臣:万岁,黄金白银,臣视之如粪土。臣年岁已老,欲告老还乡。臣乞良田千亩以荫后世,别无他求。万岁爷:爱卿,你劳苦功高,却仅要如此小赏,朕今天就如你所愿。户部刘侍郎,查看湖广一带是否还有千亩上等良田未曾封赏。刘侍郎:长沙尚有五万余亩上等良田未曾封赏。万岁爷:在长沙拨良田千亩封赏爱卿。爱卿,良田千亩,你欲何用啊?某功臣:谢万岁。长沙一带,适合种水稻,臣想用来种水稻。种水稻需要把田分为一亩一块,方便耕种。。。。。
2、如何使用malloc函数不要莫名其妙,其实上面这段小小的对话,就是malloc的使用过程。malloc是一个函数,专门用来从堆上分配内存。使用malloc函数需要几个要求:内存分配给谁?这里是把良田分配给某功臣。分配多大内存?这里是分配一千亩。是否还有足够内存分配?这里是还有足够良田分配。内存的将用来存储什么格式的数据,即内存用来做什么?这里是用来种水稻,需要把田分成一亩一块。分配好的内存在哪里?这里是在长沙。
如果这五点都确定,那内存就能分配。下面先看malloc函数的原型:(void*)malloc(intsize)malloc函数的返回值是一个void类型的指针,参数为int类型数据,即申请分配的内存大小,单位是byte。内存分配成功之后,malloc函数返回这块内存的首地址。你需要一个指针来接收这个地址。但是由于函数的返回值是void*类型的,所以必须强制转换成你所接收的类型。也就是说,这块内存将要用来存储什么类型的数据。比如:char*p=(char*)malloc(100);