Archive for ‘C and CPP’ Category

2012/11/23

有一段非常非常非常简单的网络编程代码,C语言,C/S模式,相信每一个学习C语言网络编程的人都写过,正因为特别简单,所以发生错误时第一反应并不是我的代码错了,而是系统的BUG! 事实证明,这种想法真是 too young, too simple, sometime naive ! 无论是系统调用还是库函数代码,全世界那么多人在用,经过这么多年的千锤百炼,发生错误的可能性是很小的,大多时候都是自己的粗心大意。本次乌龙事件最后查明的原因是传给recvfrom函数的最后一个参数 addrlen没有被初始化。 事情是这样的,一个非常简单的客户/服务器程序。 第一次运行 ./server 和 ./client 127.0.0.1 , 当client发送数据的时候,server收到了,但是显示client的IP地址是错误的,因为是错误的IP地址,所以server把回送的数据报发给了错误的地址,client当然就收不到了。

42,616 views
2011/10/01

时间倒回到2011年5月的一天,大学的最后一门课《计算机信息安全技术》,讲到《缓冲区溢出》这一章,并且给出了一段示例代码来演示缓冲区溢出,回到宿舍后出于好奇我运行了一下这段代码,发现结果并不是书上所说的那样,当时在人人网也发过一篇吐槽的日志,但是一直拖到现在都没有仔细的去研究过,正好现在十一放假没事,就花点时间搞搞啦。 书第136页-137页。代码如下,出于简单考虑(其实书上的C++代码格式也是错的),我除去了头文件和cout函数,这样就跟纯C语言代码是一样了。 01 void function(int a) 02 { 03     char buffer[5]; 04     char *ret; 05     ret=buffer+12; 06     *ret+=8; 07 } 08 int main() 09 { 10     int x; 11     x=10; 12     function(7); 13     x=1; 14     return 0; 15 } 书上说最后x的值是10,不是1,而我的结果恰恰相反。 接着用gcc产生汇编代码,在这里用 gcc -O0 -S 命令告诉编译器不采用任何优化措施,产生最原始的汇编代码,这样有利于我们分析,即使是采用-O1级优化的时候,汇编代码已经很难读了,大家可以试一试。 01 function: 02     pushl %ebp 03    […]

Tags: ,. 9,880 views
2011/02/14

函数指针,顾名思义就是指向函数的指针,它与一般的指针有什么不同呢?我觉得,函数指针只是在定义的时候有一点不同,使用的时候,它就是一个指针该怎么用就怎么用。 int (*f)(int,double); 类似于上面的定义式就是函数指针的定义了。 从前往后分析,最前面的int 说明了这个所指向的函数的返回值,显然,这个被指向的函数会返回一个整型的值;(*f)()结构说明了这是一个函数指针,(int,double)说明了这个指针指向的函数的参数形式,即第一个参数是int型,第二个参数是double型,这时,我们脑海里可以想象有一个这样的函数 int function(int a,double b),并且有一个叫 f 的指针指向了这个函数(其实是指向了这个函数段的起始地址)。 有了前面的分析,就不难理解这个定义了 char * (*f)(double,double); 下面再来一个难一点的,int (*g[])(int ,int);首先这肯定是一个指针,但是[]怎么理解呢?按照数组的理解方法,例如int array[9]定义了一个9个元素的数组,每个元素都是int型,以此类推,这是一个函数指针数组,每一个数组元素的类型都是一个函数指针,他们都各自指向一个类似于 int func(int,int)的函数。 如何使用函数指针呢?我们知道,函数名其实就是指向函数代码段的一个指针,因此,f和function都可以看成是一个指针,都指向了内存中同一块代码段,所以,调用f(3,4.5)与function(3,4.5)是一样的,相当于是给原来的函数一个别名吧。当然,f是一个指针,理所当然可以对他进行“间接访问”,即 (*f)(3,4.5)。 一般情况下对于函数指针的常见情况也就是以上这些了,那么函数指针到底有什么用呢? >说实话,我自己写代码到目前为止还没用过函数指针,一方面是我对这个不熟悉,在coding的过程中不能灵活运用;另一方面函数指针可能确实不如其他语法常用,因此,我举一个《C和指针》中类似的例子。 例子一:不用函数指针的实现。 swith(op){ case ‘+’:add(x,y);break; case ‘-‘:sub(x,y);break; case ‘*’:mul(x,y);break; case ‘/’:div(x,y);break; } 上面的代码实现了模拟一个计算器对于x,y做加减乘除,那么用函数指针如何实现呢? 例子二:用函数指针实现。 首先我们需要声明函数,并对函数指针数组初始化。 double add(double,double); double sub(double,double); double mul(double,double); double div(double,double); /*声明函数指针数组*/   double (*op_fun[4])(double,double)={add,sub,mul,div}; 现在我们可以这样使用: result=op_fun[op](x,y); OK,以上就是鄙人学习函数指针的一点点心得。

