随笔 - 23  文章 - 0 评论 - 68 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

广告中国绩效网,注册立刻送10元 广告中国绩效网,注册立刻送10元

常用链接

留言簿(7)

随笔分类

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

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

int copy_from_back(FILE * srcfd, FILE * dstfd);

int main(int argc, char *argv[])
{
 FILE *srcfd = NULL;
 FILE *dstfd = NULL;
 
 if (argc != 3)
 {
  printf("usage: FileStudy srcFiel dstFile\n");
 }

 srcfd = fopen(argv[1], "r");
 dstfd = fopen(argv[2], "w+");

 if (copy_from_back(srcfd, dstfd) == -1)
 {
  printf("copy error: ");
  exit(EXIT_FAILURE);
 }

 return 0; 
}


int copy_from_back(FILE *srcfd, FILE *dstfd)
{
 char ch;
 int num_read = 0;
 
 if (srcfd == NULL || dstfd == NULL)
 {
  perror("fopen error: ");
  return -1;
 }

 fseek(dstfd, 0, SEEK_SET);
 
 /*指向文件末尾,如果继续读,返回EOF*/
 if (fseek(srcfd, 1, SEEK_END) != 0)
 {
  perror("fseek error");
 } 
 else
 {
  
  printf("begin to read file\n");
  while (ftell(srcfd) > 0)
  {
   char ch = fgetc(srcfd);
   if (ch == EOF)
   {
    printf("file end!\n");
    fseek(srcfd, -2, SEEK_CUR);
    continue;
   }
   putchar(ch);
   fputc(ch, dstfd);
   num_read++;
   fseek(srcfd, -2, SEEK_CUR);
  }

  char start = fgetc(srcfd);
  putchar(start);
  printf("\nread file end: %d \n", num_read);
 }

 return 0;
}

/*
int copy_from_back(FILE *srcfd, FILE *dstfd)
{
 char ch;
 
 if (srcfd == NULL || dstfd == NULL)
 {
  perror("fopen error: ");
  return -1;
 }
 
 fseek(srcfd, 0, SEEK_SET);
 
 while ((ch = fgetc(srcfd)) != EOF)
 { 
  putchar(ch);
  
  fputc(ch, dstfd); 
  fseek(dstfd, 1, SEEK_SET);
 }

 return 0;
}
*/

posted @ 2007-10-18 18:17 吴剑 阅读(264) | 评论 (0)编辑 收藏

如果你需要加入一段在main退出后执行的代码,可以使用atexit()函数,注册一个函数。

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

void fn1( void ), fn2( void ), fn3( void ), fn4( void );

// atexit()以栈的方式注册函数,先注册的函数会后执行。

void main( void )
{
atexit( fn1 );
atexit( fn2 );
atexit( fn3 );
atexit( fn4 );

printf( “This is executed first.\n” );

return;
}

void fn1()
{
printf( “next.\n” );
}

void fn2()
{
printf( “executed ” );
}

void fn3()
{
printf( “is ” );
}

void fn4()
{
printf( “This ” );
}

结果:
This is executed first.
This is executed next.


posted @ 2007-10-16 21:57 吴剑 阅读(238) | 评论 (0)编辑 收藏
linux下用socket的抓包程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h>  
#include <netinet/ip.h> 
#include <string.h> 
#include <netdb.h> 
#include <netinet/tcp.h> 
#include <netinet/udp.h>
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h> 
#include <net/if.h> 
#include <sys/ioctl.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <linux/if_ether.h>
#include <net/ethernet.h>


void die(char *why, int n) 

  perror(why); 
  exit(n); 

int do_promisc(char *nif, int sock ) 

struct ifreq ifr; 
               
strncpy(ifr.ifr_name, nif,strlen(nif)+1); 
   if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1))  //获得flag
   {        
     die("ioctl", 2); 
   } 
  
   ifr.ifr_flags |= IFF_PROMISC;  //重置flag标志
 
   if(ioctl(sock, SIOCSIFFLAGS, &ifr) == -1 )  //改变模式
   {
     die("ioctl", 3); 
   } 

//修改网卡成PROMISC(混杂)模式

char buf[40960]; 

main() 

struct sockaddr_in addr;
struct ether_header *peth;
struct iphdr *pip;        
struct tcphdr *ptcp;
struct udphdr *pudp;

