关于函数返回指针的 问题!!

软件和网站开发以及相关技术探讨
回复
csuqc19841001
帖子: 10
注册时间: 2007-11-03 11:35

关于函数返回指针的 问题!!

#1

帖子 csuqc19841001 » 2008-01-06 20:44

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char *test( int num )
{
char *p = (char *)malloc( sizeof( char )*num );
return p;
}

int main( void )
{
char *p = NULL;
p = test( 10 ); //故意是申请的空间小于要拷贝的内容
strcpy( p , "hello! world rutrueiyteiy " );
printf("string *p: %s\n",p);
while( *p != '\0' )
printf("%c ",*p++);

return 0;
}
按照书上说的肯定是 不能 正确运行的 阿 ,但是在ubuntu上面:
程序能够正常运行:
qc@qc-laptop:/home/q$ cc -o t t.c
qc@qc-laptop:/home/q$ ./t
string *p: hello! world rutrueiyteiy
h e l l o ! w o r l d r u t r u e i y t e i y qc@qc-laptop:/home/q$

请问:不是 说不能返回指向动态内存的指针马?
还有 很明显申请的内存空间小于需要的空间???
头像
bones7456
帖子: 8495
注册时间: 2006-04-12 20:05
来自: 杭州
联系:

#2

帖子 bones7456 » 2008-01-06 21:10

这个要看编译器了,世上没有绝对的事情,嘿嘿。
用gcc试试。
关注我的blog: ε==3
dbzhang800
帖子: 3182
注册时间: 2006-03-10 15:10
来自: xi'an China
联系:

#3

帖子 dbzhang800 » 2008-01-06 21:12

好好学学C语言先。

指针是C语言中最强大,最容易被滥用,也最容易出错的。

你必须自己检查你分配的中间是否足够大,访问数组是否越界等问题。编译器只会按你写的程序工作,而不是按照你所想的东西工作。

所以,确保你写的是你所想的。 程序在某种境况下能正常工作并不能说明程序是正确的,特别是用指针的时候,要格外小心。
头像
shellex
帖子: 2180
注册时间: 2007-02-18 19:33
系统: OSX
来自: lyric.im
联系:

#4

帖子 shellex » 2008-01-06 21:26

ls说俄虾米啊,都不对路
我告诉你。linux上gcc在堆上会分配冗余空间,,貌似按照8还是16 byte的倍数分配。所以可以...
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

#5

帖子 eexpress » 2008-01-06 22:49

嗯。是后面有空间。多定义几个指针试试。就段错误了。
● 鸣学
dbzhang800
帖子: 3182
注册时间: 2006-03-10 15:10
来自: xi'an China
联系:

#6

帖子 dbzhang800 » 2008-01-06 23:09

shellex 写了:ls说俄虾米啊,都不对路
我告诉你。linux上gcc在堆上会分配冗余空间,,貌似按照8还是16 byte的倍数分配。所以可以...
楼主关注的应该不是这个问题。

可以负责任的告诉你,楼主的这个程序不止是在linux下gcc编译后可以执行,而且windows下不论用gcc还是vc编译后也都可以正常运行。
而且在Solaris下不论你用gcc,还是sun的的CC编译器,生成的可执行文件都是可正常执行的。


我想强调的是,用指针或数组的时候,要自己检查自己用的是不是正确,因为这类的错误编译器往往帮不上忙。而且会给你一种太平的假象。
头像
shellex
帖子: 2180
注册时间: 2007-02-18 19:33
系统: OSX
来自: lyric.im
联系:

#7

帖子 shellex » 2008-01-07 6:30

dbzhang800 写了:
shellex 写了:ls说俄虾米啊,都不对路
我告诉你。linux上gcc在堆上会分配冗余空间,,貌似按照8还是16 byte的倍数分配。所以可以...
楼主关注的应该不是这个问题。

可以负责任的告诉你,楼主的这个程序不止是在linux下gcc编译后可以执行,而且windows下不论用gcc还是vc编译后也都可以正常运行。
而且在Solaris下不论你用gcc,还是sun的的CC编译器,生成的可执行文件都是可正常执行的。


我想强调的是,用指针或数组的时候,要自己检查自己用的是不是正确,因为这类的错误编译器往往帮不上忙。而且会给你一种太平的假象。
哼,楼主就是在故意出错以获取缓冲区溢出的第一手资料。
但是你强调得对。
头像
bones7456
帖子: 8495
注册时间: 2006-04-12 20:05
来自: 杭州
联系:

#8

帖子 bones7456 » 2008-01-07 8:57

代码: 全选

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char *test( int num )
{
char *p = (char *)malloc( sizeof( char )*num );
return p;
}

int main( void )
{
char *p = NULL;
char *q = NULL;
p = test( 10 ); //故意是申请的空间小于要拷贝的内容
q = (char *)malloc(sizeof(char)*10);
strcpy( q, "hello" );
printf( "q=%s\n", q);
strcpy( p , "hello! world rutrueiyteiy " );
printf( "now q=%s\n", q);
printf("string *p: %s\n",p);
while( *p != '\0' )
printf("%c ",*p++);

return 0;
}
执行结果:
$ ./a.out
q=hello
now q=rueiyteiy
string *p: hello! world rutrueiyteiy
h e l l o ! w o r l d r u t r u e i y t e i y
看到q的变化没?因为给p赋了超长的值,q受到影响了.这也许是LZ想要的错误.
关注我的blog: ε==3
头像
hubert_star
论坛版主
帖子: 5373
注册时间: 2007-10-29 22:12
系统: OSX 10.9 + Ub 1304
来自: 江苏南京

#9

帖子 hubert_star » 2008-01-07 8:58

首先看源代码

这是strcpy的源代码:

代码: 全选


char *
strcpy (dest, src)
     char *dest;
     const char *src;
{
  reg_char c;
  char *__unbounded s = (char *__unbounded) CHECK_BOUNDS_LOW (src);
  const ptrdiff_t off = CHECK_BOUNDS_LOW (dest) - s - 1;
  size_t n;

  do
    {
      c = *s++;
      s[off] = c;
    }
  while (c != '\0');

  n = s - src;
  (void) CHECK_BOUNDS_HIGH (src + n);
  (void) CHECK_BOUNDS_HIGH (dest + n);

  return dest;
}
libc_hidden_builtin_def (strcpy)


不带长度参数的c字符串一般都会有溢出的情况

但是溢出的数据会不会导致程序段错误还要看边界情况,否则只会影响内部变量而不会导致程序段错误
上次由 hubert_star 在 2008-01-07 9:21,总共编辑 2 次。
佛经说,人有八苦: 生、老、病、死、求不得、怨憎、爱别离、五阴盛 故我苦!
圣经说,人有七罪: 饕餮、贪婪、懒惰、淫欲、傲慢、嫉妒和暴怒  故我有罪!

我这篇帖子里面没有任何攻击我们伟大的中华人民共和国政府和任劳任怨的人民公仆(和本论坛高素质的版主)的文字和含义;

特此声明!

有些事,我们明知道是错的,也要去坚持,因为不甘心;有些人,我们明知道是爱的,也要去放弃,因为没结局;有时候,我们明知道没路了,却还在前行,因为习惯了。

欢迎来我的新浪微博@me
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

#10

帖子 eexpress » 2008-01-07 9:03

看来排骨理解了。排骨真认真啊。
● 鸣学
头像
David50814
帖子: 556
注册时间: 2007-06-11 4:20
来自: 北京
联系:

#11

帖子 David50814 » 2008-01-07 19:04

所谓的高手~~牛
头像
iblicf
帖子: 3766
注册时间: 2007-01-15 17:15

#12

帖子 iblicf » 2008-01-07 19:30

检查core dump文件
今晚吕烁问了一个怎样利用core dump文件调试程序bug的问题。两年前翻译过一章调试的英文资料。很久没有用都忘的差不多了。找到了《An Introduction to GCC - for the GNU compilers gcc and g++》中的一节,用了半个多小时翻译出来,权且做为一个资料以备将来参考。《An Introduction to GCC - for the GNU compilers gcc and g++》是GCC爱好者必看的一本入门级的书。GCC最早的开发者-Richard M. Stallman为这本书做序。

对应的英文引自http://www.network-theory.co.uk/docs/gccintro/gccintro_38.html
5.1 检查core文件(内核转储文件)
除了允许程序在调试器的控制下运行外,-g选项一个非常有用的功能是利用“core dump”检查程序崩溃的原因。
当一个程序异常结束时(比如崩溃),操作系统能够将程序崩溃时内存中的状态信息写入一个core文件(通常这个文件命名为core)。这个文件经常被称为 core dump(内核转储).与-g选项产生的符号表信息结合,这个core dump能用来找到程序在哪一行异常结束了,以及程序运行到这一行时相关变量的值。
这个特性在软件开发当中和软件发布后都是非常有用的,这是因为可以从程序崩溃的现场调查有关问题。
下面的简单程序中包含一个非法访存的bug,我们将用这个程序来产生一个core文件。

