C-02\规范及随机数rand()原理
小知识点
assert()函数
assert 断言函数,用于在调试过程中捕捉程序的错误。对某种假设条件进行检测,如果条件成立就不进行任何操作,如果条件不成立就捕捉到这种错误,并打印出错误信息,终止程序执行。在发行版本是不会执行的
win32管理单元
- 大小:4字节
- 也就是说一个
char也会占用4字节
选字体原则
能区分0Oo1liB8
gets()函数
gets()由于没有提供限制输入字符串长度的方法,极容易造成内存溢出,导致安全隐患,建议不用
取整问题
C语言规定,除法运算为向零取整(即3.5向零取整为3,-3.5向零取整为-3)
printf("%d",10 % 3); // 1
printf("%d",10 % -3); // 1
printf("%d",-10 % 3); // -1
printf("%d",-10 % -3); // -1
对应数学原理为
\[a/b = q,r <==> r=a-qb
\]
命令行显示不全问题
今天在测试一个10000!(10000的阶乘)的时候,用控制台显示输出内容时,由于内容行数过大,虽然已经翻页了,但仍然看不到最前面的内容。
解决办法
单击命令行窗口上边框->属性->布局,然后适当增大屏幕缓冲区高度大小即可。
各系统的栈地址
xp 0x0012XXXX
win7 0x0018XXXX
win10 0x0019XXXX
变量约定
| 变量类型 | 命名表示 | 自选 |
|---|---|---|
| int | n或i | n |
| float | f或flt | flt |
| double | d或dbl | dbl |
| char | c或by | c |
| short int | w或h | h |
| char * | psz或pstr(psz表示‘\0'结尾的字符串,结尾不确定是不是’\0'的使用pstr) |
根据情况使用 |
char sz[SIZE] |
sz或str(sz表示‘\0'结尾的字符串,结尾不确定是不是’\0'的使用str) |
根据情况使用 |
快速完成编译与链接的批处理脚本
del *.exe //删除所在目录下所有exe文件
del *.obj //删除所在目录下所有obj文件
cl /c /W3 /WX /Od hello.c //编译hello.c文件,只编译不链接,采用3级警告并将警告视为错误,禁用优化 成功执行这步就会生成hello.obj文件
link hello.obj //链接hello.obj与所需库文件和其他目标程序,成功执行后就会生成hello.exe可执行文件
pause //暂停窗口等待进一步的操作
hello.exe //运行hello.exe文件
小端(大端)存储
小端:高地址存高位,低地址存低位(较高的有效字节存储在较高的存储器地址,较低的有效字节存储在较低的存储器地址)
大端:高地址存低位,低地址存高位(较高的有效字节存储在较低的存储器地址,较低的有效字节存储在较高的存储器地址)
代码规范(赋初值)
- 初始化变量时需赋值,赋值为零或对应的错误值/无效值
- 如果不赋初值,则变量的值为之前程序留下的残留数据,可能会导致程序时不时出现莫名的问题
- 以下列举了一些常用类型的初值
| 变量 | 初值 |
|---|---|
| int n | 0 |
| float flt | 0.0f |
| double dbl | 0.0 |
| char c | '\0' |
| int *p | NULL |
简单正则表达式
char szBuf[16] = {0};
scanf("%[0-9]15s",szBuf); // 只接受限制的字符,遇到其余字符会直接截断
| 表达式 | 作用 |
|---|---|
| [0-9] | 只接收0-9 |
| [0,9] | 只接收0或9两个数字 |
| [^0] | 除了0都能接收 |
随机数rand()函数
-
实现文件:
rand.c -
算法:
-
单线程:
(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff)holdrand为静态全局变量,只会被初始化一次,初始化值为1L -
多线程:
( ((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) >> 16) & 0x7fff )多线程实际和单线程算法是一样的,只是
holdrand不是全局变量,而是存储在每个线程独享的(_tiddata)结构体中,该数据在线程创建时被赋值为1L
-
-
缺点:
- 由于每次重新运行程序,随机种子都被赋值为
1L,所以多次运行程序的结果都是一样的
- 由于每次重新运行程序,随机种子都被赋值为
srand()函数
- 实现文件:
rand.c - 功能:
- 单线程:将静态全局变量
holdrand的值设置为函数参数值 - 多线程:将当前线程的
_holdrand的值设置为函数参数值
- 单线程:将静态全局变量
- 配合
time(NULL)就能生成不同的随机种子,在调用rand()函数之前,调用该函数就能设置随机种子,该函数一个线程只需调用一次即可
/***
*rand.c - random number generator
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* defines rand(), srand() - random number generator
*
*******************************************************************************/
#include <cruntime.h>
#include <mtdll.h>
#include <stddef.h>
#include <stdlib.h>
#ifndef _MT
static long holdrand = 1L;
#endif /* _MT */
/***
*void srand(seed) - seed the random number generator
*
*Purpose:
* Seeds the random number generator with the int given. Adapted from the
* BASIC random number generator.
*
*Entry:
* unsigned seed - seed to seed rand # generator with
*
*Exit:
* None.
*
*Exceptions:
*
*******************************************************************************/
void __cdecl srand (
unsigned int seed
)
{
#ifdef _MT
_getptd()->_holdrand = (unsigned long)seed;
#else /* _MT */
holdrand = (long)seed;
#endif /* _MT */
}
/***
*int rand() - returns a random number
*
*Purpose:
* returns a pseudo-random number 0 through 32767.
*
*Entry:
* None.
*
*Exit:
* Returns a pseudo-random number 0 through 32767.
*
*Exceptions:
*
*******************************************************************************/
int __cdecl rand (
void
)
{
#ifdef _MT
_ptiddata ptd = _getptd();
// 每一个线程创建的时候,其 _holdrand 的值都被赋值为1L
return( ((ptd->_holdrand = ptd->_holdrand * 214013L
+ 2531011L) >> 16) & 0x7fff );
#else /* _MT */
return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
#endif /* _MT */
}
_tiddata结构体
- 定义的文件:
mtdll.h - 存储着线程数据(每个线程独享),其中
_holdrand成员为随机种子
/* Structure for each thread's data */
struct _tiddata {
unsigned long _tid; /* thread ID */
unsigned long _thandle; /* thread handle */
int _terrno; /* errno value */
unsigned long _tdoserrno; /* _doserrno value */
unsigned int _fpds; /* Floating Point data segment */
unsigned long _holdrand; /* rand() seed value */
char * _token; /* ptr to strtok() token */
#ifdef _WIN32
wchar_t * _wtoken; /* ptr to wcstok() token */
#endif /* _WIN32 */
unsigned char * _mtoken; /* ptr to _mbstok() token */
/* following pointers get malloc'd at runtime */
char * _errmsg; /* ptr to strerror()/_strerror() buff */
char * _namebuf0; /* ptr to tmpnam() buffer */
#ifdef _WIN32
wchar_t * _wnamebuf0; /* ptr to _wtmpnam() buffer */
#endif /* _WIN32 */
char * _namebuf1; /* ptr to tmpfile() buffer */
#ifdef _WIN32
wchar_t * _wnamebuf1; /* ptr to _wtmpfile() buffer */
#endif /* _WIN32 */
char * _asctimebuf; /* ptr to asctime() buffer */
#ifdef _WIN32
wchar_t * _wasctimebuf; /* ptr to _wasctime() buffer */
#endif /* _WIN32 */
void * _gmtimebuf; /* ptr to gmtime() structure */
char * _cvtbuf; /* ptr to ecvt()/fcvt buffer */
/* following fields are needed by _beginthread code */
void * _initaddr; /* initial user thread address */
void * _initarg; /* initial user thread argument */
/* following three fields are needed to support signal handling and
* runtime errors */
void * _pxcptacttab; /* ptr to exception-action table */
void * _tpxcptinfoptrs; /* ptr to exception info pointers */
int _tfpecode; /* float point exception code */
/* following field is needed by NLG routines */
unsigned long _NLG_dwCode;
/*
* Per-Thread data needed by C++ Exception Handling
*/
void * _terminate; /* terminate() routine */
void * _unexpected; /* unexpected() routine */
void * _translator; /* S.E. translator */
void * _curexception; /* current exception */
void * _curcontext; /* current exception context */
#if defined (_M_MRX000)
void * _pFrameInfoChain;
void * _pUnwindContext;
void * _pExitContext;
int _MipsPtdDelta;
int _MipsPtdEpsilon;
#elif defined (_M_PPC)
void * _pExitContext;
void * _pUnwindContext;
void * _pFrameInfoChain;
int _FrameInfo[6];
#endif /* defined (_M_PPC) */
};
typedef struct _tiddata * _ptiddata;
每个线程的随机种子赋值
- 实现文件:
tidtable.c
/***
*void _initptd(_ptiddata ptd) - initialize a per-thread data structure
*
*Purpose:
* This routine handles all of the per-thread initialization
* which is common to _beginthread, _beginthreadex, _mtinit
* and _getptd.
*
*Entry:
* pointer to a per-thread data block
*
*Exit:
* the common fields in that block are initialized
*
*Exceptions:
*
*******************************************************************************/
// 线程的初始化函数
void __cdecl _initptd (
_ptiddata ptd
)
{
ptd->_pxcptacttab = (void *)_XcptActTab;
ptd->_holdrand = 1L; // 每个线程的随机化种子
#ifdef _M_MRX000
/*
* MIPS per-thread data
*/
ptd->_MipsPtdDelta =
ptd->_MipsPtdEpsilon = -1L ;
#endif /* _M_MRX000 */
}
浙公网安备 33010602011771号