char mac[16];
int i,sock, r, len;        
char *data;
char *ptemp;
char ss[32],dd[32];

if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1)  //建立socket
//man socket可以看到上面几个宏的意思
{
        die("socket", 1); 
}

do_promisc("eth0", sock);    //eth0为网卡名称

system("ifconfig");

for(;;) 

     len = sizeof(addr); 

     r = recvfrom(sock,(char *)buf,sizeof(buf), 0, (struct sockaddr *)&addr,&len); 
     //调试的时候可以增加一个输出r的语句判断是否抓到包
     buf[r] = 0; 
     ptemp = buf;
     peth = (struct ether_header *)ptemp;

     ptemp += sizeof(struct ether_header); //指针后移eth头的长度
     pip = (struct ip *)ptemp; //pip指向ip层的包头

     ptemp += sizeof(struct ip);//指针后移ip头的长度 

     switch(pip->protocol)   //根据不同协议判断指针类型
     {
         case IPPROTO_TCP:
         ptcp = (struct tcphdr *)ptemp;       //ptcp指向tcp头部
         printf("TCP pkt :FORM:[%s]:[%d]\n",inet_ntoa(*(struct in_addr*)&(pip->saddr)),ntohs(ptcp->source));
         printf("TCP pkt :TO:[%s]:[%d]\n",inet_ntoa(*(struct in_addr*)&(pip->daddr)),ntohs(ptcp->dest));
        
         break;
        
         case IPPROTO_UDP:
         pudp = (struct udphdr *)ptemp;      //ptcp指向udp头部 
              printf("UDP pkt:\n len:%d payload len:%d from %s:%d to %s:%d\n", 
             r, 
             ntohs(pudp->len),
             inet_ntoa(*(struct in_addr*)&(pip->saddr)),
             ntohs(pudp->source),
             inet_ntoa(*(struct in_addr*)&(pip->daddr)),
             ntohs(pudp->dest)
         ); 
         break;
        
         case  IPPROTO_ICMP:
         printf("ICMP pkt:%s\n",inet_ntoa(*(struct in_addr*)&(pip->saddr)));
         break;
        
         case  IPPROTO_IGMP:
         printf("IGMP pkt:\n");
         break;
        
         default:
         printf("Unkown pkt, protocl:%d\n", pip->protocol);
         break;
    } //end switch

perror("dump");
 }
 
}

/*
[playmud@fc3 test]$ gcc -v
Reading specs from /usr/lib/gcc/i386-redhat-linux/3.4.2/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-java-awt=gtk --host=i386-redhat-linux
Thread model: posix
gcc version 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)

************************eth的结构**************************************
struct ether_header
{
  u_int8_t  ether_dhost[ETH_ALEN];      // destination eth addr
  u_int8_t  ether_shost[ETH_ALEN];      // source ether addr   
  u_int16_t ether_type;                 // packet type ID field
} __attribute__ ((__packed__));

***********************IP的结构***********************************
struct iphdr
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ihl:4;
    unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int version:4;
    unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
    u_int8_t tos;
    u_int16_t tot_len;
    u_int16_t id;
    u_int16_t frag_off;
    u_int8_t ttl;
    u_int8_t protocol;
    u_int16_t check;
    u_int32_t saddr;
    u_int32_t daddr;
  };

***********************TCP的结构****************************
struct tcphdr
  {
    u_int16_t source;
    u_int16_t dest;
    u_int32_t seq;
    u_int32_t ack_seq;
#  if __BYTE_ORDER == __LITTLE_ENDIAN
    u_int16_t res1:4;
    u_int16_t doff:4;
    u_int16_t fin:1;
    u_int16_t syn:1;
    u_int16_t rst:1;
    u_int16_t psh:1;
    u_int16_t ack:1;
    u_int16_t urg:1;
    u_int16_t res2:2;
#  elif __BYTE_ORDER == __BIG_ENDIAN
    u_int16_t doff:4;
    u_int16_t res1:4;
    u_int16_t res2:2;
    u_int16_t urg:1;
    u_int16_t ack:1;
    u_int16_t psh:1;
    u_int16_t rst:1;
    u_int16_t syn:1;
    u_int16_t fin:1;
#  else
#   error "Adjust your <bits/endian.h> defines"
#  endif
    u_int16_t window;
    u_int16_t check;
    u_int16_t urg_ptr;
};
***********************UDP的结构*****************************
struct udphdr
{
  u_int16_t source;
  u_int16_t dest;
  u_int16_t len;
  u_int16_t check;
};

*************************************************************
*/


