C/C++指针错误与调试相关学习总结

使用VS2010调试技巧让C指针无处遁形

http://blog.csdn.net/21aspnet/article/details/6723758  

Linux 下调试远没有windows下的VS方便,不管是VC++6还是VS2003,2005,2008,2010,2012.
VS2012自动格式化代码 Ctrl+K+D
VS下调试一定要注意尽量不要用F11,要用F10!不然需要引入库文件,提示的警告信息可以“忽略”即可
所以我觉得不妨用VS调试程序,可以用VS来研究C语言似乎是一个比较不错的主意,当你的C已经很好的时候可以直接在linux下去手写代码了。
当然windows下写的C程序放到Linux下运行,也是可以的,不过需要知道的是有些语法Windows下支持但是Linux下是不支持。
还有时会有乱码,需要注意!注意!
其实微软是希望用C++的,所以默认VS2010是用来开发C++的。准确的说是VC++。
 
首先装好VS2012.
新建一个VC++的 win32控制台项目:
 
然后“欢迎使用 Win32 应用程序向导”下一步,需要注意的是附加类型勾上“空项目”,再完成
 
系统自动生成解决方案文件夹,在右侧“解决方案”中的“源文件”中新建文件即可。
 
弹出的窗口默认选中的是C++的cpp文件,你只要将文件名改为.c即可,也可以点左边“代码”菜单筛选下。
 
自己写代码:

#include <stdio.h>  
main()  
{  
    int a=1;  
    int * b=&a;  
    printf("%d",b);    
}  

然后在printf处设置断点。
 
按F5启动调式。

在“监视”窗口,你可以自己添加需要监视的元素,很清晰的看到内存的值在右侧。
也可以使用 命令和即时窗口 有兴趣可以自己研究。
 
再来看看字符串指针:

#include <stdio.h>  
main()  
{  
    //int a=1;  
    //int * b=&a;  
    char * c="abcama1w";  
    char *d=c;  
    printf("%s",d);    
}  

是不是很清晰。
再看数组

#include <stdio.h>  
main()  
{  
    //int a=1;  
    //int * b=&a;  
    char c[12]="abcama1w";  
    char *d=c;  
    printf("%s",d);    
}  

下面这张图更清晰的反映数组和指针的关系

再看看d
========

C语言指针错误的分析及调试

全文见此
http://www.c-s-a.org.cn/ch/reader/view_abstract.aspx?file_no=20130336

摘要
C语言指针的有些错误在程序编译阶段难以发现,分析了带有此类错误的示例程序,并在VC6.0进行调试,展示此类指针错误的错误现象,分析其产生的原因;

2指针错误的分析及调试
2.1 指针在使用前未初始化
VC编译时产生警告C4700,应检查指针是否初始化;
2.2 指针指向的内存已经释放
2.3 指针指向的地址越界
========

C语言指针的运用及常见错误

全文
https://wenku.baidu.com/view/341895c56529647d27285267.html

*和[]在定义时只是说明作用,不能误解为运算符
指针变量未初始化
指针类型错误
用整数值直接给指针赋值
指针偏移
指针之间相互赋值
========

C语言 运行后出现乱码的结果,调试中发现提示错误的指针

#include "stdafx.h" #include<string> char *concat(const char *s1,const char *s2) { char *result; result=(char *)malloc(strlen(s1)+strlen(s2)+1); if(result==NULL){ printf("error:malloc faineled in concat\n"); exit(EXIT... 展开

if(result==NULL)
{
    printf("error:malloc faineled in concat\n");
    exit(EXIT_FAILURE);
}  
strcpy(result,s1);
strcat(result,s2);
少头文件#include<stdlib.h>,中间这么改
========

C语言调试时文件指针FILE *fp出错