Tags: ,,. 6,377 views
2010/04/18

更新是需要的。否则对不起来踩博客的童鞋们~~ 只是我最近比较忙阿,觉得没什么好更新的,也许要等到明年我闲下来了,才会有精力来好好打理博客,想念各位~ 先就把这个《C语言简单词法分析器》放上来吧,很早之前我就在CFAN论坛发过,如有雷同,纯属有意。 代码就不贴,直接上文件。猛击此处 顺便透露一下,下一篇博客估计是《简单四则运算器》,嘿嘿,还是一堆代码,不解释,你懂的~~(最近很流行这句话)

Tags: ,. 7,753 views
2009/08/22

D大同学   曰:数组作为参数会退化为指针,这个规则应该牢记。。。

KC  曰:当数组首地址被作为指针传…

Tags: ,,. 6,314 views
2009/08/14
Tags: ,,. 1,946 views

一段时间没用数组指针,居然忘记了这个语法了,调试了半天都不行,真郁闷… 我贴出一段代码来描述我的意思。 QUOTE: 有问题的代码 #include<iostream> using namespace std; void print(int *p) {     int i,j;     for(i=0;i<20;i++)//一种打印方式     {         for(j=0;j<3;j++)         cout<<p[i][j]<<",";     }     cout<<endl;     for(i=0;i<20;i++)//另一种打印方式     {         for(j=0;j<3;j++)         cout<<*(*(p+i)+j)<<",";     } } int main() {     int array[20][3];     for(int i=0;i<20;i++)//赋值     {         for(int j=0;j<3;j++)         array[i][j]=i+j+2;     }     print(array);//打印     return 0; } //如果把array改成char型呢?相应的函数定义怎么改? 如果把array改成char型呢?相应的函数定义怎么改? [ 本帖最后由 52computer 于 2009-3-10 14:13 编辑 ] ———————————————————————                         热心人的解答 ——————————————————————— #include using namespace std; void print(int p[][3]) {         int i,j;         for(i=0;i<20;i++)//一种打印方式         {                 for(j=0;j<3;j++)                     cout<<<",";         }         cout<         for(i=0;i<20;i++)//另一种打印方式         {                 for(j=0;j<3;j++)                         cout<<*(*(p+i)+j)<<",";         } } […]

Tags: ,. 2,604 views

#include<iostream> #include<fstream> using namespace std; int main() { ofstream file; file.open(“test.txt”,ios::app); //追加,ios::app的作用就是追加 //当文件打开失败,它也会自动地创建文件“test.txt” file<<“one   \n”; file<<“two   \n”; file<<“three   \n”; return 0; } //当第二次运行这个程序时,one,two,three还在test.txt中,而不是被抹掉了

Tags: ,. 2,002 views

上实验课的时候做的,把“结构体”和“链表”和“类”联系到了一块,第一次这样做. 有什么不足的地方还请高手指教! 题目: [实现要求] 利用上一实验设计的链表结构存放队列类中的队列元素。也即队列元素的空间是动态申请的。 在构造队列对象时,初始化该链表,在析构队列对象时,释放链表所占的空间。 C语言: 高亮代码由发芽网提供 /** Author: Wang Runzhen* Date  : 2009 年 8 月 14 日*/ #include<iostream>using namespace std;struct List{    int n;    struct List *next;}; class Queue{private:    int count;    List *p,*head,*pNext,*die;public:    Queue()    {        count=0;        p=new List;       […]

Tags: ,,. 2,542 views

