编程基础及技巧

避免对空指针进行赋值操作时内存崩溃方法:

char netdb[1024] = {0};定义数组常量

char *netdebug = netdb;把数组指针赋值给字符串指针,这样字符串指针就不是空指针了,避免了空指针操作。

fseek(fp, 0, 2);

acklen = ftell(fp);

fseek(fp, 0, 0);       求文件指针的指向的文件的大小

/*执行结果写进ackuf */

if((fgets(ackbuf, acklen, fp)) ==NULL )    fgets函数一次只能读取一行

{

ackstatus = ERR_CLIREQ;

goto Err;

}

调试语句,加在你认为可能出错的地方,例如:

fprintf(stderr, "00000000000000000000:%s\n", tmp);

fprintf(stderr, "222222222222222222222222:%d\n", acklen);

if(!strncmp(tmp, "0", strlen(tmp))) 判断字符串是否是0,这种用法很繁琐,可以用下面的指令:

if(tmp[0] == ‘0‘)

char netto[1024] = {0};

char *nettool = netto;

char *nettooldef = netto;两个字符串指针指向的是同一个内存地址,无论是对nettool操作还是对nettooldef操作,都是对同一个内存地址进行操作。还是没有避免混淆。

正确用法:

char netto[1024] = {0};

char nettodef[1024] = {0};

char *nettool = netto;

char *nettooldef = nettodef;

strncat("ping -c 3", tmp, strlen(tmp));这种用法是错误的,extern char *strncat(char *dest,char *src,int n);  dest是一个指针变量,代表内存地址,不应该是常量。正确用法如下:

char ping[20] = "ping -c 3";

strncat(ping, tmp, strlen(tmp));

fseek(fp, 0, 2);

acklen = ftell(fp);

fseek(fp, 0, 0);

ackbuf = (char *)malloc(acklen);

/*执行结果写进ackuf */

if((fread(ackbuf, 1, acklen, fp)) != acklen )     这样管道获取acklen是错误的。解决方法如下

while(!feof(fp) && (++acount_buf))

{

/* strlen入参不能为空指针!!!!!!!!!!!!!!!!!,故改用acount_buf */

ackbuf = (unsigned char *)realloc(ackbuf, acount_buf * BUF_SIZE);

if(!ackbuf)

{

ackstatus = ERR_CLIREQ;

goto Err;

}

fread(ackbuf + strlen(ackbuf), sizeof(char), BUF_SIZE, fp);}   第一次只是给ackbuf分配了内存空间,但是没有赋值,而strlen求的是实际的字符串长度,因此strlen(ackbuf)=0.

/* 标志位 */

tmp = strtok((char *)reqbuf, "\r\n");

switch(tmp[0])

{

case ‘0‘:

/* netstat */

snprintf(cmdline, sizeof(cmdline), "%s", NETSTAT_CMD);

break;

case ‘1‘:

/* arp */

snprintf(cmdline, sizeof(cmdline), "%s", ARP_CMD);

break;

case ‘2‘:

/* ping */

tmp = strtok(NULL, "\r\n");

assert(tmp);

snprintf(cmdline, sizeof(cmdline), "%s%s", PING_CMD, tmp);

break;

case ‘3‘:

/* traceroute */

tmp = strtok(NULL, "\r\n");

assert(tmp);

snprintf(cmdline, sizeof(cmdline), "%s%s", TRACEROUTE_CMD, tmp);

break;

case ‘4‘:

/* nmap */

tmp = strtok(NULL, "\r\n");

assert(tmp);

snprintf(cmdline, sizeof(cmdline), "%s%s", NMAP_CMD, tmp);

break;

default :

/* other error!! */

ackstatus = ERR_CLIREQ;

goto Err;

}

这段程序很是繁琐,修改如下:

tmp = strtok((char *)reqbuf, "\r\n");

cmdnum = atoi(tmp);

/* 容错处理 */

if(cmdnum < 0 || cmdnum >4)

{

ackstatus = ERR_CLIREQ;

goto Err;

}

/* 命令参数 */

tmp = strtok(NULL, "\r\n");

snprintf(cmdline, sizeof(cmdline), "%s%s", cmdbuf[cmdnum], tmp ? tmp : "");

