文档流是文档中可显示对象在排列时所占用的位置。比如网页的div标签它默认占用的宽度位置是一整行,p标签默认占用宽度也是一整行,因为div标签和p标签是块状对象。
网页中大部分对象默认是占用文档流,也有一些对象是不占文档流的,比如表单中隐藏域。当然我们也可以让占用文档流的元素转换成不占文档流,这就要用到CSS中属性position来控制。
看看CSS 2.0对position的定义:检索对象的定位方式。共有4种取值。
static:默认值,无特殊(静态)定位。对象遵循HTML定位规则 。
absolute:绝对定位。将对象从文档流中拖出,使用left,right,top,bottom等属性相对于其最接近的一个最有定位设置的父对象进行绝对定位。如果不存在这样的父对象,则依据body对象。而其层叠通过z-index属性定义 。当对象定位在浏览器窗口以外,浏览器因此显示滚动条。
fixed:固定定位。对象定位遵从绝对(absolute)方式。但是要遵守一些规范。当对象定位在浏览器窗口以外,浏览器不会因此显示滚动条,而当滚动条滚动时,对象始终固定在原来位置。
relative:相对定位。对象不可层叠,但将依据left,right,top,bottom等属性在正常文档流中偏移位置。当对象定位在浏览器窗口以外,浏览器因此显示滚动条。
inherit:继承值,对象将继承其父对象相应的值
posted @
2009-10-13 16:56 华梦行 阅读(897) |
评论 (0) |
编辑 收藏
发现一个不错的养生网站 养生之道 www.yszd.org ,希望大家喜欢。
posted @
2009-09-25 22:25 华梦行 阅读(263) |
评论 (0) |
编辑 收藏
hessian
posted @
2009-08-24 09:26 华梦行 阅读(226) |
评论 (0) |
编辑 收藏
http://xstream.codehaus.org/json-tutorial.html
posted @
2009-08-12 08:55 华梦行 阅读(266) |
评论 (0) |
编辑 收藏
/*
CSS Reset for Taobao
注意:这里是 ONLY for Taobao 的 reset rules
维护:玉伯(lifesinger@gmail.com), 正淳(ragecarrier@gmail.com)
*/
/* require(reset.css) */
html {
color: #404040; /* 淘宝文字默认色 */
background: #fff; /* 覆盖掉用户在不知情的情况下,设置的页面背景 */
}
/* 淘宝链接默认色 */
a { color: #404040; }
a:hover { color: #f60; }
/* 重置 hr */
hr {
color: #ccc;
background-color: #ccc;
}
/* misc */
html {
/* 让非ie浏览器默认也显示垂直滚动条,防止因滚动条引起的闪烁 */
overflow-y: scroll;
}
posted @
2009-07-29 18:09 华梦行 阅读(504) |
评论 (0) |
编辑 收藏
javascript的继承机制并不是明确规定的,而是通过模仿实现的,意味着继承不是由解释程序处理,开发者有权决定最适合的继承方式. 下面我给出几种常用的方法:
1 .对象冒充
原理: 构造函数使用this关键字给所有属性和方法赋值, 因为构造函数只是一个函数,所以可以使ClassA的构造函数成为classB的方法,然后调用它.这样classB就会收到classA的构造函数中定义的属性和方法.例子:
function classA(name)
{
this.name=name;
this.showName=function(){alert(this.name);}
}
function classB(name)
{
this.newMethod = classA;
this.newMethod(name);
}
obj = new classA("hero");
objB = new classB("dby");
obj.showName(); // print hero
objB.showName(); // print dby 说明classB 继承了classA的方法.
对象冒充可以实现多重继承 例如
function classz(){
this.newMethod = classX;
this.newMethod();
delete this.newMethod;
this.newMethod=classY;
this.newMethod():
delete this.newMethod;
}
但是如果classX和classY有相同的属性或者方法,classY具有高优先级.
2.call()方法
call方法使与经典的对象冒充法就相近的方法,它的第一个参数用作this的对象,其他参数都直接传递给函数自身.
function sayName(perfix)
{
alert(perfix+this.name);
}
obj= new Object();
obj.name="hero";
sayName.call(obj,"hello," );
function classA(name)
{
this.name=name;
this.showName=function(){alert(this.name);};
}
function classB(name)
{
classA.call(this,name);
}
objB = new classB("bing");
objB.showName();////说明classB继承classA的showName方法
3.apply()方法
aplly()方法有2个参数,一个用作this对象,一个使传递给函数的参数数组.
function sayName(perfix)
{
alert(perfix+this.name);
}
obj= new Object();
obj.name="hero";
sayName.aplly(obj,new Array("hello,") );
4. 原型链
prototype对象的任何属性和方法都会被传递给对应类的所有实例,原型链就是用这种方式来显现继承.
function classA (){}
classA.prototype.name="hero";
classA.prototype.showName=function(){alert(this.name)}
function classB(){}
classB.prototype=new classA();
objb = new classB()
objb.showName();//print hero 说明b继承了a的方法
这里需要注意 调用classA的构造函数时,没有给它传递参数,这是原型链的标准做法,确保函数的构造函数没有任何参数.
并且 子类的所有属性和方法,必须出现在prototype属性被赋值后,应为在它之前赋的值会被删除.因为对象的prototype属性被替换成了新对象,添加了新方法的原始对象将被销毁.
5 混和方式
就是用冒充方式 定义构造函数属性,用原型法定义对象方法.
function classA(name)
{
this.name=name;
}
classA.prototype.showName=function(){alert(this.name)}
function classB(name)
{
classA.call(this,name);
}
classB.prototype = new classA();
classB.prototype.showName1=function(){alert(this.name+"*****");};
obj = new classB("hero");
obj.showName();
obj.showName1();
在classB的构造函数中通过调用call方法 继承classA中的name属性,用原型链来继承classA的showName方法.
posted @
2009-07-16 13:47 华梦行 阅读(114) |
评论 (0) |
编辑 收藏
1)Sun的JVM在实现Selector上,在Linux和Windows平台下的细节。
2)Selector类的wakeup()方法如何唤醒阻塞在select()系统调用上的细节。
先给大家做一个简单的回顾,在Windows下,Sun的Java虚拟机在Selector.open()时会自己和自己建立loopback的TCP链接;在Linux下,Selector会创建pipe。这主要是为了Selector.wakeup()可以方便唤醒阻塞在select()系统调用上的线程(通过向自己所建立的TCP链接和管道上随便写点什么就可以唤醒阻塞线程)
我们知道,无论是建立TCP链接还是建立管道都会消耗系统资源,而在Windows上,某些Windows上的防火墙设置还可能会导致Java的Selector因为建立不起loopback的TCP链接而出现异常。
而在我的另一篇文章《用GDB调试Java程序》中介绍了另一个Java的解释器——GNU的gij,以及编译器gcj,不但可以比较高效地运行Java程序,而且还可以把Java程序直接编译成可执行文件。
GNU的之所以要重做一个Java的编译和解释器,其一个重要原因就是想解释Sun的JVM的效率和资源耗费问题。当然,GNU的Java编译/解释器并不需要考虑太多复杂的平台,他们只需要专注于Linux和衍生自Unix System V的操作系统,对于开发人员来说,离开了Windows,一切都会变得简单起来。在这里,让我们看看GNU的gij是如何解释Selector.open()和Selector.wakeup()的。
同样,我们需要一个测试程序。在这里,为了清晰,我不会例出所有的代码,我只给出我所使用的这个程序的一些关键代码。
我的这个测试程序中,和所有的Socket程序一样,下面是一个比较标准的框架,当然,这个框架应该是在一个线程中,也就是一个需要继承Runnable接口,并实现run()方法的一个类。(注意:其中的s是一个成员变量,是Selector类型,以便主线程序使用)
//生成一个侦听端
ServerSocketChannel ssc = ServerSocketChannel.open();
//将侦听端设为异步方式
ssc.configureBlocking(false);
//生成一个信号监视器
s = Selector.open();
//侦听端绑定到一个端口
ssc.socket().bind(new InetSocketAddress(port));
//设置侦听端所选的异步信号OP_ACCEPT
ssc.register(s,SelectionKey.OP_ACCEPT);
System.out.println("echo server has been set up ......");
while(true){
int n = s.select();
if (n == 0) { //没有指定的I/O事件发生
continue;
}
Iterator it = s.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
if (key.isAcceptable()) { //侦听端信号触发
…… …… ……
…… …… ……
}
if (key.isReadable()) { //某socket可读信号
…… …… ……
…… …… ……
}
it.remove();
}
}
而在主线程中,我们可以通过Selector.wakeup()来唤醒这个阻塞在select()上的线程,下面是写在主线程中的唤醒程序:
new Thread(this).start();
try{
//Sleep 30 seconds
Thread.sleep(30000);
System.out.println("wakeup the select");
s.wakeup();
}catch(Exception e){
e.printStackTrace();
}
这个程序在主线程中,先启动一个线程,也就是上面那个Socket线程,然后休息30秒,为的是让上面的那个线程有阻塞在select(),然后打印出一条信息,这是为了我们用strace命令查看具体的系统调用时能够快速定位。之后调用的是Selector的wakeup()方法来唤醒侦听线程。
接下来,我们可以通过两种方式来编译这个程序:
1)使用gcj或是sun的javac编译成class文件,然后使用gij解释执行。
2)使用gcj直接编译成可执行文件。
(无论你用那种方法,都是一样的结果,本文使用第二种方法,关于gcj的编译方法,请参看我的《用GDB调试Java程序》)
编译成可执行文件后,执行程序时,使用lsof命令,我们可以看到没有任何pipe的建立。可见GNU的解释更为的节省资源。而对于一个Unix的C程序员来说,这意味着如果要唤醒select()只能使用pthread_kill()来发送一个信号了。下面就让我们使用strace命令来验证这个想法。
下图是使用strace命令来跟踪整个程序运行时的系统调用,我们利用我们的输出的“wakeup the select”字符串快速的找到了wakeup的实际系统调用。
posted @
2009-06-16 14:50 华梦行 阅读(561) |
评论 (0) |
编辑 收藏
很早就听说tomcat6使用nio了,这几天突然想到一个问题,使用nio代替传统的bio,ThreadLocal岂不是会存在冲突?
如果读者有socket的编程基础,应该会接触过堵塞socket和非堵塞socket,堵塞socket就是在accept、read、write等IO操作的的时候,如果没有可用符合条件的资源,不马上返回,一直等待直到有资源为止。而非堵塞socket则是在执行select的时候,当没有资源的时候堵塞,当有符合资源的时候,返回一个信号,然后程序就可以执行accept、read、write等操作,这个时候,这些操作是马上完成,并且马上返回。而windows的winsock则有所不同,可以绑定到一个EventHandle里,也可以绑定到一个HWND里,当有资源到达时,发出事件,这时执行的io操作也是马上完成、马上返回的。一般来说,如果使用堵塞socket,通常我们时开一个线程accept socket,当有socket链接的时候,开一个单独的线程处理这个socket;如果使用非堵塞socket,通常是只有一个线程,一开始是select状态,当有信号的时候马上处理,然后继续select状态。
按照大多数人的说法,堵塞socket比非堵塞socket的性能要好。不过也有小部分人并不是这样认为的,例如Indy项目(Delphi一个比较出色的网络包),它就是使用多线程+堵塞socket模式的。另外,堵塞socket比非堵塞socket容易理解,符合一般人的思维,编程相对比较容易。
nio其实也是类似上面的情况。在JDK1.4,sun公司大范围提升Java的性能,其中NIO就是其中一项。Java的IO操作集中在java.io这个包中,是基于流的阻塞API(即BIO,Block IO)。对于大多数应用来说,这样的API使用很方便,然而,一些对性能要求较高的应用,尤其是服务端应用,往往需要一个更为有效的方式来处理IO。从JDK 1.4起,NIO API作为一个基于缓冲区,并能提供非阻塞O操作的API(即NIO,non-blocking IO)被引入。 BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。
这个时候,问题就出来了:我们非常多的java应用是使用ThreadLocal的,例如JSF的FaceContext、Hibernate的session管理、Struts2的Context的管理等等,几乎所有框架都或多或少地应用ThreadLocal。如果存在冲突,那岂不惊天动地?
后来终于在Tomcat6的文档(http://tomcat.apache.org/tomcat-6.0-doc/aio.html)找到答案。根据上面说明,应该Tomcat6应用nio只是用在处理发送、接收信息的时候用到,也就是说,tomcat6还是传统的多线程Servlet,我画了下面两个图来列出区别:
tomcat5:客户端连接到达 -> 传统的SeverSocket.accept接收连接 -> 从线程池取出一个线程 -> 在该线程读取文本并且解析HTTP协议 -> 在该线程生成ServletRequest、ServletResponse,取出请求的Servlet -> 在该线程执行这个Servlet -> 在该线程把ServletResponse的内容发送到客户端连接 -> 关闭连接。
我以前理解的使用nio后的tomcat6:客户端连接到达 -> nio接收连接 -> nio使用轮询方式读取文本并且解析HTTP协议(单线程) -> 生成ServletRequest、ServletResponse,取出请求的Servlet -> 直接在本线程执行这个Servlet -> 把ServletResponse的内容发送到客户端连接 -> 关闭连接。
实际的tomcat6:客户端连接到达 -> nio接收连接 -> nio使用轮询方式读取文本并且解析HTTP协议(单线程) -> 生成ServletRequest、ServletResponse,取出请求的Servlet -> 从线程池取出线程,并在该线程执行这个Servlet -> 把ServletResponse的内容发送到客户端连接 -> 关闭连接。
从上图可以看出,BIO与NIO的不同,也导致进入客户端处理线程的时刻有所不同:tomcat5在接受连接后马上进入客户端线程,在客户端线程里解析HTTP协议,而tomcat6则是解析完HTTP协议后才进入多线程,另外,tomcat6也比5早脱离客户端线程的环境。
实际的tomcat6与我之前猜想的差别主要集中在如何处理servlet的问题上。实际上即使抛开ThreadLocal的问题,我之前理解tomcat6只使用一个线程处理的想法其实是行不同的。大家都有经验:servlet是基于BIO的,执行期间会存在堵塞的,例如读取文件、数据库操作等等。tomcat6使用了nio,但不可能要求servlet里面要使用nio,而一旦存在堵塞,效率自然会锐降。
所以,最终的结论当然是tomcat6的servlet里面,ThreadLocal照样可以使用,不存在冲突
posted @
2009-06-16 14:30 华梦行 阅读(203) |
评论 (0) |
编辑 收藏
我就拿一个房子来做一个比方吧,服务器好比就是一幢房子,黑客最直接的方式就是带着一些撬锁的工具,去把房子的锁给撬掉,然后夺门而入,这种方式被称为服务器入侵。还有一类就是它直接撬大门锁撬不开,它就把这个房子的窗打破,从窗子里面钻进去,来进行破坏,这种方式叫做网站入侵。还有一类就是黑客带着一只训练有素的小猴子,让小猴子爬到房子的房顶,从烟囱里面钻进去,然后把大门打开,这种方式叫做特洛伊木马入侵。还有一类就是我们前面讲到那个事件的DDOS攻击这个技术,这个相当于黑客带着一大帮人过来把房子的大门给堵住了,让房子里面的人出不来,让外面的人也进不去,这就是DDOS攻击。
posted @
2009-06-10 10:40 华梦行 阅读(138) |
评论 (0) |
编辑 收藏
SELECT DATEADD(mm,DATEDIFF(mm,0,getdate()),0)
//首先选出当前月,然后把他转换为日期
select (2009-1900)*12
select DATEDIFF(mm,0,getdate())
posted @
2009-06-08 14:39 华梦行 阅读(177) |
评论 (0) |
编辑 收藏
#define WINVER 0x0050
#define WINVER 0x0500,这个表示是为Windows 2000编译,不保证Windows 98/NT4可以正常运行
Windows Server 2003
WINVER>=0x0502
Windows XP
WINVER>=0x0501
Windows 2000
WINVER>=0x0500
Windows NT 4.0
WINVER>=0x0400
Windows Me
WINVER>=0x0500
Windows 98
WINVER>=0x0410
Windows 95
WINVER>=0x0400
posted @
2009-03-26 22:15 华梦行 阅读(167) |
评论 (0) |
编辑 收藏
// TODO: Add your message handler code here and/or call default
/*HDC hdc;
hdc=::GetDC(m_hWnd);
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);*/
/*CDC *pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);*/
//CClientDC dc(this);
/*CClientDC dc(GetParent());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);*/
//CWindowDC dc(this);
//CWindowDC dc(GetParent());
/*CWindowDC dc(GetDesktopWindow());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);*/
/*CPen pen(PS_DOT,1,RGB(0,255,0));
CClientDC dc(this);
CPen *pOldPen=dc.SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(pOldPen);*/
// CBrush brush(RGB(255,0,0));
/*CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
CBrush brush(&bitmap);*/
/*CClientDC dc(this);
//dc.FillRect(CRect(m_ptOrigin,point),&brush);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush *pOldBrush=dc.SelectObject(pBrush);
dc.Rectangle(CRect(m_ptOrigin,point));
dc.SelectObject(pOldBrush);*/
m_bDraw=FALSE;
CView::OnLButtonUp(nFlags, point);
posted @
2009-03-24 16:25 华梦行 阅读(155) |
评论 (0) |
编辑 收藏
#include <iostream.h>
#include <string>
char* strToBinary(int x);
char* strToHex(int i);
char* transToGKB(char *t);
int main ()
{
char *p=strToBinary(233);
//cout<<p;
//cout<<strToHex(233);
cout<<transToGKB("商");
return 0;
}
char* transToGKB(char *t){
int res=0;
int intlen;
intlen=strlen(t);
if(intlen>1){
char *result=new char[5];
int i=0;
if(0>t[0]){
res=256+t[0];
}
char *p1=strToHex(res);
if(0>t[1]){
res=256+t[1];
}
char *p2=strToHex(res);
result=p1;
result[2]=p2[0];
result[3]=p2[1];
result[4]='\0';
return result;
}
else{
//if(t[0]>64)
char * p=new char[3];
p=strToHex(t[0]);
p[2]='\0';
return p;
}
}
//数字转为二进制(255以内的正数)
char* strToBinary(int i){
char *result=new char[9];
int n=1;
int m;
int c=0;
int j=8;
for(c=0;c<8;c++){
m=i%2;
j=j-1;
i=n=i/2;
if(n>=0){
if (m>0){
result[j]='1';
}else
{
result[j]='0';
}
}
}
result[8]='\0';
// cout<<result;
return result;
}
//数字转为十六进制(255以内的正数)
char* strToHex(int i){
char *result=new char[3];
int n=1;
int m;
int c=0;
int j=2;
for(c=0;c<2;c++){
m=i%16;
j=j-1;
i=n=i/16;
if(n>=0){
if (m>0){
if (m==1){
result[j]='1';
}
else if (m==2){
result[j]='2';
}
else if (m==3){
result[j]='3';
}
else if (m==4){
result[j]='4';
}
else if (m==5){
result[j]='5';
}
else if (m==6){
result[j]='6';
}
else if (m==7){
result[j]='7';
}
else if (m==8){
result[j]='8';
}
else if (m==9){
result[j]='9';
}
else if (m==10){
result[j]='A';
}
else if (m==11){
result[j]='B';
}
else if (m==12){
result[j]='C';
}
else if (m==13){
result[j]='D';
}
else if (m==14){
result[j]='E';
}
else if (m==15){
result[j]='F';
}
}else
{
result[j]='0';
}
}
}
result[2]='\0';
return result;
}
posted @
2009-03-19 16:37 华梦行 阅读(171) |
评论 (0) |
编辑 收藏
#include <iostream.h>
#include <string>
void yihuo(char *t,int n, int m);
void myToBinary();
void transToGKB(char *t);
void myToHex();
int main(){
//cout<<"GOOD";
int i=122;
int j=233;
int m=j^i;
char t[128]={0xC9,0xCC,0xC9,0xCC,0xC9,0xCC,'\0',0xC9,0xCC,0xC9,0xCC};
yihuo(t,0, 2);
// transToGKB(t);
//cout<<m;
//yihuo(2, 3);
//myToHex();
// myToBinary();
cout<<endl;
return 0;
}
//进制之间的转换
// 字符串传为16进制
void myToHex(){
char c[] = "CC";
unsigned long tt= strtoul(c, NULL, 16);
cout<<strtol(c, NULL, 16);
}
// 字符串传为16进制
void myToBinary(){
char c[] = "10000000";
// unsigned long tt= strtoul(c, NULL, 2);
cout<<strtol(c, NULL, 2);
}
//汉字的转换, 16进制转换为汉字
void transToGKB(char *t){
// char *t="商户";
// CharN
//如果是负数,则转为正整数
// if(0>t[0]){
// res=256+t[0];
// }
int j=t[0];
cout<<t<<endl;
}
void yihuo(char *t,int n, int m) {
char *tt="商户说的算";
//转成数字并且保存到数组,然后求异或
//求的长度
const int mylen=strlen(tt)+1;
char mysplit[1000];
//循环对这个整形数组进行赋值
int i=0;
for(i<0;i<mylen-1;i++){
if (tt[i]<0){
mysplit[i]=256+tt[i];
}else
{
mysplit[i]=tt[i];
}
}
int result=mysplit[n-1];
int j;
for(j=n;j<n+m;j++){
result=result^mysplit[n];
cout<<"L"<<endl;
cout<<mysplit[n];
cout<<"M"<<endl;
}
//进行遍历求异或
mysplit[mylen-1]='\0';
cout<<mysplit;
cout<<"ee";
if(result<0)
result=256+result;
cout<<result;
//int j=t[0];
// cout<<t<<endl;
}
posted @
2009-03-17 17:47 华梦行 阅读(444) |
评论 (0) |
编辑 收藏
Integer.parseInt(String.valueOf(o));
posted @
2009-03-14 15:21 华梦行 阅读(268) |
评论 (0) |
编辑 收藏
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
Text1.Text = PropBag.ReadProperty("RecordSource", _
m_def_recordSource)
Text2.Text = PropBag.ReadProperty _
("ConnectionString", m_def_connectionString)
End Sub
posted @
2009-03-11 22:27 华梦行 阅读(120) |
评论 (0) |
编辑 收藏
int main(void)
{
int m=4;
int nn;
int *n;
int *s;
int *p;
int *q;
n=&m;
nn=n;
q=n;
s=nn;
printf("%08x",*s);
return 0;
}
posted @
2009-03-10 21:45 华梦行 阅读(126) |
评论 (0) |
编辑 收藏
0xFFFFFF20 数据输入缓冲区
0xFFFFFF24 输出数据缓冲区
0xFFFFFF28 控制寄存器
posted @
2009-03-10 16:51 华梦行 阅读(223) |
评论 (0) |
编辑 收藏
1.程序段:程序段为程序代码在内存中的映射.一个程序可以在内存中多有个副本.
2.初始化过的数据:在程序运行值初已经对变量进行初始化的
3.未初始化过的数据:在程序运行初未对变量进行初始化的数据
4.堆(stack):存储局部,临时变量,在程序块开始时自动分配内存,结束时自动释放内存.存储函数的返回指针.
5.栈(heap):存储动态内存分配,需要程序员手工分配,手工释放.
#
include
<stdio.h>
int g1=0, g2=0, g3=0;
intmax(int i)
{
int m1=0,m2,m3=0,*p_max;
static n1_max=0,n2_max,n3_max=0;
p_max =(int*)malloc(10);
printf("打印max程序地址\n");
printf("in max: 0x%08x\n\n",max);
printf("打印max传入参数地址\n");
printf("in max: 0x%08x\n\n",&i);
printf("打印max函数中静态变量地址\n");
printf("0x%08x\n",&n1_max);//打印各本地变量的内存地址
printf("0x%08x\n",&n2_max);
printf("0x%08x\n\n",&n3_max);
printf("打印max函数中局部变量地址\n");
printf("0x%08x\n",&m1);//打印各本地变量的内存地址
printf("0x%08x\n",&m2);
printf("0x%08x\n\n",&m3);
printf("打印max函数中malloc分配地址\n");
printf("0x%08x\n\n",p_max);//打印各本地变量的内存地址
if(i)return 1;
elsereturn 0;
}
int main(int argc,char**argv)
{
staticint s1=0, s2, s3=0;
int v1=0, v2, v3=0;
int*p;
p =(int*)malloc(10);
printf("打印各全局变量(已初始化)的内存地址\n");
printf("0x%08x\n",&g1);//打印各全局变量的内存地址
printf("0x%08x\n",&g2);
printf("0x%08x\n\n",&g3);
printf("======================\n");
printf("打印程序初始程序main地址\n");
printf("main: 0x%08x\n\n", main);
printf("打印主参地址\n");
printf("argv: 0x%08x\n\n",argv);
printf("打印各静态变量的内存地址\n");
printf("0x%08x\n",&s1);//打印各静态变量的内存地址
printf("0x%08x\n",&s2);
printf("0x%08x\n\n",&s3);
printf("打印各局部变量的内存地址\n");
printf("0x%08x\n",&v1);//打印各本地变量的内存地址
printf("0x%08x\n",&v2);
printf("0x%08x\n\n",&v3);
printf("打印malloc分配的堆地址\n");
printf("malloc: 0x%08x\n\n",p);
printf("======================\n");
max(v1);
printf("======================\n");
printf("打印子函数起始地址\n");
printf("max: 0x%08x\n\n",max);
return 0;
}
这个程序可以大致查看整个程序在内存中的分配情况:
可以看出,传入的参数,局部变量,都是在栈顶分布,随着子函数的增多而向下增长.
函数的调用地址(函数运行代码),全局变量,静态变量都是在分配内存的低部存在,而malloc分配的堆则存在于这些内存之上,并向上生长
posted @
2009-03-10 15:40 华梦行 阅读(213) |
评论 (0) |
编辑 收藏
#include <stdio.h>
#include <string.h>
hello(){
char *hello="dddd大点的";
int i;
for(i=0;i<strlen(hello);i++){
printf("%s\n",&hello[i]);
}
}
void testStr(){
int i=0;
for(i=0;i<128;i++)
{
printf("%c",(char)i);
}
}
void testmy(){
char *hello="??大点的";
char hellodd[]={hello};
unsigned char test= hellodd[2];
if(test>137){
printf("大于%u",test);
}else
{
printf("小于");
}
//putchar((char)hello[5]);
printf("字符:%d \n",hellodd[2]);
printf("%d",strlen( hellodd));
}
//相当于substring
teststrcopy(){
char *s="到的得到";
char d[]={" "};
//strncpy(d,s+0,2);
strncpy(d,s,2);
printf("%s\n",d);
}
int main(void){
//testmy();
//teststrcopy();
return 0;
}
posted @
2009-03-10 15:23 华梦行 阅读(81) |
评论 (0) |
编辑 收藏