转载: 为了避免同一个文件被include多次 1 #ifndef方式 2 #pragma once方式 在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别。 方式一: #ifndef __SOMEFILE_H__ #define __SOMEFILE_H__ … … // 一些声明语句 #endif 方式二: #pragma once … … // 一些声明语句 #ifndef的方式依赖于宏名字不能**,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心“撞车”,可能就会导致头文件明明存在,编译器却硬说找不到声明的状况 #pragma once则由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名碰撞引发的“找不到声明”的问题,重复包含更容易被发现并修正。 方式一由语言支持所以移植性好,方式二 可以避免名字重复

Tags: ,. 2,343 views

同学你好,当你看到这个页面时,你一定实在做课程设计吧? 曾经这儿有一份完整的答案,但是我把它删除了,抱歉,搞得跟标题党一样,让您白跑一趟了; 我觉得我不能把一份答案放在这里,这是在误人子弟,尽管你可以继续Google到另一份答案; 不过我还是想劝你自己动手写写吧,当你写完了肯定回很有收获的! 以下是这次课程设计的题目,在题目的基础上,我适当的增加和减少的某些功能。 设计题目2:学生信息管理系统 设计要求: 设计要求实现如下功能: (1)建立学生信息数据,包括学号、姓名、性别、三科成绩、出生时间、年龄(必须计算得到)。 (2)使用继承的方法构造至少3个类,(即学生类——虚基类,本科生和研究生类——派生类)使用相应的对象放置10个学生信息。 (3)编写同名display()成员函数,用来输出数组的内容。 (4)按不同类别输出学生信息,比如按性别。(可选功能) (5)要求对“<<”和“>>”运算符进行重载。 (6)抽取并计算学生的平均成绩。 (7)按照至少一科成绩进行排序。 (8)检索(查找)指定信息。(如按姓名检索、按年龄检索) 贴出部分代码,完整的在附件里可以下载,呵呵

Tags: ,. 5,763 views

转自原博客 QUOTE: #include <iostream> #include <list> #include <numeric> #include <algorithm> using namespace std; //创建一个list容器的实例LISTINT typedef list<int> LISTINT; //创建一个list容器的实例LISTCHAR typedef list<int> LISTCHAR; void main(void) { //————————– //用list容器处理整型数据 //————————– //用LISTINT创建一个名为listOne的list对象 LISTINT listOne; //声明i为迭代器 LISTINT::iterator i; //从前面向listOne容器中添加数据 listOne.push_front (2); listOne.push_front (1); //从后面向listOne容器中添加数据 listOne.push_back (3); listOne.push_back (4); //从前向后显示listOne中的数据 cout<<“listOne.begin()— listOne.end():”<<endl; for (i = listOne.begin(); i != listOne.end(); ++i) cout […]

Tags: ,. 4,710 views
2,045 views

编写一个函数,求从n个不同的数中取r个数的所有选择的个数    其中: n! = n*(n-1)*(n-2)*…*1。   //非递归 #include<iostream.h> double fn(int n); double Cnr(int n,int r); void main() {      int n,r;       for(;;)    {       cout<<"Put in n , r:";       cin>>n>>r;       if(n>0&&r>=0&&r<n)            break;       else            cout<<"The number is error!"<<endl;    }        cout<<"result="<<Cnr(n,r)<<endl; }     double fn(int n) {      double s=1;      for(int i=1;i<=n;i++)     {          s=s*i;      }      return s; }   double Cnr(int n,int r) {     double sum;     sum=fn(n)/(fn(r)*fn((n-r)));     return sum; }     //递归 #include<iostream.h> double Cnr(int ,int); void main() {  int n,r;  for(;;)  {      cout<<"Put in n,r:";      cin>>n>>r;      if(n>0&&r>0&&r<n)            break;      else […]

Tags: ,. 2,007 views
2009/08/13

  转自原博客 vector deque 以及list 都是动态增长的,在这三者之中选择的准则主要是关注插入特性以及对元素的后续访问要求 vector 表示一段连续的内存区域每个元素被顺序存储在这段内存中。对vector 的随机访问效率很高 。但是在任意位置而不是在vector 末尾插人元素则效率很低,因为它需要把待插入元素右边的每个元素都拷贝一遍。类似地删除任意一个而不是vector的最后一个元素效率同样很低

Tags: ,. 9,492 views