snprintf(cmdline, sizeof(cmdline), "%s%s", cmdbuf[cmdnum], tmp ? tmp : null);

编译出错,null没有内存地址,snprintf出错。修改如下:

snprintf(cmdline, sizeof(cmdline), "%s%s", cmdbuf[cmdnum], tmp ? tmp : "");

char *tmp = NULL;

tmp = strtok((char *)cmdline, "\r\n");        不需要给tmp提前分配内存,因为tmp只是和strtok指向同一个内存空间。

调试语句的使用技巧,使用#if 1   #endif 1:

#if 1(0表示永远都不会成立的一个条件,这样这段代码就不会编译了,1表示永远都成立的条件)

char test[] = "192.168.51.206\r\n21\r\nftp\r\n123456\r\nDIRECTORY\r\n\r\n";

reqbuf = (char *)test;

#endif

makecert.c:

struct iw_key_struct

{

char crtname[64];

char commoname[64];

char country[4];

…….

}

…..

tmp=China;

sprintf(keystr->country,"%s\n",tmp);

程序执行错误,修改char country[10]之后,没有问题了。使用sprintf时,格式化数据大小必须小于字符缓冲区大小。

#define MAKEKEYPATH "/home/xiachengjiao/nnba/nnba/mise/calls/engine/key/"

snprintf(cmdline, sizeof(cmdline), "mkdir %sdemoCA 1>/dev/null 2>&1", MAKEKEYPATH);

retval = iw_system(cmdline);

指令执行错误,因为/engine/key/demoCA/之前不存在,所以mkdir需要加参数-p。正确写法:

snprintf(cmdline, sizeof(cmdline), "mkdir –p %sdemoCA 1>/dev/null 2>&1", MAKEKEYPATH);

snprintf(cmdline, sizeof(cmdline), "select keyname from server.ww_cert_t where keyname=‘%s‘", keyname);

snprintf的用法是挺巧妙的,如上。

char **res = NULL;

int retval = 0;

DEBUGLOG(IW_LOG_MAINBRANCE, DEBUG, "keyname=%s,endtime=%s,remark=%s\n", keyname, endtime, remark);

/* 判断数据库表中证书名称是否重复 */

snprintf(cmdline, sizeof(cmdline), "select keyname from server.ww_cert_t where keyname=‘%s‘", keyname);

DEBUGLOG(IW_LOG_MAINBRANCE, DEBUG, "cmdline=%s\n", cmdline);

retval = iw_db_select(cmdline, res);

DEBUGLOG(IW_LOG_MAINBRANCE, DEBUG, "retval=%d,*res=%s\n",  retval,* res);

程序段错误,下面程序正确的。

char *res = NULL;

int retval = 0;

DEBUGLOG(IW_LOG_MAINBRANCE, DEBUG, "keyname=%s,endtime=%s,remark=%s\n", keyname, endtime, remark);

/* 判断数据库表中证书名称是否重复 */

snprintf(cmdline, sizeof(cmdline), "select keyname from server.ww_cert_t where keyname=‘%s‘", keyname);

DEBUGLOG(IW_LOG_MAINBRANCE, DEBUG, "cmdline=%s\n", cmdline);

retval = iw_db_select(cmdline, &res);

DEBUGLOG(IW_LOG_MAINBRANCE, DEBUG, "retval=%d,res=%s\n",  retval, res);

时间: 2024-10-20 00:46:55

编程基础及技巧的相关文章

Linux CGI编程基础【整理】

Linux CGI编程基础 1.为什么使用CGI? 如前面所见,任何的HTML均是静态网页,它无法实现一些复杂的功能,而CGI可以为我们实现.如:a.列出服务器上某个目录中的文件,对目录中的文件进行操作:b.通过CGI实现串口通讯:c.实现数据库接口:d.实现从摄像头读取一张图片显示在网页上… 等等 2. CGI是什么? CGI全称是 Common Gate Intergace ,在物理上,CGI是一段程序,它运行在Server上,提供同客户端 Html页面的接口. 3. CGI编程语言 你可以

编程基础知识——C++能不能支持Java和ObjC的反射?