int foo (int *p);

int
main (void)
{
int *p = 0; /* null pointer */
return foo (p);
}

int
foo (int *p)
{
int y = *p;
return y;
}
这个程序试图解引用一个空指针p,众所周知,这是一个非法的操作。在大多数系统上,这将产生异常结束。
为了能找到程序崩溃的原因,我们需用-g选项来编译这个程序。
$ gcc -Wall -g null.c
需要注意的是空指针访问仅在运行时出现异常,因此选项-Wall并不产生任何警告。
在x86 GNU/Linux系统上运行这个可执行文件,将会引起操作系统异常终止这个程序:
$ ./a.out
Segmentation fault (core dumped)
只要出现错误信息'core dumped',操作系统就会在当前目录产生一个"core"文件。这个core文件包含程序结束时的内存信息的副本。术语“段错误”有时指程序试图访问已分配给它的内存之外的一个受限内存“段”。
一些操作系统配置为缺省不生成core文件。这样做的理由是基于core文件可能体积很大因而可能会很快占满剩余磁盘空间。在GNU Bash shell中,用命令ulimit -c 可以控制core文件的最大体积。如果用上述命令得到的是0,那么不产生core文件。当前的大小限制用下列的命令可以获知。
$ ulimit -c
0
如果结果是0, 如上所示,那么可以用下面的命令允许生成任意大小的core文件。
ulimit -c unlimited
注意上面的设置仅在当前shell有效。为了在将来的会话中有效,可以将上面的命令加入一个登录文件,比如GNU Bash shell的.bash_profile文件。
core文件可以用下面的命令装入GDB中调试。
gdb EXECUTALBE_FILE CORE_FILE
注意原来的可执行文件和core文件在调试中都是必须的。不能在没有相应的可执行文件的情况下调试一个core文件。在这个例子中,我们用下面的命令装入可执行文件和core文件:
$ gdb a.out core
调试器立即打印诊断信息,并显示程序崩溃的行号(第13行):
$ gdb a.out core
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x080483ed in foo (p=0x0) at null.c:13
13 int y = *p;
(gdb)
最后一行(gdb)是GDB的提示符,它提示后面可以继续输入命令。
为了弄清楚程序崩溃的原因,我们在调试器中用print命令显示指针p的值。
(gdb) print p
$1 = (int *) 0x0
这个信息告诉我们p是一个整形的空指针(0x0),因此我们知道指针解耦访问*p导致了程序崩溃。
我刚才偶然看到这个,你们觉得作者说的对么?
xxmv99
帖子: 166
注册时间: 2007-12-26 11:02

#13

帖子 xxmv99 » 2008-01-16 15:59

什么排骨???

你们到底是谁?

火星来的吗?

这么牛 :!:
h4m3
帖子: 5
注册时间: 2008-01-20 15:50

#14

帖子 h4m3 » 2008-01-20 16:25

dbzhang800 写了:
shellex 写了:ls说俄虾米啊,都不对路
我告诉你。linux上gcc在堆上会分配冗余空间,,貌似按照8还是16 byte的倍数分配。所以可以...
楼主关注的应该不是这个问题。

可以负责任的告诉你,楼主的这个程序不止是在linux下gcc编译后可以执行,而且windows下不论用gcc还是vc编译后也都可以正常运行。
而且在Solaris下不论你用gcc,还是sun的的CC编译器,生成的可执行文件都是可正常执行的。


我想强调的是,用指针或数组的时候,要自己检查自己用的是不是正确,因为这类的错误编译器往往帮不上忙。而且会给你一种太平的假象。
没错,malloc是分配在heap上的,不是stack,这个程序里heap上只有一个唯一的变量,是不存在什么溢出的,或者说实际上有4GB的虚拟内存给你溢出。不过即使有多个变量,现在的GCC(4.0)可以说也是相当狡诈了,会重新安排heap上的变量顺序,基本上heap和bss上的溢出已经起不了改变程序实质的目的了,而stack overflow早已经是昨日黄花了。
回复