这段调试时出错。。 printf("您选择的是:编号\n请选择您要查询的编号:\n"); scanf("%s",bianhao); while(1) { FILE *fp1=fopen("my.dat","r"); if(fgets(buff,1024,fp1)==NULL) break; if(strcmp(&buff[0],bianhao)==0) ... 展开

printf("您选择的是:编号\n请选择您要查询的编号:\n");
scanf("%s",bianhao);
 //本来你的程序是这样的    
FILE *fp1=fopen("my.dat","r");//文件只能打开一次 不能重复打开
 while(1)
{
 if(fgets(buff,1024,fp1)==NULL)
  break;
 if(strcmp(buff,bianhao)==0)//这里比较字符串不用取地址
  printf("%s",buff);
}
fclose(fp1);
//不过你的要求是 {第一个字符 等于输入的值  }那应该是这样     
printf("您选择的是:编号\n请选择您要查询的编号:\n");
scanf("%c",bianhao);//这里的bianhao是char 不是 char[]
FILE *fp1=fopen("my.dat","r");
 while(1)
{
    if(fgets(buff,1024,fp1)==NULL)
  break;
 if(buff[0] == bianhao)
  printf("%s",buff);
}
fclose(fp1);
//但是这样显然不符合逻辑 编号应该是多个字符 所以也可能是这样
printf("您选择的是:编号\n请选择您要查询的编号:\n");
scanf("%s",bianhao);//依然输入 char[]
FILE *fp1=fopen("my.dat","r");
 while(1)
{
    if(fgets(buff,1024,fp1)==NULL)
  break;
 if(strncmp(buff,bianhao, strlen(bianhao))==0)//这里的函数改成strncmp 具体意思去百度
  printf("%s",buff);
}
fclose(fp1);

FILE *fp1=fopen("my.dat","r");
主要是这里的问题... 改成绝对路径就没事了.. 但是我想要相对于程序的路径 该怎么改?
追答
什么意思 程序相对的路径 你指的是exe运行目录 或者 exe的上一个目录么
./表示 exe目录 ../表示exe上一个
注意exe在哪里。。
========

c语言如何能快速调试判断出程序在哪里出现了指针错误而中断

在程序很复杂的情况下

看出错时候的堆栈调用情况
或者
OD载入看异常断点
========

C++程序设计之指针与调试

本人学习C++的过程经验及总结,本文内容:

调试与动态内存分配

工具/原料
vs2015
C中的内存管理 
1
C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。
malloc
calloc
free
realloc
2
malloc,在内存的动态存储区中分配一块长度为“size”字节的连续区域。
函数原型
    (类型说明符*) malloc (size) 

3
使用malloc函数需要注意。
1、内存分配函数向系统申请内存空间,它的地址是随机的,取决于内存占用的状态。
2、函数调用后,分配的内存空间的内容并不初始化,因此它的取值是无法确定的。
3、如果内存不足,内存分配失败,函数返回值将是一个空指针。
4、分配的内存空间可以认为是各种数据类型的,也可以认为是数组。
5、参数size一般需要借助sizeof运算符计算类型大小,也可以直接指定内存块的字节数。
4
calloc,在内存动态存储区中分配n块长度为“size”字节的连续区域。
函数原型
      (类型说明符*)calloc(n,size) 

5
free,释放ptr所指向的一块内存空间。
函数原型
       void free(void* ptr); 
注:ptr指向的必须是一块用malloc或calloc分配的内存空间。
6
realloc,当一块内存大小不够使用时,可以用realloc函数进行重新分配。
函数原型
       void *realloc( void *ptr, size_t size );
注:realloc改变了内存块的大小,但并不保证新的内存块和旧内存块是从同一个位置开始的。
END
C++中的内存管理
1
C++动态内存分配运算符new和delete比C语言的malloc和free函数更简洁,语法更灵活。
new
delete
2
new,返回一个该类型的指针值,程序通过指针对这个变量进行操作。
C++程序设计之指针与调试
3
new与malloc对比。
都要指出变量的类型,类型名要放在new之后。
都可以赋初值,不是用“=初值”的方式而是用“(初值) ”的方式,
C++程序设计之指针与调试
4
可以定义为数组,加数组运算符[ ],用[ ]运算符申请的内存称为动态数组。
char *pc=new char[4];  //生成动态char 类型数组
动态变量没有变量名,须用指针变量接收到它的地址后,通过指针运算符“*”进行操作。
*pi=a*a;   //动态变量*pi 被赋值
5
delete,delete运算用来撤消或释放由new生成的动态变量。

6
使用内存管理函数时需要注意
1、释放动态数组时,应该在指针前加[]。
2、内存管理函数是一一对应,new与delete对应;malloc与free对应。
3、动态变量与一般变量的主要区别就是它可以在程序运行过程中任意被撤销。而一般变量则必须在其所定义的程序块结束时自动撤销。
END
内存区域
1
       在C/C++程序中,不管是局部变量,全局变量、或是动态变量,在内存中都占用一定的空间,但是它们占用不同的空间。
       一个程序将操作系统分配给其运行的内存分成4个区域。
C++程序设计之指针与调试
2
•代码区
存储程序代码,这些代码是一些计算机指令,它们将被送到CPU中执行。代码区由程序中各个函数的代码组成。
•全局数据区
存储程序的全局数据和静态数据。全局数据区的数据在程序启动时初始化,占用的内存在程序结束时才释放。
•堆区
存储程序的动态数据,包括用new和malloc等函数分配的动态内存,它们是可以在程序运行的任何时候分配和释放的。
•栈区
存储程序的局部数据,即各个函数内部使用的数据。例如在函数形参和函数内部定义的变量。函数在执行完毕后,函数内部使用的内存将会被自动释放
3
未初始化的指针
指针未初始化就进行间接引用是错误的。

END
常见指针错误
1
使用坏指针
       当指针指向的内存被释放后,指针仍然指向那个地址,这个指针通常被称作“坏指针”。
       当动态内存被释放后,不能再使用指针访问该内存。
C++程序设计之指针与调试
2
函数返回局部变量的指针
   指向局部变量的指针,指向它的指针只能在函数调用期间(函数返回前)进行间接引用。
C++程序设计之指针与调试
3
空指针的间接引用
    一般地,在函数开头要对指针进行判断。如果函数不允许空指针,那么更好的方法是使用assert增加断言,方便程序的调试,也不影响程序的发布版本的效率。

END
内存泄漏
1
       在使用动态变量时应注意的是,要保护动态变量的地址。
       动态内存地址丢失,导致内存无法使用,这种问题被称为内存泄漏。
       内存泄漏造成程序运行缓慢。动态内存泄漏会抢占内存资源,降低运行速度,甚至导致蓝屏死机。


2
      在访问一段连续的内存时,如果访问了这块连续存储空间以外的内存,那么就发生了内存访问越界。内存访问越界将会造成未知错误,极易引起程序崩溃。
      内存访问越界通常发生在使用数组时。


END
Visual C++.NET调试
1
代码编写完成后,源代码要被转换为计算机可以识别的指令,每个源文件都要被编译为中间文件,然后,所有的中间文件被链接称为.exe文件。
•【生成解决方案】
让Visual Studio.NET编译各个源文件,并将它们链接成为.exe文件或其他形式的程序文件。
•【重新生成解决方案】
让编译器重新编译所有源文件。
•【清理解决方案】
清除解决方案在以前生成可执行文件时产生的旧文件。第一次生成解决方案时,源文件都会被编译一次,此后再生成解决方案时,如果某个源文件没被修改过,这个源文件将不会被重新编译。
       生成一个解决方案后,会在【输出窗口】中显示日志,编译中发现的错误将会被列出。双击包含“error”的行,可以迅速切换到出错的代码。编译文件时,还可能出现另一种信息,即警告信息,这些警告提示了程序中潜在的错误。
2
断点的使用
      在程序代码中某些位置设置一些断点,令程序执行到这些代码时暂停,此时可以查看程序运行中变量的变化情况,以便判断程序运行是否正常。
       在Visual Studio.NET中,将光标移动到一行代码,按“F9”键,即在这行设置了断点,在代码行上会有一个红色圆点。还可以右击弹出快捷菜单,选择菜单中的【插入断点】。
C++程序设计之指针与调试
3
单击菜单【调试】→【启动】运行程序后,当程序运行到断点行时暂停执行。暂停执行时,当前代码行用箭头标示。鼠标移动到变量上时,会提示变量内容。同时也可以借助其他工具查看内存内容。
C++程序设计之指针与调试
4
•【局部变量】
在代码编辑器下边的【局部变量】标签中,可以查看断点所在函数的局部变量。这些变量的名称、值和类型会在表格中列出。变量的值可以在表格中修改。
•【自动窗口】
【自动窗口】中可以显示当前代码附近的变量的状态。
•【监视】
还可以使用【监视】窗口随时查看指定的变量。单击表格中的空行,在名称中输入变量名或表达式,即可在表格中显示这个变量的值和类型。另一种方法是选择变量,然后按“Alt+Ctrl+Q”在弹出的对话框中添加监视。
C++程序设计之指针与调试
5
单步执行
使用单步命令让程序一次只执行一行或多行代码
•逐语句
即每次执行一条语句,如果遇到函数,跳转到函数内部的语句。快捷键为“F11”。
•逐过程
在当前函数内执行一条语句或函数(函数又称过程),不跳转到被调用的函数中。快捷键为“F10”
•跳出
让程序继续执行,在当前函数调的调用语句后的一条语句暂停执行。
6
调用当前函数的状态被保存在一个叫做“调用堆栈”的数据结构中,查看它,可以了解程序中函数的调用次序。在【调用堆栈】窗口中,可以查看函数的调用过程,也可以双击窗口中的函数名称显示对应的函数代码。
========

指针调试怪象分析和解决:无法查看指针指向变量的值

http://www.cjjjs.com/paper/xmkf/2016109105018607.aspx


[摘要] 当我将光标放在指针变量上面时,没有任何提示,不过其他局部变量是有提示的。在VS环境下,调试非常方便的,只要将光标放在断点处的变量上,就可以看到变量的值。此时却没有提示指针所指向的值。


  最近在做TCP通信的监控程序,也就是Socket通信。在接受到数据后,为了效率,就直接将指针传递给上层,然后上层逻辑就取出指针指向的内容进行判断分析和处理。
    所有的通信命令即协议里规定的一问一答式的命令,都是使用同一个缓冲区来接受数据的。整个通信基础使用的是完成端口,所有数据到来都是排队有序的向上传递,所以不会遗漏数据。所以,可以使用一个缓冲区一个个的来接受和处理数据。
    然而,如果出现了问题,那就要调试。调试的时候,将断点打在了处理命令的位置。然而,当运行到断点处时,也就是收到了对应的命令的时候,程序运行停下来了,并进入了调试状态。然而问题来了。当我将光标放在指针变量上面时,没有任何提示,不过其他局部变量是有提示的。在VS环境下,调试非常方便的,只要将光标放在断点处的变量上,就可以看到变量的值。此时却没有提示指针所指向的值。
    一开始,我以为是不是VS出现了Bug,或者是代码编译的不完整,所以重新生成了解决方案好几次,依然如此。如果说是Bug,那其他局部变量却可以提示值,也说不过去。


========

关于指针与调试的一个小问题

写了一个程序,按F5调试,在下面这一句停了下来。 if((ptr -> pNext == NULL) || (ptr -> pNext -> elem[0] > s) && (ptr -> elem[0] <= s)) 这一句有什么问题吗?前面是这样的: 在另一个函数中有: ptr = (CA *)malloc(sizeof(CA)); if(!ptr) { printf(... 展开

如果ptr -> pNext = NULL;
那ptr -> pNext -> elem[0]元素在哪里呢?
最开始的时候,ptr -> pNext肯定是NULL的,所以ptr -> pNext -> elem[0]读不到。报错了撒~

不是在 || 的两端只要一端为真就行吗?难道。。。这个判断顺序不是从左到右?!!

程序在试图读取ptr -> pNext -> elem[0]的值的时候就已经出错了。。因为这块内存你没有定义。。。

能先发个源码您看看吗?300多行

if((ptr -> pNext == NULL) || (ptr -> pNext -> elem[0] > s) && (ptr -> elem[0] <= s))
由于 && 比 || 的优先级高
所以这句话的执行顺序是这样的
if( ((ptr -> pNext == NULL) || (ptr -> pNext -> elem[0] > s)) && (ptr -> elem[0] <= s))
这样,当 ptr -> pNext == NULL 成立时,再运行 ptr -> pNext -> elem[0] > s 就会产生错误
改成下面这样就行了
if((ptr -> pNext == NULL) || ((ptr -> pNext -> elem[0] > s) && (ptr -> elem[0] <= s)) )

我觉得你说的不对,正因为 && 的优先级比 || 高,所以要表示if((ptr -> pNext == NULL) ||   ((ptr -> pNext -> elem[0] > s) && (ptr -> elem[0] <= s))  ) ,去掉括号效果是一样的

编译器会默认将 &&左边的所有语句 和 &&右边的所有语句 看成是 2 个语句

不是吧高手,比如18 - 3 * 6,因为 * 的优先级高所以先算 * 啊,&&的优先级高,所以先算&&啊
========

s2010尝试运行项目时出错,无效指针

 
有些人说是IntelliTrace的原因,但我这项根本就是关闭的,


两个解决方法:
1) 打开项目属性,选择调试选项卡,将“启用非托管代码调试”一项钩上。
2) 打开项目属性,选择调试选项卡,将“启用Visual Studio宿主进程“一项钩掉。
========

我下载VC2015 调试出现无效指针弹窗

cvc2015c++vc++visual studio 2015
请问我下载VC2015 按F5 出现无效指针弹窗。


rebuild,
1>------ 已启动全部重新生成: 项目: ConsoleApplication, 配置: Debug Win32 ------
1> main.cpp
1> ConsoleApplication.vcxproj -> D:\Documents\Visual Studio 2015\project\ConsoleApplication\Debug\ConsoleApplication.exe
========== 全部重新生成: 成功 1 个,失败 0 个,跳过 0 个 ==========
clean
1>------ 已启动清理: 项目: ConsoleApplication, 配置: Debug Win32 ------
========== 清理: 成功 1 个,失败 0 个,跳过 0 个 ==========
都可以正确运行,
唯独F5断点调试的时候有一个
图片说明
其他功能都没有问题, 只有这一个, 代码是最最简单的。
我的系统是win7 64 , 求大神解救
 
工具—>调试—>常规”下,将“要求源文件与原始版本完全匹配”这一项打钩,重新编译。


评论 PYXFighting PYXFighting 谢谢您的回答 ,, 没有用,, 那个勾之前就有 。。 
========

vs2013调试时弹出一个“无效指针”错误

代码是没错的,就是vs中间安装过一次更新,安完以后之前能调试的代码现在也不能调试成功了
 
新建一个没有指针的最简单工程试试,如果依然如此,那么应该是更新安装失败了,推荐卸载VS重新装一个。
如果新建各种工程都没有这个问题,那么应该是更新后代码检查更严格了吧,单步调试看看哪里的报错。(也就是说,还是代码问题,不是调试可以运行的代码就一定没有问题的)


auto scene=.....这步定义的是个指针是在函数内部,是个局部变量,当这个函数结束,其所指的位于栈上的内存空间要被释放,scene就变成无效指针了。不知指向谁。堆和栈的区别
一个由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其
操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回
收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的
全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另
一块区域。 - 程序结束后由系统释放。
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
二、例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456\0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"
优化成一个地方。
}


这是你手打的吗,太感谢了,不过现在vs连输出helloword都会报错,我修复下vs试试
========

关于VS打开cshtml出现 未能完成该操作 无效指针



第一步:关闭VS


第二部:删除%LocalAppData%\Microsoft\VisualStudio\14.0\ComponentModelCache


第三部:重新打开


也可以试试修复VS看行不行!
========

我用vs2010的vb编程时出现:无效指针



VS2010可选择框架
删除重新添加引用,bin目录是否有DLL


我曾用vB6.0,现在在Vs中打入Textbox1.texe=‘‘MN’’
执行时就弹出无效指针
========

猜你喜欢

转载自blog.csdn.net/bcbobo21cn/article/details/77141337