| Profilo di 七夜Fly With The WindFotoBlogElenchi | Guida |
|
|
29 aprile CString与int、char*、char[100]之间的转换CString互转int 将字符转换为整数,可以使用atoi、_atoi64或atol。 而将数字转换为CString变量,可以使用CString的Format函数。如 CString s; int i = 64; s.Format("%d", i) Format函数的功能很强,值得你研究一下。 void CStrDlg::OnButton1() { // TODO: Add your control notification handler code here CString ss="1212.12"; int temp=atoi(ss); CString aa; aa.Format("%d",temp); AfxMessageBox("var is " + aa); } sart.Format("%s",buf); CString互转char* ///char * TO cstring CString strtest; char * charpoint; charpoint="give string a value"; strtest=charpoint; ///cstring TO char * charpoint=strtest.GetBuffer(strtest.GetLength()); 标准C里没有string,char *==char []==string 可以用CString.Format("%s",char *)这个方法来将char *转成CString。要把CString转成char *,用操作符(LPCSTR)CString就可以了。 CString转换 char[100] char a[100]; CString str("aaaaaa"); strncpy(a,(LPCTSTR)str,sizeof(a)); 27 aprile 1030[Phone Home]编程总结数据结构没想清楚,没有清晰的思路的时候就开始编.导致最后调了好长时间.
中间逻辑思维不严密,很多情况没考虑清楚,最后一点点的加很费事.
变量用过之后得恢复初试值,忘记了,出现了一处错误,查了半天才找到.
慢慢学习吧,努力中ing!(貌似很努力,哈哈) 11 marzo const传奇const传奇
xlander译 --------------------------------------------------------------------------------
简介 当我自己写程序需要用到const的时候,或者是读别人的代码碰到const的时候,我常常会停下来想一会儿。许多程序员从来不用const,理由是即使没用const他们也这么过来了。本文仅对const的用法稍作探讨,希望能够对提高软件的源代码质量有所帮助。 常变量 变量用const修饰,其值不得被改变。任何改变此变量的代码都会产生编译错误。Const加在数据类型前后均可。
例如:
void main(void)
{
const int i = 10; //i,j都用作常变量
int const j = 20;
i = 15; //错误,常变量不能改变
j = 25; //错误,常变量不能改变
}
常指针 Const跟指针一起使用的时候有两种方法。
const可用来限制指针不可变。也就是说指针指向的内存地址不可变,但可以随意改变该地址指向的内存的内容。 int main(void)
{
int i = 10;
int *const j = &i; //常指针, 指向int型变量
(*j)++; //可以改变变量的内容
j++; //错误,不能改变常指针指向的内存地址
}
const也可用来限制指针指向的内存不可变,但指针指向的内存地址可变。 int main(void)
{
int i = 20;
const int *j = &i; //指针,指向int型常量
//也可以写成int const *j = &i;
j++; //指针指向的内存地址可变
(*j)++; //错误,不能改变内存内容
}
看完上面的两个例子,是不是糊涂了?告诉你一个诀窍,在第一个例子中,const用来修饰指针j,j不可变(也就是指向int变量的常指针);第二个例子中,const用来修饰*j,*j不可变(也就是指向int常量的指针)。
这两种方式可以组合起来使用,使指针和内存内容都不可变。 int main(void)
{
int i = 10;
const int *const j = &i; //指向int常量的常指针
j++; //错误,不能改变指针指向的地址
(*j)++; //错误,不能改变常量的值
}
Const和引用 引用实际上就是变量的别名,这里有几条规则:
声明变量时必须初始化
一经初始化,引用不能在指向其它变量。
任何对引用的改变都将改变原变量。
引用和变量本身指向同一内存地址。
下面的例子演示了以上的规则: void main(void)
{
int i = 10; //i和j是int型变量
int j = 20;
int &r = i; //r 是变量i的引用
int &s; //错误,声明引用时必须初始化
i = 15; //i 和 r 都等于15
i++; //i 和 r都等于16
r = 18; //i 和r 都等于18
printf("Address of i=%u, Address of r=%u",&i,&r); //内存地址相同
r = j; //i 和 r都等于20,但r不是j的引用
r++; //i 和 r 都等于21, j 仍等于20
}
用const修饰引用,使应用不可修改,但这并不耽误引用反映任何对变量的修改。Const加在数据类型前后均可。 例如:
void main(void)
{
int i = 10;
int j = 100;
const int &r = i;
int const &s = j;
r = 20; //错,不能改变内容
s = 50; //错,不能改变内容
i = 15; // i和r 都等于15
j = 25; // j和s 都等于25
}
Const和成员函数 声明成员函数时,末尾加const修饰,表示在成员函数内不得改变该对象的任何数据。这种模式常被用来表示对象数据只读的访问模式。例如:
class MyClass
{
char *str ="Hello, World";
MyClass()
{
//void constructor
}
~MyClass() {
//destructor
}
char ValueAt(int pos) const //const method is an accessor method {
if(pos >= 12)
return 0;
*str = 'M'; //错误,不得修改该对象
return str[pos]; //return the value at position pos
}
}
Const和重载 重载函数的时候也可以使用const,考虑下面的代码:
class MyClass
{
char *str ="Hello, World";
MyClass()
{
//void constructor
}
~MyClass() {
//destructor
}
char ValueAt(int pos) const //const method is an accessor method {
if(pos >= 12)
return 0;
return str[pos]; //return the value at position pos
}
char& ValueAt(int pos) //通过返回引用设置内存内容 {
if(pos >= 12)
return NULL;
return str[pos];
}
}
在上面的例子中,ValueAt是被重载的。Const实际上是函数参数的一部分,在第一个成员函数中它限制这个函数不能改变对象的数据,而第二个则没有。这个例子只是用来说明const可以用来重载函数,没有什么实用意义。 实际上我们需要一个新版本的GetValue。如果GetValue被用在operator=的右边,它就会充当一个变量;如果GetValue被用作一元操作符,那么返回的引用可以被修改。这种用法常用来重载操作符。String类的operator[]是个很好的例子。(这一段译得很烂,原文如下:In reality due to the beauty of references just the second definition of GetValue is actually required. If the GetValue method is used on the the right side of an = operator then it will act as an accessor, while if it is used as an l-value (left hand side value) then the returned reference will be modified and the method will be used as setter. This is frequently done when overloading operators. The [] operator in String classes is a good example.) class MyClass {
char *str ="Hello, World";
MyClass()
{
//void constructor
}
~MyClass() {
//destructor
}
char& operator[](int pos) //通过返回引用可用来更改内存内容 {
if(pos >= 12)
return NULL;
return str[pos];
}
}
void main(void) {
MyClass m;
char ch = m[0]; //ch 等于 'H'
m[0] = 'M'; //m的成员str变成:Mello, World
}
Const的担心 C/C++中,数据传递给函数的方式默认的是值传递,也就是说当参数传递给函数时会产生一个该参数的拷贝,这样该函数内任何对该参数的改变都不会扩展到此函数以外。每次调用该函数都会产生一个拷贝,效率不高,尤其是函数调用的次数很高的时候。
例如:
class MyClass {
public:
int x;
char ValueAt(int pos) const //const method is an accessor method
{
if(pos >= 12)
return 0;
return str[pos]; //return the value at position pos
}
MyClass()
{
//void constructor
}
~MyClass()
{
//destructor
}
MyFunc(int y) //值传递
{
y = 20;
x = y; //x 和 y 都等于 20.
}
}
void main(void) {
MyClass m;
int z = 10;
m.MyFunc(z);
printf("z=%d, MyClass.x=%d",z,m.x); //z 不变, x 等于20.
}
通过上面的例子可以看出,z没有发生变化,因为MyFunc()操作的是z的拷贝。为了提高效率,我们可以在传递参数的时候,不采用值传递的方式,而采用引用传递。这样传递给函数的是该参数的引用,而不再是该参数的拷贝。然而问题是如果在函数内部改变了参数,这种改变会扩展到函数的外部,有可能会导致错误。在参数前加const修饰保证该参数在函数内部不会被改变。 class MyClass
{
public:
int x;
MyClass()
{
//void constructor
}
~MyClass()
{
//destructor
}
int MyFunc(const int& y) //引用传递, 没有任何拷贝
{
y =20; //错误,不能修改常变量
x = y
}
}
void main(void) {
MyClass m;
int z = 10;
m.MyFunc(z);
printf("z=%d, MyClass.x=%d",z,m.x); //z不变, x等于10.
}
如此,const通过这种简单安全机制使你写不出那种说不定是什么时候就会掉过头来咬你一口的代码。你应该尽可能的使用const引用,通过声明你的函数参数为常变量(任何可能的地方)或者定义那种const method,你就可以非常有效确立这样一种概念:本成员函数不会改变任何函数参数,或者不会改变任何该对象的数据。别的程序员在使用你提供的成员函数的时候,不会担心他们的数据被改得一塌糊涂。 右左法则----复杂指针解析右左法则----复杂指针解析
C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文原文是这样说的: The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.
这段英文的翻译如下: 右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。
现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:
int (*func)(int *p);
首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是int。
int (*func)(int *p, int (*f)(int*));
func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int *和int (*)(int*)这样的形参,返回值为int类型。再来看一看func的形参int (*f)(int*),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。
int (*func[5])(int *p);
func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个*,说明func的元素是指针,要注意这里的*不是修饰func的,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合,因此*修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。
int (*(*func)[5])(int *p); func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。
int (*(*func)(int *p))[5];
func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。
要注意有些复杂指针声明是非法的,例如:
int func(void) [5];
func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。
int func[5](void);
func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。
实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性,例如对于声明:
int (*(*func)(int *p))[5];
可以这样分解:
typedef int (*PARA)[5];
typedef PARA (*func)(int *); 这样就容易看得多了。 c++清屏命令#include <process.h>
system("cls") 一段有意思的代码#include <iostream.h>
int *p = NULL;
int *fFun(void)
{ int i = 0; return &i; } void subFun(void)
{ (*p)--; } void gFun(void)
{ int j; for(j = 0;j<10;j++)
{ subFun(); cout<<j; } } int main(void)
{ p = fFun(); gFun(); return 0; } 上网看见了有一个有意思的代码.据说是一个公司的面试题目,很有意思
程序运行结果是死循环输出-1
分析一下这个程序
fFun()返回一个指针给P,P指向原来i的地址,i在函数调用的时候压栈,调用完了i出栈
但是这个地址被给了P,然后调用gFun,在gFun里j压栈,占了原来i的内存地址
这是P就指向了j,然后 (*p)--,j++,程序进入死循环.... 25 febbraio I/O流控制符1)浮点显示控制
a)setprecision(n) :控制输出显示浮点数的数字个数(默认6) b)setprecision(n)+setiosflags(ios::fixed):控制定点输出表示小数位数 c)setprecision(n)+setionsflags(ios::scientific):控制指数形式输出时小数位数 2)设置输出宽度setw(n) 3)设置输出形式八进制和十六进制 dec(十) 、oct(八)、hex(十六) 4)设置填充字符 setfill(‘')+setw(n) 5)设置对齐方式 setiosflags(ios::left) (默认) setiosflags(ios::right) 6)设置强制显示小数和符号 setiosflags(ios::showpoint) setiosflags(ios::showpos) 28 dicembre 8086/8088 BIOS 中断
26 dicembre 剖析浮点数的存储形式众所周知,浮点数(float)在计算机中占4个byte即32bit,这32bit是如何表示一个浮点数的那?经过查资料,我们得知,浮点数是按照如下格式进行存储的: 例如:0.5的二进制形式是0.1 它用浮点数的形式写出来是如下格式 0 01111110 00000000000000000000000 符号位 阶码 小数位 正数符号位为0,负数符号位为1 阶码是以2为底的指数 小数位表示小数点后面的数字
下面我们来分析一下0.5是如何写成0 01111110 00000000000000000000000
首先0.5是正数所以符号位为0 再来看阶码部分,0.5的二进制数是0.1,而0.1是1.0*2^(-1),所以我们总结出来: 要把二进制数变成(1.f)*2^(exponent)的形式,其中exponent是指数 而由于阶码有正负之分所以阶码=127+exponent; 即阶码=127+(-1)=126 即 01111110 余下的小数位为二进制小数点后面的数字,即00000000000000000000000
由以上分析得0.5的浮点数存储形式为0 01111110 00000000000000000000000
现在我们明白了一个数是如何表示成浮点数形式,下面我们来编一个c++程序来验证它. C++代码如下:
#include <iostream.h> void main() { float f; int a[4][8];
cin>>f; unsigned char b[4]; for(int i=0;i<4;i++) { b[i]=*((char *)&f+i); } for(i=0;i<4;i++) { int temp=b[i]; for(int j=0;j<8;j++) { a[i][j]=temp%2; temp/=2; } } cout<<a[3][7]<<" "; for(i=6;i>=0;i--) { cout<<a[3][i]; } cout<<a[2][7]<<" "; for(i=6;i>=0;i--) { cout<<a[2][i]; } for(i=1;i>=0;i--) { for(int j=7;j>=0;j--) { cout<<a[i][j]; } } cout<<endl; }
俄罗斯方块汇编源代码; Tetris DATA SEGMENT STACK SEGMENT STACK CODE SEGMENT EXIT: ;SET GRAPHICS INT1C PROC DELAY PROC NEAR CALL CHECK RIGHT PROC NEAR MOV BH,00H SKIP6: RET LEFT PROC NEAR MOV BH,00H SKIP8: RET DOWN PROC NEAR PUT PROC NEAR INC SCORE[4] MOV SI,OFFSET BOARD MOV DL,0AH MOV CL,03H DISPSCORE PROC NEAR DISPNEXT PROC NEAR CLD COPY21 PROC NEAR COPY12 PROC NEAR BEGIN PROC NEAR MOV CX,08 CALL COPY21 CHECK PROC NEAR ;RETURN AL=0/F 0:OK F:NO DISPPAD PROC NEAR ;BX BH=PAGE BL=COLOR DISPCELL PROC NEAR ;DH=ROW DL=COL BH=PAGE BL=COLOR SUB DI,2 MOV AX,0C07H RANDOM PROC NEAR INITGAME PROC NEAR MOV CX,20 MOV CX,20 CODE ENDS
24 dicembre Bresenham画线算法假设x列的象素已确定,其行下标为y。那么下一个象素的列坐标必为x+1。而行坐标要么不变,要么递增1。是否递增1取决于如图所示的误差项d的值。因为直线的起始点在象素中心,所以误差项d的初始值为0。X下标每增加1,d的值相应递增直线的斜率值,即d=d+k(k=y/x为直线斜率)。一旦d>=1时,就把它减去,这样保证d始终在0、1之间。当d>0.5时,直线与x+1垂直网络线交点最接近于当前象素(x,y)的右上方象素(x+1,y+1);而当d<0.5时,更接近于象素(x+1,y),当d=0。5时,与上述二象素一样接近,约定取(x+1,y+1)。令e=d-0。5。则当e>=0时,下一象素的y下标增加1,而当e〈0时,下一象素的y下标不增。E的初始值为-0.5. 破解所谓的“网页源代码加密”在地址栏或按Ctrl+O,输入: javascript:s=document.documentElement.outerHTML;document.write('<body></body>');document.body.innerText=s; 源代码就出来了。不论加密如何复杂,最终都要还原成浏览器可以解析的html代码,而documentElement.outerHTML正是最终的结果。 |
|
|