user-0 提问: 指针问题

回复:
user: user-1
content: 引用 8 楼 zhao4zhong1 的回复:[quote=引用 5 楼 u013990248 的回复:] 我用的是linux C， 啊！！！怎么但不调试啊？？？？ GDB常用命令 调用gdb编译需要在cc后面加 -g参数再加-o； [root@redhat home]#gdb 调试文件：启动gdb (gdb) l ：（字母l）从第一行开始列出源码 (gdb) break n :在第n行处设置断点 (gdb) break func：在函数func()的入口处设置断点 (gdb) info break： 查看断点信息 (gdb) r：运行程序 (gdb) n：单步执行 (gdb) c：继续运行 (gdb) p 变量 ：打印变量的值 (gdb) bt：查看函数堆栈 (gdb) finish：退出函数 (gdb) shell 命令行：执行shell命令行 (gdb) set args 参数:指定运行时的参数 (gdb) show args：查看设置好的参数 (gdb) show paths:查看程序运行路径；            set environment varname [=value] 设置环境变量。如：set env USER=hchen；             show environment [varname] 查看环境变量； (gdb) cd 相当于shell的cd; (gdb)pwd ：显示当前所在目录 (gdb)info program： 来查看程序的是否在运行，进程号，被暂停的原因。 (gdb)clear 行号n：清除第n行的断点 (gdb)delete 断点号n：删除第n个断点 (gdb)disable 断点号n：暂停第n个断点 (gdb)enable 断点号n：开启第n个断点 (gdb)step：单步调试如果有函数调用，则进入函数；与命令n不同，n是不进入调用的函数的 list ：简记为 l ，其作用就是列出程序的源代码，默认每次显示10行。 list 行号：将显示当前文件以“行号”为中心的前后10行代码，如：list 12 list 函数名：将显示“函数名”所在函数的源代码，如：list main list ：不带参数，将接着上一次 list 命令的，输出下边的内容。 注意 ：如果运行list 命令得到类似如下的打印，那是因为在编译程序时没有加入 -g 选项： (gdb) list 1       ../sysdeps/i386/elf/start.S: No such file or directory.         in ../sysdeps/i386/elf/start.S run：简记为 r ，其作用是运行程序，当遇到断点后，程序会在断点处停止运行，等待用户输入下一步的命令。 回车：重复上一条命令。 set args：设置运行程序时的命令行参数，如：set args 33 55 show args：显示命令行参数 continue：简讯为 c ，其作用是继续运行被断点中断的程序。 break：为程序设置断点。 break 行号：在当前文件的“行号”处设置断点，如：break  33 break 函数名：在用户定义的函数“函数名”处设置断点，如：break cb_button info breakpoints：显示当前程序的断点设置情况 disable breakpoints Num：关闭断点“Num”，使其无效，其中“Num”为 info breakpoints 中显示的对应值 enable breakpoints Num：打开断点“Num”，使其重新生效 step：简记为 s ，单步跟踪程序，当遇到函数调用时，则进入此函数体（一般只进入用户自定义函数）。 next：简记为 n，单步跟踪程序，当遇到函数调用时，也不进入此函数体；此命令同 step 的主要区别是，step 遇到用户自定义的函数，将步进到函数中去运行，而 next 则直接调用函数，不会进入到函数体内。 until：当你厌倦了在一个循环体内单步跟踪时，这个命令可以运行程序直到退出循环体。 finish： 运行程序，直到当前函数完成返回，并打印函数返回时的堆栈地址和返回值及参数值等信息。 stepi或nexti：单步跟踪一些机器指令。 print 表达式：简记为 p ，其中“表达式”可以是任何当前正在被测试程序的有效表达式，比如当前正在调试C语言的程序，那么“表达式”可以是任何C语言的有效表达式，包括数字，变量甚至是函数调用。 print a：将显示整数 a 的值 print ++a：将把 a 中的值加1,并显示出来 print name：将显示字符串 name 的值 print gdb_test(22)：将以整数22作为参数调用 gdb_test() 函数 print gdb_test(a)：将以变量 a 作为参数调用 gdb_test() 函数 bt：显示当前程序的函数调用堆栈。 display 表达式：在单步运行时将非常有用，使用display命令设置一个表达式后，它将在每次单步进行指令后，紧接着输出被设置的表达式及值。如： display a watch 表达式：设置一个监视点，一旦被监视的“表达式”的值改变，gdb将强行终止正在被调试的程序。如： watch a kill：将强行终止当前正在调试的程序 help 命令：help 命令将显示“命令”的常用帮助信息 call 函数(参数)：调用“函数”，并传递“参数”，如：call  gdb_test(55) layout：用于分割窗口，可以一边查看代码，一边测试： layout src：显示源代码窗口 layout asm：显示反汇编窗口 layout regs：显示源代码/反汇编和CPU寄存器窗口 layout split：显示源代码和反汇编窗口 Ctrl + L：刷新窗口 quit：简记为 q ，退出gdb 当然，gdb的功能远不止这些，包括多进程/多线程/信号/远程调试等功能在这里均没有提及，有需要的读者可以参考其它信息 本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/pizi0475/archive/2011/03/08/6232749.aspx [/quote]   大神啊， 我就需要这个， lz可以试试这个， 这个调试比用printf（“aaaaaaaaaaaa\n”）；的方法好多了（linux系统上）