posted @ 2007-10-15 22:59 吴剑 阅读(634) | 评论 (0)编辑 收藏

#define INTERFACE "eth0"
#define MAX_SIZE 65535

int init_raw_socket();
int open_promisc(char *interface, int sockfd);

int main()
{
    int sockfd;
    int bytes_recv;
    int addr_len;

    char recv_buff[MAX_SIZE];
    struct sockaddr_in from_addr;
    struct ip *ip;
    struct tcp *tcp;

    sockfd = init_raw_socket();
    open_promisc(INTERFACE, sockfd);

    addr_len = sizeof(from_addr);

    while (1)
    {
        bytes_recv = recvfrom(sockfd, recv_buff, MAX_SIZE - 1, 0,
            (struct sockaddr_in*)&from_addr, &addr_len));
        if (bytes_recv < 0)
        {
            perror("recvfrom error");
            exit(EXIT_FAILURE);
        }

        printf("receive %d bytes from %s\n", bytes_recv,
            inet_ntoa(from_addr.sin_addr));

        ip = (struct ip*)recv_buff;
        if (ip->ip_protocol == 6)
        {
            printf("IP header length ::: %d\n",ip->ip_length);  
            printf("Protocol ::: %d\n",ip->ip_protocol);  
            tcp = (struct tcp *)(buffer + (4*ip->ip_length));  
            printf("Source port ::: %d\n",ntohs(tcp->tcp_source_port));  
            printf("Dest port ::: %d\n",ntohs(tcp->tcp_dest_port));  
        }
    }
    return 0;
}

int init_raw_socket()
{
    int sockfd;
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sockfd < 0)
    {
        perror("create socker error");
        exit(EXIT_FAILURE);
    }
    
    return sockfd;
}

int open_promisc(char *interface, int sockfd)
{
    struct ifreq ifr;
    strncpy(ifr.ifr_name, interface, strlen(interface) + 1);
    if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror("couldn't rettrive flags for the interface");
        exit(EXIT_FAILURE);
    }

    ifr.ifr_flags |= IFF_PROMISC;
    if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) == -1)
    {
        perror("couldn't set the promisc flags");
        exit(EXIT_FAILURE);
    }

    printf("set interface: %s to promisc\n", interface);
    return 0;
}


关于open_promisc打开网口混合模式
#include <sys/ioctl.h>
#include <net/if.h>

Linux 支持 一些 配置 网络设备 的 标准 ioctl. 他们 用于 任意的 套接字 描述符, 而 无须 了解 其 类型 或 系列. 他们 传递 一个 ifreq 结构:

struct ifreq
{
char ifr_name[IFNAMSIZ]; /* Interface name */
union {
struct sockaddr ifr_addr;
struct sockaddr ifr_dstaddr;
struct sockaddr ifr_broadaddr;
struct sockaddr ifr_netmask;
struct sockaddr ifr_hwaddr;
short ifr_flags;
int ifr_ifindex;
int ifr_metric;
int ifr_mtu;
struct ifmap ifr_map;
char ifr_slave[IFNAMSIZ];
char ifr_newname[IFNAMSIZ];
char * ifr_data;
};
}

struct ifconf
{
int ifc_len; /* size of buffer */
union {
char * ifc_buf; /* buffer address */
struct ifreq *ifc_req; /* array of structures */
};
};

一般说来, ioctl 通过 把 ifr_name 设置为 接口 的 名字 来 指定 将要 操作 的 设备. 结构的 其他成员 可以 分享 内存.

如果 某个 ioctl 标记为 特权操作, 那么 操作时 需要 有效uid 为 0, 或者 拥有 CAP_NET_ADMIN 能力. 否则 将 返回 EPERM .

SIOCGIFNAME
给定 ifr_ifindex, 返回 ifr_name 中 的 接口名字. 这是 唯一 返回 ifr_name 内容 的 ioctl.
SIOCGIFINDEX
把 接口 的 索引 存入 ifr_ifindex.
SIOCGIFFLAGS, SIOCSIFFLAGS
读取 或 设置 设备的 活动标志字. ifr_flags 包含 下列值 的 屏蔽位:

设备标志
IFF_UP 接口正在运行.
IFF_BROADCAST 有效的广播地址集.
IFF_DEBUG 内部调试标志.
IFF_LOOPBACK 这是自环接口.
IFF_POINTOPOINT 这是点到点的链路接口.
IFF_RUNNING 资源已分配.
IFF_NOARP 无arp协议, 没有设置第二层目的地址.
IFF_PROMISC 接口为杂凑(promiscuous)模式.
IFF_NOTRAILERS 避免使用trailer .
IFF_ALLMULTI 接收所有组播(multicast)报文.
IFF_MASTER 主负载平衡群(bundle).
IFF_SLAVE 从负载平衡群(bundle).
IFF_MULTICAST 支持组播(multicast).
IFF_PORTSEL 可以通过ifmap选择介质(media)类型.
IFF_AUTOMEDIA 自动选择介质.
IFF_DYNAMIC 接口关闭时丢弃地址.

设置 活动标志字 是 特权操作, 但是 任何进程 都可以 读取 标志字.

SIOCGIFMETRIC, SIOCSIFMETRIC
使用 ifr_metric 读取 或 设置 设备的 metric 值. 该功能 目前 还没有 实现. 读取操作 使 ifr_metric 置 0, 而 设置操作 则 返回 EOPNOTSUPP.
SIOCGIFMTU, SIOCSIFMTU
使用 ifr_mtu 读取 或 设置 设备的 MTU(最大传输单元). 设置 MTU 是 特权操作. 过小的 MTU 可能 导致 内核 崩溃.
SIOCGIFHWADDR, SIOCSIFHWADDR
使用 ifr_hwaddr 读取 或 设置 设备的 硬件地址. 设置 硬件地址 是 特权操作.
SIOCSIFHWBROADCAST
使用 ifr_hwaddr 读取 或 设置 设备的 硬件广播地址. 这是个 特权操作.
SIOCGIFMAP, SIOCSIFMAP
使用 ifr_map 读取 或 设置 接口的 硬件参数. 设置 这个参数 是 特权操作.
struct ifmap 
{
unsigned long mem_start;
unsigned long mem_end;
unsigned short base_addr;
unsigned char irq;
unsigned char dma;
unsigned char port;
};

对 ifmap 结构 的 解释 取决于 设备驱动程序 和 体系结构.

SIOCADDMULTI, SIOCDELMULTI
使用 ifr_hwaddr 在 设备的 链路层 组播过滤器 (multicase filter) 中 添加 或 删除 地址. 这些是 特权操作. 
SIOCGIFTXQLEN, SIOCSIFTXQLEN
使用 ifr_qlen 读取 或 设置 设备的 传输队列长度. 设置 传输队列长度 是 特权操作.
SIOCSIFNAME
ifr_ifindex 中 指定的 接口名字 改成 ifr_newname. 这是个 特权操作.
SIOCGIFCONF
返回 接口地址(传输层) 列表. 出于 兼容性, 目前 只代表 AF_INET 地址. 用户 传送 一个 ifconf 结构 作为 ioctl 的 参数. 其中 ifc_req 包含 一个 指针 指向 ifreq 结构数组, 他的 长度 以字节 为单位 存放在 ifc_len 中. 内核 用 所有 当前的 L3(第三层?) 接口地址 填充 ifreqs, 这些 接口 正在 运行: ifr_name 存放 接口名字 (eth0:1等), ifr_addr 存放 地址. 内核 在 ifc_len 中 返回 实际长度; 如果 他 等于 初始长度, 表示 溢出了, 用户 应该 换一个 大些的 缓冲区 重试 一下. 没有 发生 错误时 ioctl 返回 0, 否则 返回 -1, 溢出 不算 错误.

相关结构体:
/*structure of an ip header*/   
struct ip {     
unsigned int ip_length:4; /*little-endian*/   
unsigned int ip_version:4;  
unsigned char ip_tos;   
unsigned short ip_total_length;    
unsigned short ip_id;    
unsigned short ip_flags;  
unsigned char ip_ttl;  
unsigned char ip_protocol;  
unsigned short ip_cksum;  
unsigned int ip_source; unsigned int ip_dest;    
};  
    
