LoveUnix » 编程开发 & Rational » 问c问题,麻烦无双
让LU留住您的每

一天 让LU博客留住您的每一天
2005-8-26 11:29 zhangxiangod
我想请问c中几个比较基本的问题!<br /><br />1。数组的存储方式是怎样的,书上一般没有涉及。它是不是一个类似结构的存储,比如 在定义char a[5]时 先分配一个char起始空间在寄存器中,存一个相应基地址在数据段中,然后把5存在堆栈段中,在初始化(赋值)过程中,把5取出作为一个值给其在内存中空间够大的地方分配5个相应的char空间 。是这样吗?<br />2。函数是怎样存储的?是不是也是存成一个地址,地址指向相应一块内存空间起址,内存空间中放函数代码。在静态编译时编译成字节代码,执行时转到相应地址依次执行代码和分配空间!那么函数的参数如何传递?是不是也和函数封装成了一个类似结构的东东!在调用时取出?<br />3.指针指向的是一个地址,地址按常理说是32或16位 即2个或4个字节,在内存中应该是相同的。在c语言中,不同类型的指针大小是不一样的。int * ,char *的大小就不一样,这是怎么回事?<br /><br />不好意思!小弟这方面比较糊涂。。。可能错误很多。请大家帮我想想!谢谢!

2005-8-26 12:51 99大话王
<!--QuoteBegin--><div class='quotetop'>QUOTE</div><div class='quotemain'><!--QuoteEBegin-->3.指针指向的是一个地址,地址按常理说是32或16位 即2个或4个字节,在内存中应该是相同的。在c语言中,不同类型的指针大小是不一样的。int * ,char *的大小就不一样,这是怎么回事?<br /><!--QuoteEnd--></div><!--QuoteEEnd--><br /><br />我来回答你这个问题 <!--emo&:blush:--><img src='style_emoticons/default/blush.gif' border='0' style='vertical-align:middle' alt='blush.gif' /><!--endemo--> <br /><br />指针大小?这个概念不明白<br /><br />int * pint = 0;<br />char * pchar = 0;<br /><br />以上两个指针的地址都是0,是一样的<br />地址是象0x00000000这样表示的<br /><br />你说的大小不一样,可能应该是int和char占用空间(sizeof)不一样<br /><br />++pint;<br />++pchar;<br /><br />这样后它们就不一样了<br />pint等于0x00000004<br />pchar等于0x00000001<br /><br />这是因为int和char占用空间(sizeof)不一样的原因

2005-8-26 13:56 misame
嗯。头两个问题网上很容易搜到的,呵呵

2005-8-29 11:03 zhangxiangod
<br />呵呵,网上类似的问题我是没有搜到,可能是笨吧!不过翻了点资料,对这几个问题有了点新认识,现写在下面:<br />1.数组存储方式是怎样的  我们都知道。计算机cpu有指令指针寄存器IP和变址寄存器SI,用来标示内存中代码段和数据段的偏移地址。而代码段和数据段的基址则放在cpu的段寄存器 CS和DS中,那么,当定义数组的时候,其实就是先通过DS:SI确定了数据应该存放在数据段中的位置,接着在相应地方分配了size*类型大小的空间(这部分c自动完成),而相应的大小参数实际除了确定分配空间外应该没有意义,所以当初始化值确定后,可以不用此大小参数值;在访问的时候,用寄存器相对寻址的方式从DS中取出值给AX或是其他寄存器,此时每次SI=SI+类型大小。<br /><br />2.函数是怎样存储的    同上,函数的代码运行时当然是存在内存中代码段处通过CS:IP确定其具体存放的位置;在运行时指令顺次执行,当执行到函数定义时,即把函数定义作为一个过程放入堆栈段中,确定SP,以便以后执行;当执行到函数调用时,即做两件事,一是把实参放入堆栈SS中,用来传给函数;二是把入口地址指向堆栈段,通过SS:SP访问到堆栈段中的函数实体。(这就解释了为什么函数应当先定义后调用,或如果定义在调用后应当先声明。原因是函数在定义的时候应当放入堆栈中,过程的运行在堆栈段中。如果函数在调用后定义,函数调用会找不到相应的地址,此时应当在调用前声明。声明的作用是通过全局查找把函数调入堆栈中以便函数调用时能进行下去)<br /><br />3.指针是怎么回事     指针其实就是c在数据段DS分配的一个相应大小的空间,只是这个空间存放的都是地址值。(其实地址值和普通值没什么两样都是二进制数),只是在编译的过程中,碰到指针赋值等操作,把其编译成寄存器间接寻址或寄存器相对寻址等操作。通常的int,char赋值在汇编中用的是直接寻址或立即寻址(即直接赋值),,,但在指针中我们用的是地址寻址,即把指针代码地址中所应对应的相应地址中的内容取出来。。这也解释了数组和指针为什么可以通用,因为数组在编译时可以通过直接寻址立即寻址以及寄存器寻址等,而指针只能通过寄存器寻址(当然这是由具体语言规定的)。<br /><br />以上是我对这三个问题的进一步认识,知识所限,可能很多东西有错误或不完善,希望大家指正。。我如果有了更深的认识也会继续!

