c语言中memcpy是字节大小,使用memcpy函数时要注意拷贝数据的长度

memcpy函数简介

memcpy函数是C/C++语言中的一个用于内存复制的函数,声明在 string.h 中(C++是 cstring)。其原型是:

void *memcpy(void *destin, void *source, unsigned n);

作用是:以source指向的地址为起点,将连续的n个字节数据,复制到以destin指向的地址为起点的内存中。

函数有三个参数,第一个是目标地址,第二个是源地址,第三个是数据长度。

使用memcpy函数时,需要注意:

数据长度(第三个参数)的单位是字节(1byte = 8bit)。

注意该函数有一个返回值,类型是void*,是一个指向destin的指针。

memcpy函数复制的数据长度

使用memcpy函数时,特别要注意数据长度。

如果复制的数据类型是char,那么数据长度就等于元素的个数。而如果数据类型是其他(如int, double, 自定义结构体等),就要特别注意数据长度的值。

好的习惯是,无论拷贝何种数据类型,都用 n * sizeof(type_name)的写法。

先以最简单的情况说明:

char a[10] = "abcdefgh";

unsigned n = 2;

void * p = memcpy(a+3, a, n);

以上代码将从a开始的两个字节的数据(即'a'和'b'),复制到从a+3开始的内存('d'所在的地址)。这样,'d'和'e'被替换。

执行结束之后,字符数组(字符串)a的内容变为"abcabfgh",返回值p即为a的地址(p == a)。

再以int类型为例说明:

int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

unsigned n = 5;

void * p = memcpy(a+3, a, n);

int类型的长度是4个字节。以上代码将从a开始的5个字节的数据复制。5个字节的数据是什么呢?前四个字节组成了一个完整的int(即第一个元素0)。第五个字节,只能取到第二个元素的第1个字节。这里又会涉及到big-endian和little-endian的问题。假设是小端方式储存(更常见),那么读到的是元素1的低8位,写成十六进制即0x1。

目标地址是a+3。由于指针加减常数,单位是与类型保持一致的,也就是在a的基础上,增加3倍int长度,对应的是元素3的地址。元素3被替换为0。元素4写成十六进制是0x0004,低8位被替换为0x1,变为0x0001。

所以执行结束之后,数组a的内容变为 { 0, 1, 2, 0, 1, 5, 6, 7, 8, 9 },返回值p即为a的地址(p == a)。

根据上面的解释,如果把程序里的n改为6、7、8,那么结果都是一样的。因为数字1和4的二进制表示除了低8位不同,高位都是0。

倘若高位不相同,那么结果就没那么简单了。还是以int数组为例:

int a[10] = { 0, -1, 2, 3, 4, 5, 6, 7, 8, 9 };

unsigned n = 5;

memcpy(a+3, a, n);

复制5个字节的数据,前4个字节组成了一个int,即第一个元素0。那么元素3被替换为0。第5个字节从-1中取。-1的十六进制表示为0xFFFF,第5个字节的数据是0xF。元素4变为0x000F,即15。数组a变为 { 0, -1, 2, 0, 15, 5, 6, 7, 8, 9 }。