/* Structure of a TCP header */  
struct tcp {  
unsigned short tcp_source_port;  
unsigned short tcp_dest_port;  
unsigned int tcp_seqno;    
unsigned int tcp_ackno;  
unsigned int tcp_res1:4, /*little-endian*/  
tcp_hlen:4,  
tcp_fin:1,  
tcp_syn:1,  
tcp_rst:1,  
tcp_psh:1,  
tcp_ack:1,  
tcp_urg:1,  
tcp_res2:2;  
unsigned short tcp_winsize;  
unsigned short tcp_cksum;  
unsigned short tcp_urgent;  
};  
/*********************EOF***********************************/  

posted @ 2007-10-15 22:58 吴剑 阅读(638) | 评论 (0)编辑 收藏

内存分配方式有三种:

(1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

(2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

(3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

 

posted @ 2007-10-15 18:13 吴剑 阅读(193) | 评论 (0)编辑 收藏

有了malloc/free 为什么还要new/delete ?
malloc 与free 是C++/C 语言的标准库函数,new/delete 是C++的运算符。它们都可
用于申请动态内存和释放内存。
对于非内部数据类型的对象而言,光用maloc/free 无法满足动态对象的要求。对象
在创建的同时要自动执行构造函数, 对象在消亡之前要自动执行析构函数。由于
malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数
和析构函数的任务强加于malloc/free。
因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个
能完成清理与释放内存工作的运算符delete。注意new/delete 不是库函数。
我们先看一看malloc/free 和new/delete 如何实现对象的动态内存管理,见示例7-8。
class Obj
{
public :
Obj(void){ cout << “Initialization” << endl; }
~Obj(void){ cout << “Destroy” << endl; }
void Initialize(void){ cout << “Initialization” << endl; }
void Destroy(void){ cout << “Destroy” << endl; }
};
void UseMallocFree(void)
{
Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存
a->Initialize(); // 初始化
//…
a->Destroy(); // 清除工作
free(a); // 释放内存
}
void UseNewDelete(void)
{
Obj *a = new Obj; // 申请动态内存并且初始化
//…
delete a; // 清除并且释放内存
}
示例7-8 用malloc/free 和new/delete 如何实现对象的动态内存管理
类Obj 的函数Initialize 模拟了构造函数的功能,函数Destroy 模拟了析构函数的功
能。函数UseMallocFree 中,由于malloc/free 不能执行构造函数与析构函数,必须调用
成员函数Initialize 和Destroy 来完成初始化与清除工作。函数UseNewDelete 则简单得

多。
所以我们不要企图用malloc/free 来完成动态对象的内存管理,应该用new/delete。
由于内部数据类型的“ 对象”没有构造与析构的过程,对它们而言malloc/free 和
new/delete 是等价的。
既然new/delete 的功能完全覆盖了malloc/free,为什么C++不把malloc/free 淘
汰出局呢?这是因为C++程序经常要调用C 函数,而C 程序只能用malloc/free 管理动
态内存。
如果用free 释放“new 创建的动态对象”,那么该对象因无法执行析构函数而可能
导致程序出错。如果用delete 释放“malloc 申请的动态内存”,理论上讲程序不会出错,
但是该程序的可读性很差。所以new/delete 必须配对使用,malloc/free 也一样。

 

posted @ 2007-10-15 18:11 吴剑 阅读(504) | 评论 (0)编辑 收藏
      在unix系统调用中,标准输入描述字用stdin,标准输出用stdout,标准出错用stderr表示,但在一些调用函数,引用了STDIN_FILENO表示标准输入才,同样,标准出入用STDOUT_FILENO,标准出错用STDERR_FILENO.
      请问,他们有什么区别吗?
stdin等是FILE *类型,属于标准I/O,在<stdio.h>。
STDIN_FILENO等是文件描述符,是非负整数,一般定义为0, 1, 2,属于没有buffer的I/O,直接调用系统调用,在<unistd.h>。
posted @ 2007-10-15 18:07 吴剑 阅读(437) | 评论 (0)编辑 收藏

1、为什么 fflush(stdin) 是错的

首先请看以下程序:
#include <stdio.h>

int main( void )
{
 int i;

  for (;;)
  {
        fputs("Please input an integer: ", stdout);
        scanf("%d", &i);
        printf("%d\n", i);
  }
  return 0;
}

这个程序首先会提示用户输入一个整数,然后等待用户输入,如果用户输入的是整数,程序会输出刚才输入的整数,并且再次提示用户输入一个整数,然后等待用户输入。但是一旦用户输入的不是整数(如小数或者字母),假设 scanf 函数最后一次得到的整数是 2 ,那么程序会不停地输出“Please input an integer: 2”。这是因为 scanf("%d", &i); 只能接受整数,如果用户输入了字母,则这个字母会遗留在“输入缓冲区”中。因为缓冲中有数据,故而 scanf 函数不会等待用户输入,直接就去缓冲中读取,可是缓冲中的却是字母,这个字母再次被遗留在缓冲中,如此反复,从而导致不停地输出“Please input an integer: 2”。
 
也许有人会说:“居然这样,那么在 scanf 函数后面加上‘fflush(stdin);’,把输入缓冲清空掉不就行了?”然而这是错的!C和C++的标准里从来没有定义过 fflush(stdin)。也许有人会说:“可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?”的确,某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(linux 下的 gcc 就不支持),因为标准中根本没有定义 fflush(stdin)。MSDN 文档里也清楚地写着fflush on input stream is an extension to the C standard(fflush 操作输入流是对 C 标准的扩充)。当然,如果你毫不在乎程序的移植性,用 fflush(stdin) 也没什么大问题。以下是 C99 对 fflush 函数的定义:

int fflush(FILE *stream);
 
如果 stream 指向输出流或者更新流(update stream),并且这个更新流
最近执行的操作不是输入,那么 fflush 函数将把这个流中任何待写数据传送至
宿主环境(host environment)写入文件。否则,它的行为是未定义的。

原文如下:
int fflush(FILE *stream);
If stream points to an output stream or an update stream in which
the most recent operation was not input, the fflush function causes
any unwritten data for that stream to be delivered to the host environment
to be written to the file; otherwise, the behavior is undefined.

  其中,宿主环境可以理解为操作系统或内核等。
    由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用 fflush(stdin)  是不正确的,至少是移植性不好的。

2、清空输入缓冲区的方法

 虽然不可以用 fflush(stdin),但是我们可以自己写代码来清空输入缓冲区。只需要在 scanf 函数后面加上几句简单的代码就可以了。

        /* C 版本 */
        #include <stdio.h>


        int main( void )
        {
            int i, c;
              for ( ; ; )
            {
                fputs("Please input an integer: ", stdout);
                scanf("%d", &i);

             if ( feof(stdin) || ferror(stdin) )
                { /* 如果用户输入文件结束标志(或文件已被读完), */
                  /* 或者发生读写错误,则退出循环               */
           
                    /* do something */
                    break;
                }
                /* 没有发生错误,清空输入流。                 */
                /* 通过 while 循环把输入流中的余留数据“吃”掉 */
                while ( (c = getchar()) != '\n' && c != EOF ) ;
                /* 使用 scanf("%*[^\n]"); 也可以清空输入流, */

               /* 不过会残留 \n 字符。                          */

               printf("%d\n", i);
            }

             return 0;
        }

        /* C++ 版本 */
        #include <iostream>
        #include <limits> // 为了使用numeric_limits

     using std::cout;
        using std::endl;
        using std::cin;
        using std::numeric_limits;
        using std::streamsize;

     int main()
        {
            int value;
            for ( ; ; )
            {
                cout << "Enter an integer: ";
                cin >> value;
                if ( cin.eof() || cin.bad() )
                { // 如果用户输入文件结束标志(或文件已被读完),
                  // 或者发生读写错误,则退出循环

                 // do something
                    break;
                }
                // 读到非法字符后,输入流将处于出错状态,
                // 为了继续获取输入,首先要调用 clear 函数
                // 来清除输入流的错误标记,然后才能调用
                // ignore 函数来清除输入流中的数据。
                cin.clear();
                // numeric_limits<streamsize>::max() 返回输入缓冲的大小。
                // ignore 函数在此将把输入流中的数据清空。
                // 这两个函数的具体用法请读者自行查询。
                cin.ignore( numeric_limits<streamsize>::max(), '\n' );

                cout << value << '\n';
            }

         return 0;
        }

posted @ 2007-10-15 18:06 吴剑 阅读(3277) | 评论 (0)编辑 收藏
    在网络上面我们用的IP都是数字加点(192.168.0.1)构成的, 而在struct in_addr结构中用的是32位的IP,我们上面那个32位IP(C0A80001)是的192.168.0.1 为了转换我们可以使用下面两个函数 

    int inet_aton(const char *cp,struct in_addr *inp)
    char *inet_ntoa(struct in_addr in)

    函数里面 a 代表 ascii n 代表network.第一个函数表示将a.b.c.d的IP转换为32位的IP,存储在 inp指针里面.第二个是将32位IP转换为a.b.c.d的格式.


    同样inet_addr也可以进行字符串到32位整形的转换:

    首先,假设你已经有了一个sockaddr_in结构体ina,你有一个IP地址"132.241.5.10" 要储存在其中,你就要用到函数inet_addr(),将IP地址从 点数格式转换成无符号长整型。使用方法如下:
    ina.sin_addr.s_addr = inet_addr("132.241.5.10");
    有的也使用unsigned long dst_ip = inet_addr("");

    可见IPv4 套接口地址结构
    struct in_addr
    {
        in_addr_t s_addr ;
    }
    // 32bits IPv4 地址
    //网络字节顺序 Network Byte Order
    类似:
    struct in_addr
    {
        unsigned long s_addr; // that’s a 32-bit long, or 4 bytes
    };

    这里错误返回INADDR_NONE (实际上是-1,每位都是1)
    而另一个INADDR_ANY的值为0,意思是任何地址都可以。

    注意,inet_addr()返回的地址已经是网络字节格式,所以你无需再调用 函数htonl()。
    我们现在发现上面的代码片断不是十分完整的,因为它没有错误检查。 显而易见,当inet_addr()发生错误时返回-1。记住这些二进制数字?(无符  号数)-1仅仅和IP地址255.255.255.255相符合!这可是广播地址!大错特 错!记住要先进行错误检查。
    好了,现在你可以将IP地址转换成长整型了。有没有其相反的方法呢? 它可以将一个in_addr结构体输出成点数格式?这样的话,你就要用到函数 inet_ntoa()("ntoa"的含义是"network to ascii"),就像这样: 
    printf("%s",inet_ntoa(ina.sin_addr));
    它将输出IP地址。需要注意的是inet_ntoa()将结构体in-addr作为一 个参数,不是长整形。同样需要注意的是它返回的是一个指向一个字符的 指针。它是一个由inet_ntoa()控制的静态的固定的指针,所以每次调用 inet_ntoa(),它就将覆盖上次调用时所得的IP地址。例如:
    char *a1, *a2;
    .
    .
    a1 = inet_ntoa(ina1.sin_addr); /* 这是198.92.129.1 */
    a2 = inet_ntoa(ina2.sin_addr); /* 这是132.241.5.10 */
    printf("address 1: %s ",a1);
    printf("address 2: %s ",a2);
    输出如下:
    address 1: 132.241.5.10
    address 2: 132.241.5.10
    假如你需要保存这个IP地址,使用strcopy()函数来指向你自己的字符指针。



posted @ 2007-10-11 23:32 吴剑 阅读(22620) | 评论 (0)编辑 收藏
atoi(将字符串转换成整型数)
相关函数 atof,atol,atrtod,strtol,strtoul

表头文件 #include<stdlib.h>

定义函数 int atoi(const char *nptr);

函数说明 atoi()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。如果遇到错误返回0。

返回值 返回转换后的整型数。如果都是字符串,则应该是0。

附加说明 atoi()与使用strtol(nptr,(char**)NULL,10);结果相同。

范例 /* 将字符串a 与字符串b转换成数字后相加*/
#include<stdlib.h>
mian()
{
char a[]=”-100”;
char b[]=”456”;
int c;
c=atoi(a)+atoi(b);
printf(c=%d\n”,c);
}

执行 c=356

posted @ 2007-10-11 23:09 吴剑 阅读(336) | 评论 (0)编辑 收藏
仅列出标题
共3页: 1 2 3