2005-8-29 12:21 无双
如果学习汇编 那理解起来应该比较容易<br /><br />程序有三个段<br />数据段<br />代码段<br />stack<br />heap<br /><br />函数在代码段中<br />指针的话使用一个int变量保存 在寻址时把它当成一个指针进行寻址<br />

2005-8-29 16:11 zhangxiangod
那我在问下,如果不先于调用定义的话!为什么函数应当先声明后调用呢!声明在其中起到了什么作用!

2005-8-29 18:58 无双
编译时知道要链接的符号类型是什么<br /><br />声明是声明这个名字是一个函数使用

2005-8-30 08:28 zhangxiangod
<!--QuoteBegin-无双+2005-08-29 19:58:46--><div class='quotetop'>QUOTE(无双 @ 2005-08-29 19:58:46)</div><div class='quotemain'><!--QuoteEBegin--><br />编译时知道要链接的符号类型是什么<br /><br />声明是声明这个名字是一个函数使用<br />[right][snapback]487202[/snapback][/right]<br /><!--QuoteEnd--></div><!--QuoteEEnd--><br /><br />我知道了!函数名也是一个标示符,也需要和其他变量一样先定义后执行,如果没有先定义,就必须在前面先声明下,此是函数,编译时在执行到这个过程的时候就不会把此语句当成变量或其他的东西处理,而是函数类型来处理!

2005-8-30 09:31 无双
yes <!--emo&:rose:--><img src='style_emoticons/default/rose.gif' border='0' style='vertical-align:middle' alt='rose.gif' /><!--endemo-->

2005-9-3 18:33 freestream
现在的计算机教材真是误人子弟。<br />在现代的操作系统中,不存在堆栈,堆(heap)和栈(stack)是两个概念.<br />全局变量及动态分配的内存在堆中。动态局部变量在栈中。静态的局部变量在栈中。另外,在多线程系统中,每个线程都有自己的栈。

2005-9-3 23:37 Anakin
垃圾 堆 里捡垃圾,垃圾 堆  是 自己的的<br />客   栈 里住店,  客   栈  是 客栈老板的

2005-9-6 10:26 无双
常量和静态/全局变量是放在程序的数据段 <br /><br />栈和堆都是放运行时动态的变量的<br /><br />数据段里面的是编译时就已经确定大小的内容

2005-9-6 10:46 zhangxiangod
同意!顺便问下友元函数?感觉如果公有函数可以访问私有成员,申明在私有成员中的友元函数的作用在哪!是不是在虚函数那块?

