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 * pszpstr(psz表示‘\0'结尾的字符串,结尾不确定是不是’\0'的使用pstr) 根据情况使用
char sz[SIZE] szstr(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 */
}
posted @ 2022-02-10 20:35  逸聆君  阅读(197)  评论(0)    收藏  举报