如果 n = 6,那么4变为```0x00FF``,即255。数组a变为 { 0, -1, 2, 0, 255, 5, 6, 7, 8, 9 }。

可以看出,如果你想用memcpy复制元素,那么一定要写对数据长度。如果要完整地复制 n 个 int 类型元素,那么写法如下:

int a[10] = { 0, -1, 2, 3, 4, 5, 6, 7, 8, 9 };

unsigned n = 5 * sizeof(int);

memcpy(a+3, a, n);

数组a变为 { 0, -1, 2, 0, -1, 2, 0, -1, 8, 9 }。

如果是其他类型,用法也是一样的。

好的习惯是,如果拷贝何种数据类型,都用 n * sizeof(type_name)的写法。

sprintf、strcpy 及 memcpy 函数区别

这些函数的区别在于 实现功能 以及 操作对象 不同.strcpy 函数操作的对象是 字符串 ,完成 从 源字符串 到 目的字符串 的 拷贝 功能. sprintf 函数操作的对象 不限于字符串 :虽然 ...

memmove和memcpy函数的区别及实现

一.memmove()和memcpy()函数和strcpy()函数的区别: (1)使用的类型不同,strcpy()函数只对字符串进行操作:memmove()和memcpy()函数对所有类型都适用,为内 ...

一个按比特位拷贝数据的函数copybits

一个按比特位拷贝数据的函数 没有进行特别的优化.其实还可以在拷贝源开始位置和目标开始位置是2的整数倍位置的时候进行优化. 说明 这个函数用于从src数组首地址跳过sbb个字节,又跳过ssb个比特位,拷 ...

ajax请求为异步操作时,返回的数据不会被并列函数执行

ajax请求为异步操作时,返回的数据不会被并列函数执行

C语言之memcpy函数

昨天自己动手实现memcpy这个函数,用一个例程试了一下,结果正确,满心欢心,可是有些地方想不明白,于是百度了一下,结果自己写的函数简直无法直视. 觉得还是写个总结,以示教训. 先贴上我自己的函数: ...

memcpy函数的使用方法

c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中. 1.函数原型 void *memcpy(void * ...

memset和memcpy函数、atoi函数

memset void *memset(void *s,int c,size_t n) 总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c.如下: // 1.将已开辟内存空间s的首n个字节 ...

实现memcpy()函数及过程总结

1.为什么会写memcpy 在之前的应聘笔试上遇到一道笔试题,题目要求实现一个my_memcpy函数.函数原型:void * my_memcpy(void *dst, const void *src, ...

C/C++ memcpy函数的用法

功能 memcpy指的是c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中 头文件 所在头文件

随机推荐

JS 控制CSS样式表

JS控制CSS所使用的方法:  你想要改变把他的display属性由none改为inline.  ...

spring之BeanFactoryAware接口

springBeanFactoryAware (转)要直接在自己的代码中读取spring的bean,我们除了根据常用的set外,也可以通过spring的BeanFactoryAware接口实现,只要实 ...

java Literals

Primitive Data Types The Java programming language is statically-typed, which means that all variabl ...

jQuery - Chaining

jQuery - Chaining @(编程) 通过 jQuery,您可以把动作/方法链接起来. Chaining 允许我们在一条语句中允许多个 jQuery 方法(在相同的元素上). jQuery ...

基于jQuery的宽屏可左右切换的焦点图插件

之前分享了很多实用的jQuery焦点图插件,大家可以看看.今天要继续为大家分享一款很不错的jQuery焦点图插件,它是宽屏展示的,而且有两个大气的按钮用来左右切换图片.效果图如下: 在线预览   源码 ...

Sql Server——查询(二)

上次写了查询里的一些简单的查询方法,如果说上次的是初级查询,那这次的就是高级查询了. 今天主要是聚合函数.分组查询.连接查询.联合查询.在我看来前三个挺简单的,稍微难理解点的也就最后一个,为什么呢?因 ...

Python 学习 第十六篇:networkx

networkx是Python的一个包,用于构建和操作复杂的图结构,提供分析图的算法.图是由顶点.边和可选的属性构成的数据结构,顶点表示数据,边是由两个顶点唯一确定的,表示两个顶点之间的关系.顶点和边 ...

centos6.7不联网的情况下安装配置本地yum源

1  cd / 2 mkdir -p /app/ios 3  cd /opt     mkdir ios 4   把下载好的centos-6.7-x86_64-bin-dvd1.iso  上传到 /o ...

JVM—内存溢出、OutOfMemoryError、StackOverflowError

学习jvm时看到几篇非常好的系列文章,转载了: 学习小记一之自动内存管理机制(一) http://my.oschina.net/linuxfelix/blog/1 ...

【C#】简单计算器源代码

form1.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.D ...

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package util; import java.lang.reflect.*; public class MD5 { /* 下面这些S11-S44实际上是一个4*4的矩阵,在原始的C实现是用#define 实现的, 这里把它们实现成为static final是表示了只读,切能在同一个进程空间内的多个 Instance间共享*/ static final int S11 = 7; static final int S12 = 12; static final int S13 = 17; static final int S14 = 22; static final int S21 = 5; static final int S22 = 9; static final int S23 = 14; static final int S24 = 20; static final int S31 = 4; static final int S32 = 11; static final int S33 = 16; static final int S34 = 23; static final int S41 = 6; static final int S42 = 10; static final int S43 = 15; static final int S44 = 21; static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 下面的三个成员是MD5计算过程用到的3个核心数据,在原始的C实现 被定义到MD5_CTX结构 */ private long[] state = new long[4]; // state (ABCD) private long[] count = new long[2]; // number of bits, modulo 2^64 (lsb first) private byte[] buffer = new byte[64]; // input buffer /* digestHexStr是MD5的唯一一个公共成员,是最新一次计算结果的   16进制ASCII表示. */ public String digestHexStr; /* digest,是最新一次计算结果的2进制内部表示,表示128bit的MD5值. */ private byte[] digest = new byte[16]; /* getMD5ofStr是类MD5最主要的公共方法,入口参数是你想要进行MD5变换的字符串 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的. */ public String getMD5ofStr(String inbuf) { md5Init(); md5Update(inbuf.getBytes(), inbuf.length()); md5Final(); digestHexStr = ""; for (int i = 0; i < 16; i++) { digestHexStr += byteHEX(digest[i]); } return digestHexStr; } // 这是MD5这个类的标准构造函数,JavaBean要求有一个public的并且没有参数的构造函数 public MD5() { md5Init(); return; } /* md5Init是一个初始化函数,初始化核心变量,装入标准的幻数 */ private void md5Init() { count[0] = 0L; count[1] = 0L; ///* Load magic initialization constants. state[0] = 0x67452301L; state[1] = 0xefcdab89L; state[2] = 0x98badcfeL; state[3] = 0x10325476L; return; } /* F, G, H ,I 是4个基本的MD5函数,在原始的MD5的C实现,由于它们是 简单的位运算,可能出于效率的考虑把它们实现成了宏,在java,我们把它们   实现成了private方法,名字保持了原来C的。 */ private long F(long x, long y, long z) { return (x & y) | ((~x) & z); } private long G(long x, long y, long z) { return (x & z) | (y & (~z)); } private long H(long x, long y, long z) { return x ^ y ^ z; } private long I(long x, long y, long z) { return y ^ (x | (~z)); } /* FF,GG,HH和II将调用F,G,H,I进行近一步变换 FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ private long FF(long a, long b, long c, long d, long x, long s, long ac) { a += F (b, c, d) + x + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long GG(long a, long b, long c, long d, long x, long s, long ac) { a += G (b, c, d) + x + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long HH(long a, long b, long c, long d, long x, long s, long ac) { a += H (b, c, d) + x + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long II(long a, long b, long c, long d, long x, long s, long ac) { a += I (b, c, d) + x + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } /* md5Update是MD5的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个 函数由getMD5ofStr调用,调用之前需要调用md5init,因此把它设计成private的 */ private void md5Update(byte[] inbuf, int inputLen) { int i, index, partLen; byte[] block = new byte[64]; index = (int)(count[0] >>> 3) & 0x3F; // /* Update number of bits */ if ((count[0] += (inputLen << 3)) < (inputLen << 3)) count[1]++; count[1] += (inputLen >>> 29); partLen = 64 - index; // Transform as many times as possible. if (inputLen >= partLen) { md5Memcpy(buffer, inbuf, index, 0, partLen); md5Transform(buffer); for (i = partLen; i + 63 < inputLen; i += 64) { md5Memcpy(block, inbuf, 0, i, 64); md5Transform (block); } index = 0; } else i = 0; ///* Buffer remaining input */ md5Memcpy(buffer, inbuf, index, i, inputLen - i); } /* md5Final整理和填写输出结果 */ private void md5Final () { byte[] bits = new byte[8]; int index, padLen; ///* Save number of bits */ Encode (bits, count, 8); ///* Pad out to 56 mod 64. index = (int)(count[0] >>> 3) & 0x3f; padLen = (index < 56) ? (56 - index) : (120 - index); md5Update (PADDING, padLen); ///* Append length (before padding) */ md5Update(bits, 8); ///* Store state in digest */ Encode (digest, state, 16); } /* md5Memcpy是一个内部使用的byte数组的块拷贝函数,从input的inpos开始把len长度的       字节拷贝到output的outpos位置开始 */ private void md5Memcpy (byte[] output, byte[] input, int outpos, int inpos, int len) { int i; for (i = 0; i < len; i++) output[outpos + i] = input[inpos + i]; } /* md5Transform是MD5核心变换程序,有md5Update调用,block是分块的原始字节 */ private void md5Transform (byte block[]) { long a = state[0], b = state[1], c = state[2], d = state[3]; long[] x = new long[16]; Decode (x, block, 64); /* Round 1 */ a = FF (a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */ d = FF (d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */ c = FF (c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */ b = FF (b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */ a = FF (a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */ d = FF (d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */ c = FF (c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */ b = FF (b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */ a = FF (a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */ d = FF (d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */ c = FF (c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */ b = FF (b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */ a = FF (a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */ d = FF (d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */ c = FF (c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */ b = FF (b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */ /* Round 2 */ a = GG (a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */ d = GG (d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */ c = GG (c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */ b = GG (b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */ a = GG (a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */ d = GG (d, a, b, c, x[10], S22, 0x2441453L); /* 22 */ c = GG (c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */ b = GG (b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */ a = GG (a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */ d = GG (d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */ c = GG (c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */ b = GG (b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */ a = GG (a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */ d = GG (d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */ c = GG (c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */ b = GG (b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */ /* Round 3 */ a = HH (a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */ d = HH (d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */ c = HH (c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */ b = HH (b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */ a = HH (a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */ d = HH (d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */ c = HH (c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */ b = HH (b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */ a = HH (a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */ d = HH (d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */ c = HH (c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */ b = HH (b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */ a = HH (a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */ d = HH (d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */ c = HH (c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */ b = HH (b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */ /* Round 4 */ a = II (a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */ d = II (d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */ c = II (c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */ b = II (b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */ a = II (a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */ d = II (d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */ c = II (c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */ b = II (b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */ a = II (a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */ d = II (d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */ c = II (c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */ b = II (b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */ a = II (a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */ d = II (d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */ c = II (c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */ b = II (b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; } /*Encode把long数组按顺序拆成byte数组,因为java的long类型是64bit的, 只拆低32bit,以适应原始C实现的用途 */ private void Encode (byte[] output, long[] input, int len) { int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (byte)(input[i] & 0xffL); output[j + 1] = (byte)((input[i] >>> 8) & 0xffL); output[j + 2] = (byte)((input[i] >>> 16) & 0xffL); output[j + 3] = (byte)((input[i] >>> 24) & 0xffL); } } /*Decode把byte数组按顺序合成成long数组,因为java的long类型是64bit的, 只合成低32bit,高32bit清零,以适应原始C实现的用途 */ private void Decode (long[] output, byte[] input, int len) { int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = b2iu(input[j]) | (b2iu(input[j + 1]) << 8) | (b2iu(input[j + 2]) << 16) | (b2iu(input[j + 3]) << 24); return; } /* b2iu是我写的一个把byte按照不考虑正负号的原则的"升位"程序,因为java没有unsigned运算 */ public static long b2iu(byte b) { return b < 0 ? b & 0x7F + 128 : b; } /*byteHEX(),用来把一个byte类型的数转换成十六进制的ASCII表示,  因为java的byte的toString无法实现这一点,我们又没有C语言的 sprintf(outbuf,"%02X",ib) */ public static String byteHEX(byte ib) { char[] Digit = { '0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' }; char [] ob = new char[2]; ob[0] = Digit[(ib >>> 4) & 0X0F]; ob[1] = Digit[ib & 0X0F]; String s = new String(ob); return s; } public static String toMD5(String source){ MD5 md5 = new MD5(); return md5.getMD5ofStr(source); } }
软件编程规范培训实例与练习 软件编程规范培训实例与练习  问题分类 1 逻辑类问题(A类)-指设计、编码出现的计算正确性和一致性、程序逻辑控制等方面出现的问题,在系统起关键作用,将导致软件死机、功能正常实现等严重问题; 接口类问题(B类)-指设计、编码出现的函数和环境、其他函数、全局/局部变量或数据变量之间的数据/控制传输不匹配的问题,在系统起重要作用,将导致模块间配合失效等严重问题; 维护类问题(C类)-指设计、编码出现的对软件系统的维护方便程度造成影响的问题,在系统不起关键作用,但对系统后期维护造成不便或导致维护费用上升; 可测试性问题(D类)-指设计、编码因考虑不周而导致后期系统可测试性差的问题。  处罚办法 问题发生率: P=D/S D=DA+0.5DB+0.25DC 其: P -问题发生率 D -1个季度内错误总数 DA -1个季度内A类错误总数 DB -1个季度内B类错误总数 DC -1个季度内C类错误总数 S -1个季度内收到问题报告单总数 1)当D≥3时,如果P≥3%,将进行警告处理,并予以公告; 2)当D≥5时,如果P≥5%,将进行罚款处理,并予以公告。 目 录 一、逻辑类代码问题 第5页 1、变量/指针在使用前就必须初始化 第5页 【案例1.1.1】 第5页 2、防止指针/数组操作越界 第5页 【案例1.2.1】 第5页 【案例1.2.2】 第6页 【案例1.2.3】 第7页 【案例1.2.4】 第8页 3、避免指针的非法引用 第9页 【案例1.3.1】 第9页 4、变量类型定义错误 第10页 【案例1.4.1】 第10页 5、正确使用逻辑与&&、屏蔽&操作符 第17页 【案例1.5.1】 第17页 6、注意数据类型的匹配 第18页 【案例1.6.1】 第18页 【案例1.6.2】 第18页 7、用于控制条件转移的表达式及取值范围是否书写正确 第20页 【案例1.7.1】 第20页 【案例1.7.2】 第21页 【案例1.7.3】 第22页 8、条件分支处理是否有遗漏 第24页 【案例1.8.1】 第24页 9、引用已释放的资源 第26页 【案例1.9.1】 第26页 10、分配资源是否已正确释放 第28页 【案例1.10.1】 第28页 【案例1.10.2】 第29页 【案例1.10.3】 第30页 【案例1.10.4】 第32页 【案例1.10.5】 第33页 【案例1.10.6】 第35页 【案例1.10.7】 第38页 11、防止资源的重复释放 第39页 【案例1.11.1】 第39页 12、公共资源的互斥性和竞用性 第40页 【案例1.12.1】 第40页 【案例1.12.2】 第40页 二、接口类代码问题 第43页 1、对函数参数进行有效性检查 第43页 【案例2.1.1】 第43页 【案例2.1.2】 第43页 【案例2.1.3】 第44页 【案例2.1.4】 第46页 【案例2.1.5】 第47页 【案例2.1.6】 第48页 2、注意多出口函数的处理 第49页 【案例2.2.1】 第49页 三、维护类代码问题 第51页 1、 统一枚举类型的使用 第51页 【案例3.1.1】 第51页 2、 注释量至少占代码总量的20% 第51页 【案例3.2.1】对XXX产品BAM某版本部分代码注释量的统计 第51页 四、产品兼容性问题 第52页 1、系统配置、命令方式 第52页 【案例4.1.1】 第52页 【案例4.1.2】 第53页 2、设备对接 第54页 【案例4.2.1】 第54页 3、其他 第55页 【案例4.3.1】 第55页 五、版本控制问题 第58页 1、新老代码同一全局变量不一致 第58页 【案例5.1.1】 第58页 六、可测试性代码问题 第59页 1、调试信息/打印信息的正确性 第59页 【案例6.1.1】 第59页 一、逻辑类代码问题 1、变量/指针在使用前就必须初始化 【案例1.1.1】 C语言最大的特色就是指针。指针的使用具有很强的技巧性和灵活性,但同时也带来了很大的危险性。在XXX的代码有如下一端对指针的灵活使用: ... ... _UC *puc_card_config_tab; ... ... Get_Config_Table(
public class MD5Code { static final int S11 = 7; static final int S12 = 12; static final int S13 = 17; static final int S14 = 22; static final int S21 = 5; static final int S22 = 9; static final int S23 = 14; static final int S24 = 20; static final int S31 = 4; static final int S32 = 11; static final int S33 = 16; static final int S34 = 23; static final int S41 = 6; static final int S42 = 10; static final int S43 = 15; static final int S44 = 21; static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; private long[] state = new long[4];// state (ABCD) private long[] count = new long[2];// number of bits, modulo 2^64 (lsb // first) private byte[] buffer = new byte[64]; // input buffer /* * digestHexStr是MD5的唯一一个公共成员,是最新一次计算结果的 16进制ASCII表示. */ public String digestHexStr; /* * digest,是最新一次计算结果的2进制内部表示,表示128bit的MD5值. */ private byte[] digest = new byte[16]; /* * getMD5ofStr是类MD5最主要的公共方法,入口参数是你想要进行MD5变换的字符串 * 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的. */ public String getMD5ofStr(String inbuf) { md5Init(); md5Update(inbuf.getBytes(), inbuf.length()); md5Final(); digestHexStr = ""; for (int i = 0; i < 16; i++) { digestHexStr += byteHEX(digest[i]); } return digestHexStr; } // 这是MD5这个类的标准构造函数,JavaBean要求有一个public的并且没有参数的构造函数 public MD5Code() { md5Init(); return; } /* md5Init是一个初始化函数,初始化核心变量,装入标准的幻数 */ private void md5Init() { count[0] = 0L; count[1] = 0L; // /* Load magic initialization constants. state[0] = 0x67452301L; state[1] = 0xefcdab89L; state[2] = 0x98badcfeL; state[3] = 0x10325476L; return; } /* * F, G, H ,I 是4个基本的MD5函数,在原始的MD5的C实现,由于它们是 * 简单的位运算,可能出于效率的考虑把它们实现成了宏,在java,我们把它们 实现成了private方法,名字保持了原来C的。 */ private long F(long x, long y, long z) { return (x & y) | ((~x) & z); } private long G(long x, long y, long z) { return (x & z) | (y & (~z)); } private long H(long x, long y, long z) { return x ^ y ^ z; } private long I(long x, long y, long z) { return y ^ (x | (~z)); } /* * FF,GG,HH和II将调用F,G,H,I进行近一步变换 FF, GG, HH, and II transformations for * rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent * recomputation. */ private long FF(long a, long b, long c, long d, long x, long s, long ac) { a += F(b, c, d) + x + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long GG(long a, long b, long c, long d, long x, long s, long ac) { a += G(b, c, d) + x + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long HH(long a, long b, long c, long d, long x, long s, long ac) { a += H(b, c, d) + x + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long II(long a, long b, long c, long d, long x, long s, long ac) { a += I(b, c, d) + x + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } /* * md5Update是MD5的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个 * 函数由getMD5ofStr调用,调用之前需要调用md5init,因此把它设计成private的 */ private void md5Update(byte[] inbuf, int inputLen) { int i, index, partLen; byte[] block = new byte[64]; index = (int) (count[0] >>> 3) & 0x3F; // /* Update number of bits */ if ((count[0] += (inputLen << 3)) < (inputLen << 3)) count[1]++; count[1] += (inputLen >>> 29); partLen = 64 - index; // Transform as many times as possible. if (inputLen >= partLen) { md5Memcpy(buffer, inbuf, index, 0, partLen); md5Transform(buffer); for (i = partLen; i + 63 < inputLen; i += 64) { md5Memcpy(block, inbuf, 0, i, 64); md5Transform(block); } index = 0; } else i = 0; // /* Buffer remaining input */ md5Memcpy(buffer, inbuf, index, i, inputLen - i); } /* * md5Final整理和填写输出结果 */ private void md5Final() { byte[] bits = new byte[8]; int index, padLen; // /* Save number of bits */ Encode(bits, count, 8); // /* Pad out to 56 mod 64. index = (int) (count[0] >>> 3) & 0x3f; padLen = (index < 56) ? (56 - index) : (120 - index); md5Update(PADDING, padLen); // /* Append length (before padding) */ md5Update(bits, 8); // /* Store state in digest */ Encode(digest, state, 16); } /* * md5Memcpy是一个内部使用的byte数组的块拷贝函数,从input的inpos开始把len长度的 * 字节拷贝到output的outpos位置开始 */ private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos, int len) { int i; for (i = 0; i < len; i++) output[outpos + i] = input[inpos + i]; } /* * md5Transform是MD5核心变换程序,有md5Update调用,block是分块的原始字节 */ private void md5Transform(byte block[]) { long a = state[0], b = state[1], c = state[2], d = state[3]; long[] x = new long[16]; Decode(x, block, 64); /* Round 1 */ a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */ d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */ c = FF(c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */ b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */ a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */ d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */ c = FF(c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */ b = FF(b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */ a = FF(a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */ d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */ c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */ b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */ a = FF(a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */ d = FF(d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */ c = FF(c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */ b = FF(b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */ /* Round 2 */ a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */ d = GG(d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */ c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */ b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */ a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */ d = GG(d, a, b, c, x[10], S22, 0x2441453L); /* 22 */ c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */ b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */ a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */ d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */ c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */ b = GG(b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */ a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */ d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */ c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */ b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */ /* Round 3 */ a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */ d = HH(d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */ c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */ b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */ a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */ d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */ c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */ b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */ a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */ d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */ c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */ b = HH(b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */ a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */ d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */ c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */ b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */ /* Round 4 */ a = II(a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */ d = II(d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */ c = II(c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */ b = II(b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */ a = II(a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */ d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */ c = II(c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */ b = II(b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */ a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */ d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */ c = II(c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */ b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */ a = II(a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */ d = II(d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */ c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */ b = II(b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; } /* * Encode把long数组按顺序拆成byte数组,因为java的long类型是64bit的, 只拆低32bit,以适应原始C实现的用途 */ private void Encode(byte[] output, long[] input, int len) { int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (byte) (input[i] & 0xffL); output[j + 1] = (byte) ((input[i] >>> 8) & 0xffL); output[j + 2] = (byte) ((input[i] >>> 16) & 0xffL); output[j + 3] = (byte) ((input[i] >>> 24) & 0xffL); } } /* * Decode把byte数组按顺序合成成long数组,因为java的long类型是64bit的, * 只合成低32bit,高32bit清零,以适应原始C实现的用途 */ private void Decode(long[] output, byte[] input, int len) { int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = b2iu(input[j]) | (b2iu(input[j + 1]) << 8) | (b2iu(input[j + 2]) << 16) | (b2iu(input[j + 3]) << 24); return; } /* * b2iu是我写的一个把byte按照不考虑正负号的原则的"升位"程序,因为java没有unsigned运算 */ public static long b2iu(byte b) { return b < 0 ? b & 0x7F + 128 : b; } /* * byteHEX(),用来把一个byte类型的数转换成十六进制的ASCII表示, * 因为java的byte的toString无法实现这一点,我们又没有C语言的 sprintf(outbuf,"X",ib) */ public static String byteHEX(byte ib) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] ob = new char[2]; ob[0] = Digit[(ib >>> 4) & 0X0F]; ob[1] = Digit[ib & 0X0F]; String s = new String(ob); return s; } }
用变量a给出下面的定义 a) 一个整型数(An integer) b) 一个指向整型数的指针(A pointer to an integer) c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer) d) 一个有10个整型数的数组(An array of 10 integers) e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers) f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer) h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer ) 答案是: a) int a; // An integer b) int *a; // A pointer to an integer c) int **a; // A pointer to a pointer to an integer d) int a[10]; // An array of 10 integers e) int *a[10]; // An array of 10 pointers to integers f) int (*a)[10]; // A pointer to an array of 10 integers g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer 13.下面的数据声明都代表什么? (1)float (**def)[10]; def是一个二级指针,它指向的是一个一维数组的指针,数组的元素都是float. (2)double*(*gh)[10]; gh是一个指针,它指向一个一维数组,数组元素都是double*. (3)double(*f[10])(); f是一个数组,f有10个元素,元素都是函数的指针,指向的函数类型是没有参数且返回double的函数. (4)int *((*b)[10]); 就跟int *(*b)[10]是一样的,b是一维数组的指针. (5)Long (*fun)(int); 函数指针. (6)int (*(*F)(int,int))(int); F是一个函数指针,指向的函数的类型是有两个int参数并且返回一个函数指针的函数,返回的函数指针指向有一个int参数且返回int的函数.  所有的ASCII码都可以用“\”加数字(一般是8进制数字)来表示。而C定义了一些字母前加"\"来表示常见的那些不能显示的ASCII字符,如\0,\t,\n等,就称为转义字符,因为后面的字符,都不是它本来的ASCII字符意思了。   转义字符 意义 ASCII码值(十进制)   \a 响铃(BEL) 007   \b 退格(BS) 008   \f 换页(FF) 012   \n 换行(LF) 010   \r 回车(CR) 013   \t 水平制表(HT) 009   \v 垂直制表(VT) 011   \\ 反斜杠 092   \? 问号字符 063   \' 单引号字符 039   \" 双引号字符 034   \0 空字符(NULL) 000   \ddd 任意字符 三位八进制   \xhh 任意字符 二位十六进制   字符型常量   字符型常量所表示的值是字符型变量所能包含的值。我们可以用ASCII表达式来表示一个字符型常量,或者用单引号内加反斜杠表示转义字符。   'A', '\x2f', '\013';   其:\x表示后面的字符是十六进制数,\0表示后面的字符是八进制数。   注意:在Turbo C 2.0,字符型常量表示数的范围是-128到127,除非你把它声明为unsigned,这样就是0到255。   上面我们见到的\x,\n,\a等等都是叫转义字符,它告诉编译器需要用特殊的方式进行处理。下面给出所有的转义字符和所对应的意义:   转义字符 描述   \' 单引号   \ 双引号   \\ 反斜杠   \0 空字符   \ccc (最多三位)八进制数   \a 声音符   \b 退格符   \f 换页符   \n 换行符   \r 回车符   \t 水平制表符   \v 垂直制表符   \xhh(最多两位)十六进制符 下面的代码输出是什么,为什么? 1、sizeof()和strlen()的使用? 答: 1.从功能定义上,strlen函数,用来求字符串的长度,sizeof函数是用来求指定变量或变量类型等所占用内存的 大小; 2.sizeof是运算符,而strlen是C库函数strlen只能用char*做参数,且以'\0'结尾的; 对于静态数组处理: char str[20]="0123456789"; strlen(str)=10; //表示数组字符串的长度 sizeof(str)=20; //表示数组变量分配的长度 对于指针处理: char *str="0123456789"; strlen(str)=10; //表示字符串的长度 sizeof(str)=4; //表示指针变量的所占内存大小 sizeof(*str)=1; //表示'0'这个字符变量的所占内存大小 2、 struct 和 class的区别? 答: (1)类的成员默认是private的,当是可以声明为public,private 和protected,结构定义的成员默认的都是public. (2)结构不允许定义成员函数,当是类可以定义成员函数. (3)结构不可以存在继承关系,当是类可以存在继承关系. 3、 strcpy(), strcat(), strcmp,strlen(), strchr(), memcpy(), memcmp(), memset()的编写? 4、 内存的分配方式的分配方式有几种? 答: (1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量。 (2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集,效率很高,但是分配的内存容量有限。 (3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。 5,、解释堆和栈的区别? 答: (1)栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构的栈。 (2)堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构的堆是两回事,分配方式倒是类似于链表.(主要有:malloc/free,new/delete) 6,、枚举的用法,以及它与宏的区别? 答: 枚举(enum)作用:定义一组常量,而且这些常量组成了一个集合。当我们将emun参数传递给函数时,如果传递了一个不属于这个集合的参数,编译器报错。 区别: 枚举是类型,而宏没有类型。 枚举将检查其语法,而宏是简单的文本替换。 7、 const的用法,以及声明const变量与宏的区别? 答: const的用法有四种: a): const对象和const类型的对象; b): const指针 和 指向const的指针 及两者结合; c): const 参数修饰 和 参数返回类型的const修饰; d): const类成员 和 const 成员函数; 区别: const常量有数据类型, 而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只能进行字符 替换,没有类型 安全检查。而且字符替换可能会带来料想不到的边界效应。有些集成化工具可以对const常量进行调试, 但不能对宏量进行调试。 8、函数assert的用法? 答:断言assert是仅在debug版本起作用的宏,用于检查“不应该“发生的情况。程序员可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。 9、用预处理指令#define 声明一个常数,用以表明1年有多少秒(忽略闰年问题)? 答: #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 10、 写一个"标准"宏MIN,这个宏输入两个参数并返回较小的一个? 答: #define MIN(A,B) ((A) <= (B) ? (A) : (B)) 11、嵌入式系统经常要用到无限循环,你怎么样用C编写死循环呢? 答: 这个问题用几个解决方案。我首选的方案是: while(1) { } 一些程序员更喜欢如下方案: for(;;) { } 13、关于内存对齐的问题以及sizof()的输出? 答: 编译器自动对齐的原因:为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。 14、 static有什么用途?(请至少说明两种) 答: (1)在函数体,一个被声明为静态的变量在这一函数被调用过程维持其值不变。 (2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 (3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。 15、引用与指针有什么区别? 答: (1) 引用必须被初始化,指针不必。 (2) 引用初始化以后不能被改变,指针可以改变所指的对象。 (3) 不存在指向空值的引用,但是存在指向空值的指针。 16、什么是平衡二叉树? 答: 左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1。 17、堆栈溢出一般是由什么原因导致的? 答: 没有回收垃圾资源。 18、什么是预编译?何时需要预编译? 答: (1)总是使用不经常改动的大型代码体。 (2)程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。 19、队列和栈有什么区别? 答: 队列先进先出;栈后进先出。 20、数组和链表的区别? 答: 数组:数据顺序存储,固定大小; 链表:数据可以随机存储,大小可动态改变; 21、为什么数组名作为参数,会改变数组的内容,而其它类型如int却不会改变变量的值? 答: 当数组名作为参数时,传递的实际上是地址。而其他类型如int作为参数时,由于函数参数值实质上是实参的一份拷贝,被调函数内部对形参的改变并不影响实参的值。 22、数据结构和算法: A:查找: (1)二分法查找; B:写出下列算法的时间复杂度和实现排序: (1)冒泡排序; (2)选择排序; (3)插入排序; (4)快速排序; (5)堆排序; (6)归并排序; 23、编写gbk_strlen函数,计算含有汉字的字符串的长度,汉字作为一个字符处理;已知:汉字编码为双字节,其 参数里涉及指针,就要考虑该指针是不是一个需要修改的量,如果是,则参数应采用指向指针的指针。 (C语言里参数传递都是传值,是一个拷贝,修改指针,只是改变了拷贝的指向,原指针指向并没有改变,而修改指针的内容则是可以的。)如果函数的参数是一个指针,不要指望用该指针去申请动态内存。(即上面所说的修改该指针) 编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,指针参数也不例外。 如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,由于“指向指针的指针”这个概念不容易理解,我们也可以用函数返回值来传递动态内存。 常常有人把return语句用错了。这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡。 c语言里,利用函数的返回值来表明它是否执行成功的做法最常见。 2.如果要在单链表删除或插入一个元素,就必须知道指向删除点或插入点前面那个元素的指针才行。 数组具有随机存取性(可以立即存取任一元素) char *str = "the word" 常量字符串,静态存储区,具有程序生命期。 char *str = (char *)malloc(....); 堆上分配,手动释放,否则内存泄漏。 char str[] = "the word" 栈上分配,函数生命期。 4. '\0'不是指ASCII码值,它是字符,它的ASCII码值是0,也就是ASCII码表的第一个字符。'\0'并非是空格,空格的ASCII码值是32,只不过是输出类似于空格而已。 5. 在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长,指针本身占据了4个字节长度,即用一个字的空间保存一个地址。地址是按字节表示的,一个字节一个地址。地址+1,移动一个字节。 6.从语法上看,你只须把指针声明语句的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。 *p的结果是p所指向的东西 &a的运算结果是一个指针,指针所指向的类型是a的类型,指针所指向的地址嘛,那就是a的地址。 7. 声明了一个数组TYPE array[n],则数组名称array就有了两重含义:第一,它代表整个数组,它的类型是TYPE[n];第二 ,它是一个指针,该指针的类型是TYPE*,该指针指向的内存区就是数组第0号单元,该指针自己占有单独的内存区. 在表达式sizeof(array),数组名array代表数组本身,故这时sizeof函数测出的是整个数组的大小。 sizeof(array+n)测出的是指针类型的大小。 char类型的长度是一个字节,int类型的长度是4个字节,即一个字。 sizeof()得到的值是以字节为单位,所以sizeof(int) = 4 8. char* 相当于string ,char* arr[10]即字符串数组
1 愉快的开始-HELLO WORLD 14 1.1 INCLUDE头文件包含 14 1.2 MAIN函数 14 1.3 注释 14 1.4 {}括号,程序题和代码块 14 1.5 声明 14 1.6 C语言自定义名字的要求 15 1.7 PRINTF函数 15 1.8 RETURN语句 15 1.9 SYSTEM系统调用 15 1.9.1 System返回值在windows和unix下的不同, 15 1.9.2 POSIX 15 1.10 C语言编译过程,GCC参数简介 16 1.10.1 C语言编译过程 16 1.10.2 -E预编译 16 1.10.3 -S汇编 16 1.10.4 -c编译 16 1.10.5 链接 16 1.11 操作系统结构 17 1.11.1 用户模式 17 1.11.2 内核模式 17 1.12 64位,32位系统区别 18 1.12.1 CPU内部结构与寄存器 18 1.12.2 RISC与CISC CPU构架 18 1.12.3 SPARC,x86与ARM 18 1.13 汇编语言 18 1.13.1 I386汇编简介 18 1.13.2 VS反汇编 19 1.14 IDE工具 19 1.14.1 QT常用快捷键 19 1.14.2 VS常用快捷键 19 1.14.3 VS断点,调试 19 2 C语言数据类型 19 2.1 常量 19 2.1.1 #define 19 2.1.2 const 19 2.2 字符串常量 20 2.3 二进制数、位、字节与字 20 2.4 八进制 20 2.5 十六进制 20 2.6 原码 21 2.7 反码 21 2.8 补码 21 2.9 SIZEOF关键字 22 2.10 INT类型 22 2.10.1 int常量,变量 22 2.10.2 printf输出int值 23 2.10.3 printf输出八进制和十六进制 23 2.10.4 short,long,long long,unsigned int 23 2.10.5 整数溢出 23 2.10.6 大端对齐与小端对齐 23 2.11 CHAR类型 24 2.11.1 char常量,变量 24 2.11.2 printf输出char 24 2.11.3 不可打印char转义符 24 2.11.4 char和unsigned char 25 2.12 浮点FLOAT,DOUBLE,LONG DOUBLE类型 25 2.12.1 浮点常量,变量 25 2.12.2 printf输出浮点数 25 2.13 类型限定 25 2.13.1 const 25 2.13.2 volatile 26 2.13.3 register 26 3 字符串格式化输出和输入 26 3.1 字符串在计算机内部的存储方式 26 3.2 PRINTF函数,PUTCHAR函数 27 3.3 SCANF函数与GETCHAR函数 28 4 运算符表达式和语句 29 4.1 基本运算符 29 4.1.1 = 29 4.1.2 + 29 4.1.3 – 29 4.1.4 * 29 4.1.5 / 29 4.1.6 % 29 4.1.7 += 29 4.1.8 -= 29 4.1.9 *= 29 4.1.10 /= 30 4.1.11 %= 30 4.1.12 ++ 30 4.1.13 -- 30 4.1.14 逗号运算符 30 4.1.15 运算符优先级 30 4.2 复合语句 31 4.3 空语句 31 4.4 类型转化 31 5 条件分支语句 31 5.1 关系运算符 31 5.1.1 < 31 5.1.2 <= 31 5.1.3 > 32 5.1.4 >= 32 5.1.5 == 32 5.1.6 != 32 5.2 关系运算符优先级 32 5.3 逻辑运算符 32 5.3.1 && 32 5.3.2 || 32 5.3.3 ! 33 5.4 IF 33 5.5 IF ELSE 34 5.6 IF ELSE IF 34 5.7 SWITCH与BREAK,DEFAULT 35 5.8 条件运算符? 36 5.9 GOTO语句与标号 36 6 循环语句 36 6.1 WHILE 36 6.2 CONTINUE 37 6.3 BREAK 37 6.4 DO WHILE 37 6.5 FOR 37 6.6 循环嵌套 37 7 数组 38 7.1 一维数组定义与使用 38 7.2 数组在内存的存储方式 38 7.3 一维数组初始化 38 7.4 二维数组定义与使用 39 7.5 二维数组初始化 39 8 字符串与字符数组 39 8.1 字符数组定义 39 8.2 字符数组初始化 39 8.3 字符数组使用 40 8.4 随机数产生函数RAND与SRAND 40 8.5 用SCANF输入字符串 40 8.6 字符串的结束标志 41 8.7 字符串处理函数 41 8.7.1 gets 41 8.7.2 fgets函数 41 8.7.3 puts函数 42 8.7.4 fputs函数 42 8.7.5 strlen,字符串长度 42 8.7.6 strcat,字符串追加 42 8.7.7 strncat,字符串有限追加 43 8.7.8 strcmp,字符串比较 43 8.7.9 strncmp,字符串有限比较 43 8.7.10 strcpy字符串拷贝 43 8.7.11 strncpy字符串有限拷贝 43 8.7.12 sprintf,格式化字符串 43 8.7.13 Sscanf函数 44 8.7.14 strchr查找字符 44 8.7.15 strstr查找子串 44 8.7.16 strtok分割字符串 44 8.7.17 atoi转化为int 45 8.7.18 atof转化为float 45 8.7.19 atol转化为long 45 9 函数 45 9.1 函数的原型和调用 45 9.2 函数的形参与实参 45 9.3 函数的返回类型与返回值 46 9.4 MAIN函数与EXIT函数函数的RETURN语句 46 9.5 多个源代码文件程序的编译 47 9.5.1 头文件的使用 47 9.5.2 #include与#define的意义 47 9.5.3 #ifndef与#endif 47 9.6 函数的递归 48 9.6.1 递归的过程分析 48 9.6.2 递归的优点 52 9.6.3 递归的缺点 52 1 指针 52 1.1 指针 52 1.1.1 指针的概念 52 1.1.2 指针变量的定义 52 1.1.3 &取地址运算符 52 1.1.4 无类型指针 52 1.1.5 NULL 53 1.1.6 空指针与野指针 53 1.1.7 指针的兼容性 53 1.1.8 指向常量的指针与指针常量 54 1.1.9 指针与数组的关系 54 1.1.10 指针运算 54 1.1.11 通过指针使用数组元素 55 1.1.12 指针数组 55 1.1.13 指向指针的指针(二级指针) 55 1.1.14 指向二维数组的指针 57 1.1.15 指针变量做为函数的参数 57 1.1.16 一维数组名作为函数参数 57 1.1.17 二维数组名作为函数参数 58 1.1.18 const关键字保护数组内容 58 1.1.19 指针做为函数的返回值 58 1.1.20 指向函数的指针 59 1.1.21 把指向函数的指针做为函数的参数 60 1.1.22 memset,memcpy,memmove函数 61 1.1.23 指针小结 63 2 字符指针与字符串 64 2.1 指针和字符串 64 2.2 通过指针访问字符串数组 64 2.3 函数的参数为CHAR * 64 2.4 指针数组做为MAIN函数的形参 65 3 内存管理 65 3.1 作用域 65 3.1.1 auto自动变量 65 3.1.2 register寄存器变量 65 3.1.3 代码块作用域的静态变量 66 3.1.4 代码块作用域外的静态变量 66 3.1.5 全局变量 66 3.1.6 外部变量与extern关键字 66 3.1.7 全局函数和静态函数 66 3.2 内存四区 66 3.2.1 代码区 67 3.2.2 静态区 67 3.2.3 栈区 67 3.2.4 栈溢出 68 3.2.5 堆区 68 3.3 堆的分配和释放 70 3.3.1 malloc 70 3.3.2 free 70 3.3.3 calloc: 70 3.3.4 realloc 71 4 结构体,联合体,枚举与TYPEDEF 71 4.1 结构体 71 4.1.1 定义结构体struct和初始化 71 4.1.2 访问结构体成员 71 4.1.3 结构体的内存对齐模式 72 4.1.4 指定结构体元素的位字段 72 4.1.5 结构数组 72 4.1.6 嵌套结构 73 4.1.7 结构体的赋值 73 4.1.8 指向结构体的指针 73 4.1.9 指向结构体数组的指针 73 4.1.10 结构的数组成员和指针成员 73 4.1.11 在堆创建的结构体 74 4.1.12 将结构作为函数参数 74 4.1.13 结构,还是指向结构的指针 74 4.2 联合体 75 4.3 枚举类型 75 4.3.1 枚举定义 75 4.3.2 默认值 76 4.4 TYPEDEF 76 4.5 通过TYPEDEF定义函数指针 76 5 文件操作 77 5.1 FOPEN 77 5.2 二进制和文本模式的区别 77 5.3 FCLOSE 78 5.4 GETC和PUTC函数 78 5.5 EOF与FEOF函数文件结尾 78 5.6 FPRINTF,FSCANF,FGETS,FPUTS函数 78 5.7 STAT函数 78 5.8 FREAD和FWRITE函数 79 5.9 FREAD与FEOF 79 5.10 通过FWRITE将结构保存到二进制文件 79 5.11 FSEEK函数 80 5.12 FTELL函数 80 5.13 FFLUSH函数 80 5.14 REMOVE函数 81 5.15 RENAME函数 81 6 基础数据结构与算法 82 6.1 什么是数据结构 82 6.2 什么是算法 82 6.3 排序 83 6.3.1 冒泡排序 83 6.3.2 选择排序 83 6.4 查找 83 6.4.1 顺序查找 83 6.4.2 二分查找 83 6.5 链表 84 6.5.1 单向链表定义 84 6.5.2 单向链表数据结构定义 85 6.5.3 单向链表的实现 85
目 录 第1章 C语言 8 1.1 什么是局部程序块(local block)? 8 1.2 可以把变量保存在局部程序块吗? 9 1.3 什么时候用一条switch语句比用多条if语句更好? 9 1.4 switch语句必须包含default分支吗? 10 1.5 switch语句的最后一个分支可以不要break语句吗? 11 1.6 除了在for语句之外,在哪些情况下还要使用逗号运算符? 11 1.7 怎样才能知道循环是否提前结束了? 13 1.8 goto,longjmp()和setjmp()之间有什么区别? 13 1.9 什么是左值(lvaule)? 15 1.10 数组(array)可以是左值吗? 15 1.11 什么是右值(rvaule)? 16 1.12 运算符的优先级总能保证是“自左至右”或“自右至左”的顺序吗? 17 1.13 ++var和var++有什么区别? 17 1.14 取模运算符(modulus operator)“%”的作用是什么? 17 第2章 变量和数据存储 18 2.1. 变量存储在内存(memory)的什么地方? 18 2.2. 变量必须初始化吗? 19 2.3. 什么是页抖动(pagethrashing)? 19 2.4. 什么是const指针? 20 2.5. 什么时候应该使用register修饰符?它真的有用吗? 21 2.6. 什么时候应该使用volatile修饰符? 21 2.7. 一个变量可以同时被说明为const和volatile吗? 22 2.8. 什么时候应该使用const修饰符? 23 2.9. 浮点数比较(floating-point comparisons)的可靠性如何? 23 2.10. 怎样判断一个数字型变量可以容纳的最大值? 24 2.11. 对不同类型的变量进行算术运算会有问题吗? 25 2.12. 什么是运算符升级(operatorpromotion)? 25 2.13. 什么时候应该使用类型强制转换(typecast)? 26 2.14. 什么时候不应该使用类型强制转换(typecast)? 27 2.15. 可以在头文件说明或定义变量吗? 27 2.16. 说明一个变量和定义一个变量有什么区别? 27 2.17. 可以在头文件说明static变量吗? 28 2.18. 用const说明常量有什么好处? 28 第3章 排序与查找 28 排序 28 查找 29 排序或查找性能? 30 3.1. 哪一种排序方法最方便? 32 3.2. 哪一种排序方法最快? 33 3.3. 对外存(磁盘或磁带)而不是内存数据进行排序称为外部排序。 39 3.4. 1哪一种查找方法最方便? 44 3.5. 1哪一种查找方法最快? 46 3.6. 1什么是哈希查找? 51 3.7. 1怎样对链表进行排序? 53 3.8. 1怎样查找链表数据? 53 第4章 数据文件 59 4.1. 当errno为一个非零值时,是否有错误发生? 59 4.2. 什么是流(stream)? 59 4.3. 怎样重定向一个标准流? 60 4.4. 怎样恢复一个重定向了的标准流? 60 4.5. stdout能被强制打印到非屏幕设备上吗? 61 4.6. 文本模式(textmode)和二进制模式(binarymode)有什么区别? 61 4.7. 怎样判断是使用函数还是使用低级函数? 62 4.8. 怎样列出某个目录下的文件? 62 4.9. 怎样列出一个文件的日期和时间? 63 4.10. 怎样对某个目录下的文件名进行排序? 66 4.11. 怎样判断一个文件的属性? 67 4.12. 怎样查看PATH环境变量? 69 4.13. 怎样打开一个同时能被其它程序修改的文件? 69 4.14. 怎样确保只有你的程序能存取一个文件? 71 4.15. 怎样防止其它程序修改你正在修改的那部分文件内容? 71 4.16. 怎样一次打开20个以上的文件? 72 4.17. 怎样避开"Abort,Retry,Fail”消息? 72 4.18. 怎样读写以逗号分界的本? 74 第5章 编译预处理 76 5.1. 什么是宏(macro)?怎样使用宏? 76 5.2. 预处理程序(preprocessor)有什么作用? 77 5.3. 怎样避免多次包含同一个头文件? 79 5.4. 可以用#include指令包含类型名不是".h"的文件吗? 80 5.5. 用#define指令说明常量有什么好处? 80 5.6. 用enum关键字说明常量有什么好处? 81 5.7. 与用#define指令说明常量相比,用enum关键字说明常量有什么好处? 81 5.8. 如何使部分程序在

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值