2005-9-6 11:22 zhangxiangod
看了一篇文章懂了点!转载下!<br /><br /><br />在说明什么是友元之前,我们先说明一下为什么需要友元与友元的缺点: <br /><br />  通常对于普通函数来说,要访问类的保护成员是不可能的,如果想这么做那么必须把类的成员都生命成为public(共用的),然而这做带来的问题遍是任何外部函数都可以毫无约束的访问它操作它,c++利用friend修饰符,可以让一些你设定的函数能够对这些保护数据进行操作,避免把类成员全部设置成public,最大限度的保护数据成员的安全。 <br /><br />  友元能够使得普通函数直接访问类的保护数据,避免了类成员函数的频繁调用,可以节约处理器开销,提高程序的效率,但矛盾的是,即使是最大限度的保护,同样也破坏了类的封装特性,这即是友元的缺点,在现在cpu速度越来越快的今天我们并不推荐使用它,但它作为c++一个必要的知识点,一个完整的组成部分,我们还是需要讨论一下的。 <br /><br />  在类里声明一个普通函数,在前面加上friend修饰,那么这个函数就成了该类的友元,可以访问该类的一切成员。 <br /><br />  下面我们来看一段代码,看看我们是如何利用友元来访问类的一切成员的。<br /><br />#include &lt;iostream&gt;    <br />using namespace std;  <br />class Internet    <br />{    <br />public:    <br />    Internet(char *name,char *address)    <br />    {    <br />        strcpy(Internet::name,name);    <br />        strcpy(Internet::address,address);     <br />    }  <br />friend void ShowN(Internet &amp;obj);//友元函数的声明  <br />public:    <br />    char name[20];  <br />    char address[20];  <br />};  <br />  <br />  <br />void ShowN(Internet &amp;obj)//函数定义,不能写成,void Internet::ShowN(Internet &amp;obj)  <br />{  <br />    cout&lt;&lt;obj.name&lt;&lt;endl;  <br />}  <br />void main()    <br />{  <br />    Internet a(&quot;中国软件开发实验室&quot;,&quot;www.cndev-lab.com&quot;);  <br />    ShowN(a);  <br />    cin.get();  <br />} <br />  上面的代码通过友元函数的定义,我们成功的访问到了a对象的保护成员name,友元函数并不能看做是类的成员函数,它只是个被声明为类友元的普通函数,所以在类外部函数的定义部分不能够写成void Internet::ShowN(Internet &amp;obj),这一点要注意。<br /><br /><br /><br />一个普通函数可以是多个类的友元函数,对上面的代码我们进行修改,注意观察变化:<br /><br />#include &lt;iostream&gt;    <br />using namespace std;  <br />class Country;  <br />class Internet    <br />{    <br />public:    <br />    Internet(char *name,char *address)    <br />    {    <br />        strcpy(Internet::name,name);    <br />        strcpy(Internet::address,address);     <br />    }  <br />friend void ShowN(Internet &amp;obj,Country &amp;cn);//注意这里  <br />public:    <br />    char name[20];  <br />    char address[20];  <br />};  <br />  <br />class Country  <br />{  <br />public:  <br />    Country()  <br />    {  <br />        strcpy(cname,&quot;中国&quot;);  <br />    }  <br />friend void ShowN(Internet &amp;obj,Country &amp;cn);//注意这里  <br />protected:  <br />    char cname[30];  <br />};  <br />  <br />void ShowN(Internet &amp;obj,Country &amp;cn)  <br />{  <br />    cout&lt;&lt;cn.cname&lt;&lt;&quot;|&quot;&lt;&lt;obj.name&lt;&lt;endl;  <br />}  <br />void main()    <br />{  <br />    Internet a(&quot;中国软件开发实验室&quot;,&quot;www.cndev-lab.com&quot;);  <br />    Country b;  <br />    ShowN(a,<!--emo&B)--><img src='style_emoticons/default/cool.gif' border='0' style='vertical-align:middle' alt='cool.gif' /><!--endemo-->;  <br />    cin.get();  <br />}<br />  一个类的成员函数函数也可以是另一个类的友元,从而可以使得一个类的成员函数可以操作另一个类的数据成员,我们在下面的代码中增加一类Country,注意观察:<br /><br />#include &lt;iostream&gt;    <br />using namespace std;  <br />class Internet;  <br />  <br />class Country  <br />{  <br />public:  <br />    Country()  <br />    {  <br />        strcpy(cname,&quot;中国&quot;);  <br />    }  <br />    void Editurl(Internet &amp;temp);//成员函数的声明  <br />protected:  <br />    char cname[30];  <br />};  <br />class Internet  <br />{    <br />public:    <br />    Internet(char *name,char *address)    <br />    {    <br />        strcpy(Internet::name,name);    <br />        strcpy(Internet::address,address);   <br />    }  <br />    friend void Country::Editurl(Internet &amp;temp);//友元函数的声明  <br />protected:    <br />    char name[20];  <br />    char address[20];  <br />};  <br />void Country::Editurl(Internet &amp;temp)//成员函数的外部定义  <br />{  <br />    strcpy(temp.address,&quot;edu.cndev-lab.com&quot;);  <br />    cout&lt;&lt;temp.name&lt;&lt;&quot;|&quot;&lt;&lt;temp.address&lt;&lt;endl;  <br />}  <br />void main()  <br />{  <br />    Internet a(&quot;中国软件开发实验室&quot;,&quot;www.cndev-lab.com&quot;);  <br />    Country b;  <br />    b.Editurl(a);  <br />    cin.get();  <br />}<br />  整个类也可以是另一个类的友元,该友元也可以称做为友类。友类的每个成员函数都可以访问另一个类的所有成员。 <br /><br />示例代码如下:<br /><br />#include &lt;iostream&gt;    <br />using namespace std;  <br />class Internet;  <br />  <br />class Country  <br />{  <br />public:  <br />    Country()  <br />    {  <br />        strcpy(cname,&quot;中国&quot;);  <br />    }  <br />    friend class Internet;//友类的声明  <br />protected:  <br />    char cname[30];  <br />};  <br />class Internet  <br />{  <br />public:    <br />    Internet(char *name,char *address)    <br />    {    <br />        strcpy(Internet::name,name);    <br />        strcpy(Internet::address,address);   <br />    }  <br />    void Editcname(Country &amp;temp);  <br />protected:    <br />    char name[20];  <br />    char address[20];  <br />};  <br />void Internet::Editcname(Country &amp;temp)  <br />{  <br />    strcpy(temp.cname,&quot;中华人民共和国&quot;);   <br />}  <br />void main()  <br />{  <br />    Internet a(&quot;中国软件开发实验室&quot;,&quot;www.cndev-lab.com&quot;);  <br />    Country b;  <br />    a.Editcname(<!--emo&B)--><img src='style_emoticons/default/cool.gif' border='0' style='vertical-align:middle' alt='cool.gif' /><!--endemo-->;  <br />    cin.get();  <br />}<br />  在上面的代码中我们成功的通过Internet类Editcname成员函数操作了Country类的保护成员cname。 <br /><br />  在编程中,我们使用友元的另外一个重要原因是为了方便重载操作符的使用,这些内容我们将在后面的教程着重讨论!<br /><br /><br />这儿真好!能激励俺多读点书!

2006-2-22 00:09 永杰
推荐thinking in c++

页: [1]
查看完整版本: 问c问题,麻烦无双


Powered by Discuz! Archiver 5.5.0  © 2001-2006 Comsenz Inc.