user: user-2
content: 少年啊，千万要重视单步调试和设置断点， 用VC调试时记得按下Alt+5、Alt+6、Alt+7和Alt+8。   对学习编程者的忠告： 眼过千遍不如手过一遍！ 书看千行不如手敲一行！ 手敲千行不如单步一行！ 单步源代码千行不如单步对应汇编一行！  VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和 寄存器变化，这样过一遍不就啥都明白了吗。 对VC来说，所谓‘调试时’就是编译连接通过以后，按F10或F11键单步执行一步以后的时候，或者在某行按F9设了断点后按F5执行停在该断点处的时 候。

user: user-3
content: 崩溃的时候在弹出的对话框按相应按钮进入调试，按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。

user: user-4
content: 调试啊？？跟踪变量的值，这个应该自己可以解决的吧

user: user-5
content: 1 #include <stdio.h>   2 #include <stdlib.h>   3   4 int func(int *data, int m_c, int m_r, int *key, int n_r, int n_c, int **re)   5 {   6         int     i;   7         (* re)=malloc(sizeof(int *)*m_c);   8         for(i=0; i<m_r; i++){   9                 re      = malloc(sizeof(int)*m_r);  10         }  11         for(i=0; i<m_c*m_r; i++){    //这里读取2 * 3 = 6个值  12                 (*re)[i]        = data[i]-key[i];  //但data和key里都只有5个元素  13                 printf("%d\n", (*re)[i]);         //读到data[5]和key[5]时就越出数组边界了  14         }  15 }  16  17 int main()  18 {  19         int data[]={1, 2, 3, 4, 5};  //你这里只有5个元素，而运行时却要读取 2 * 3 = 6 个值，  20         int key[]={1, 1, 1, 1, 1};   //这样就会出现segment fault了  21         int *re;  22         func(data, 2, 3, key, 2, 3, &re);  23 }