C++能不能支持Java和ObjC的反射? 要回答这个问题,首先我们要清楚什么是反射.什么是反射? 教科书的解释我就不说了,(^o^)其实我也记不得.实际开发应用的反射就是在没有某个类型的头文件或者类结构定义的情况下,存取这个类型的对象的成员字段的值,调用这个对象的成员函数(方法). 比如我有定义了一个类型 Class  A,里面有 a,b,c三个字段,有fun()函数.现在我手里只有一个 void* pA,注意它的类型只是一个void指针,我手里也没有Class的头文件,我要怎么样得到,a,b

编程基础知识——java类加载

java类加载 先来看一段小程序: package com; public class Main1 { static { System.out.println("1111") ; } public static void main(String[] args) { System.out.println("2222") ; } } 输出结果为: 1111 2222 其中static的执行时机就是class被 classloader加载的时候执行. 这有什么用?看下面代

(转)Windows驱动编程基础教程

版权声明 本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括各种格式的文档)复制和转载本书.同时不限制利用此书赢利的行为(如收费注册下载,或者出售光盘或打印版本).不满足此前提的任何转载. 复制.赢利行为则是侵犯版权的行为. 发现本书的错漏之处,请联系作者.请不要修改本文中任何内容,不经过作者的同意发布修改后的版本. 作者信息 作者网名楚狂人.真名谭文.在上海从事W

Python核心编程基础教程之Python运算符、运算符优先级、表达式简介--20150717

Python核心编程基础教程之Python运算符.运算符优先级.表达式简介 1.Python运算符与表达式: (1)认识Pyhton运算符1:什么是运算符 在Python运算中,有时候我们需要对一个或者多个数字或者一个或者多个字符串进行运算操作,*,+ (2)认识Pyhton运算符2:运算符有哪些以及运算符的使用方法 + :加 - :减 * :乘 / :除 ** :幂 < :小于 > :大于 != :不等于 // :求相除的整数部分 % :求相除的余数部分 & :按位与 | :按位或

1.5编程基础之循环控制_29:数字反转

/* 1.5编程基础之循环控制 29:数字反转 总时间限制: 1000ms 内存限制: 65536kB 描述 给定一个整数,请将该数各个位上数字反转得到一个新数. 新数也应满足整数的常见形式,即除非给定的原数为零, 否则反转后得到的新数的最高位数字不应为零(参见样例2). 输入 输入共 1 行,一个整数N. -1,000,000,000 ≤ N≤ 1,000,000,000. 输出 输出共 1 行,一个整数,表示反转后的新数. 样例输入 样例 #1: 123 样例 #2: -380 样例输出 样

网络编程基础

网络编程基础 1.套接字概念 Linux环境下使用套接字进行进程之间的通信.用过套接字的接口,其他进程的位置对于应用程序来讲是透明的.相互通信双方端点都有一个套接字,双方如果要进行通信,通过套接字建立桥梁,双方就可以通信了. 类似文件一样,套接字也有一个套接字描述符,应用程序可以像操作文件一样操作套接字.在进行网络通信的过程中,用户感觉就是在操作文件一样,这是Linux将外部设备抽象为一个文件的好处. 2.字节序 不同主机的体系结构不同,所采用的数据存储方式不同.网络中,进程之间的通信是跨主机的

多线程编程基础知识

多线程编程基础知识 http://www.cnblogs.com/cy163/archive/2006/11/02/547428.html 当前流行的Windows操作系统能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程提供了多任务处理的能力.用进程和线程的观点来研究软件是当今普遍采用的方法,进程和线程的概念的出现,对提高软件的并行性有着重要的意义.现在的大型应用软件无一不是多线程多任务处理,单线程的软件是不可想象的.因此掌握

shell 脚本编程基础

一.编程基础 程序:指令+数据 程序编程风格: 过程式:以指令为中心,数据服务于指令 对象式:以数据为中心,指令服务于数据 shell程序:提供了编程能力,解释执行 1.程序的执行方式 计算机:运行二进制指令: 编程语言: 低级:汇编 高级: 编译:高级语言–>编译器–>目标代码 java,C# 解释:高级语言–>解释器–>机器代码 shell, perl, python 2.编程基本概念 编程逻辑处理方式: 顺序执行 循环执行 选择执行 shell编程:过程式.解释执行 编程语言