user: user-3
content: 引用 5 楼 u013990248 的回复:我用的是linux C， 啊！！！怎么但不调试啊？？？？ GDB常用命令 调用gdb编译需要在cc后面加 -g参数再加-o； [root@redhat home]#gdb 调试文件：启动gdb (gdb) l ：（字母l）从第一行开始列出源码 (gdb) break n :在第n行处设置断点 (gdb) break func：在函数func()的入口处设置断点 (gdb) info break： 查看断点信息 (gdb) r：运行程序 (gdb) n：单步执行 (gdb) c：继续运行 (gdb) p 变量 ：打印变量的值 (gdb) bt：查看函数堆栈 (gdb) finish：退出函数 (gdb) shell 命令行：执行shell命令行 (gdb) set args 参数:指定运行时的参数 (gdb) show args：查看设置好的参数 (gdb) show paths:查看程序运行路径；            set environment varname [=value] 设置环境变量。如：set env USER=hchen；             show environment [varname] 查看环境变量； (gdb) cd 相当于shell的cd; (gdb)pwd ：显示当前所在目录 (gdb)info program： 来查看程序的是否在运行，进程号，被暂停的原因。 (gdb)clear 行号n：清除第n行的断点 (gdb)delete 断点号n：删除第n个断点 (gdb)disable 断点号n：暂停第n个断点 (gdb)enable 断点号n：开启第n个断点 (gdb)step：单步调试如果有函数调用，则进入函数；与命令n不同，n是不进入调用的函数的 list ：简记为 l ，其作用就是列出程序的源代码，默认每次显示10行。 list 行号：将显示当前文件以“行号”为中心的前后10行代码，如：list 12 list 函数名：将显示“函数名”所在函数的源代码，如：list main list ：不带参数，将接着上一次 list 命令的，输出下边的内容。 注意 ：如果运行list 命令得到类似如下的打印，那是因为在编译程序时没有加入 -g 选项： (gdb) list 1       ../sysdeps/i386/elf/start.S: No such file or directory.         in ../sysdeps/i386/elf/start.S run：简记为 r ，其作用是运行程序，当遇到断点后，程序会在断点处停止运行，等待用户输入下一步的命令。 回车：重复上一条命令。 set args：设置运行程序时的命令行参数，如：set args 33 55 show args：显示命令行参数 continue：简讯为 c ，其作用是继续运行被断点中断的程序。 break：为程序设置断点。 break 行号：在当前文件的“行号”处设置断点，如：break  33 break 函数名：在用户定义的函数“函数名”处设置断点，如：break cb_button info breakpoints：显示当前程序的断点设置情况 disable breakpoints Num：关闭断点“Num”，使其无效，其中“Num”为 info breakpoints 中显示的对应值 enable breakpoints Num：打开断点“Num”，使其重新生效 step：简记为 s ，单步跟踪程序，当遇到函数调用时，则进入此函数体（一般只进入用户自定义函数）。 next：简记为 n，单步跟踪程序，当遇到函数调用时，也不进入此函数体；此命令同 step 的主要区别是，step 遇到用户自定义的函数，将步进到函数中去运行，而 next 则直接调用函数，不会进入到函数体内。 until：当你厌倦了在一个循环体内单步跟踪时，这个命令可以运行程序直到退出循环体。 finish： 运行程序，直到当前函数完成返回，并打印函数返回时的堆栈地址和返回值及参数值等信息。 stepi或nexti：单步跟踪一些机器指令。 print 表达式：简记为 p ，其中“表达式”可以是任何当前正在被测试程序的有效表达式，比如当前正在调试C语言的程序，那么“表达式”可以是任何C语言的有效表达式，包括数字，变量甚至是函数调用。 print a：将显示整数 a 的值 print ++a：将把 a 中的值加1,并显示出来 print name：将显示字符串 name 的值 print gdb_test(22)：将以整数22作为参数调用 gdb_test() 函数 print gdb_test(a)：将以变量 a 作为参数调用 gdb_test() 函数 bt：显示当前程序的函数调用堆栈。 display 表达式：在单步运行时将非常有用，使用display命令设置一个表达式后，它将在每次单步进行指令后，紧接着输出被设置的表达式及值。如： display a watch 表达式：设置一个监视点，一旦被监视的“表达式”的值改变，gdb将强行终止正在被调试的程序。如： watch a kill：将强行终止当前正在调试的程序 help 命令：help 命令将显示“命令”的常用帮助信息 call 函数(参数)：调用“函数”，并传递“参数”，如：call  gdb_test(55) layout：用于分割窗口，可以一边查看代码，一边测试： layout src：显示源代码窗口 layout asm：显示反汇编窗口 layout regs：显示源代码/反汇编和CPU寄存器窗口 layout split：显示源代码和反汇编窗口 Ctrl + L：刷新窗口 quit：简记为 q ，退出gdb 当然，gdb的功能远不止这些，包括多进程/多线程/信号/远程调试等功能在这里均没有提及，有需要的读者可以参考其它信息 本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/pizi0475/archive/2011/03/08/6232749.aspx

user: user-6
content: 动态分配的内存，可不可以，把2维数组当做一维数组用，要看分配的方式。 如果是一次性分配足够的空间，那么就可以，否则不可以。 另外，二级指针参数，不可以传回的分配给二级指针的内存，因为参数传递是值传递。  1）如果是这样就可以把 p [0] ,看做一维数组,有row *col个元素 int i; int **p = malloc(row * sizeof(int *) ); p[0] =  malloc(row *col* sizeof(int) ); for(i =1;i<row;i++)p[i] =p[0]+i * col; //或者 p[ i ] =p[ i - 1]+ col;   2）如果是这样，因为不能保证，内存的连续性 ---实际上几乎完全不可能连续--- 所以就不可以  int i;int **p = malloc(row * sizeof(int *) ); for(i =0;i<row;i++)p[i] =  malloc(col* sizeof(int) );  通过参数，回传这个二级指针，需要三级指针 ---一个二级指针的地址-- 来保存这个二级指针。 不然就通过返回值传递。   #include <stdio.h>   #include <stdlib.h>   //矩阵相加减，要求二者的行数和列数都相等  // 所以只需要传递一个行数，一个列数参数。 //1）二级分配，传递二级指针的地址--三级指针     int func(int *data, int m_c, int m_r, int *key, int ***re)    {            int     i,j;            * re = (int **) malloc(sizeof(int *)*m_c);            for(i=0; i<m_c; i++){                    re[i]     = malloc(sizeof(int)*m_r);           }           for(i=0; i<m_c i++){                 for(j=0;j<m_r;j++){                         (*re)[i][j]        = data[i[j]-key[i][j];                        printf("%d\n", (*re)[i][j]);                 }          } return 0;   }     int main()   {           int data[]={1, 2, 3, 4, 5};           int key[]={1, 1, 1, 1, 1};           int **re,i;           func(data, 2, 3, key,&re);          //结果是 re[0] 不能看作一级指针，因为re[0],re[1] 不连续。          for(i=0;i<2;i++){          free(re[i]);           }          free(re);           return 0;  }  #include <stdio.h>   #include <stdlib.h>   //一次分配，传递一级指针的地址，二级指针    int func(int *data, int m_c, int  m_r , int *key ,int **re)    {            int     i;           *re =(int *) malloc (sizeof(int ) *m_c *m_r);//直接分配足够的内存           for(i=0; i<m_c*m_r; i++){                   (*re)[i]    = data[i]-key[i];                  printf("%d\n", (*re)[i]);          }          return 0;   }     int main()   {           int data[]={1, 2, 3, 4, 5};           int key[]={1, 1, 1, 1, 1};           int *re;           func(data, 2, 3, key, 2, 3, &re);           // re就是一级指针，所以是连续的。如果要保证可以当做二维数组用，           // 分配一个二级指针，把re封装起来就可以了          // {         //      int **mat =(int **)malloc(sizeof(int*) *2);           //     for(i=0,re;i<2;i++) mat[i] = re + i*3;          //    ......           //   这里 二级指针mat， 就可以看做二维数组了          //     free(mat);          //     }                                 free(re);          return 0;  }

user: user-0
content: 我用的是linux C， 啊！！！怎么但不调试啊？？？？

user: user-7
content: for(i=0; i<m_c; i++){                                             //m_c ? m_r? 越界                re      = malloc(sizeof(int)*m_r);  }