对于++、--运算符,我们应注意以下几点:

(1)++、--运算符只能用于变量,而不能用于常量或表达式,例如8++,(x+y)--均是不合法的。

(2)++、--运算符是单目运算符,优先级高于双目基本算术运算符,而低于括号( ( ) )运算符,结合性为从右到左。

(3)++、--运算符的运算对象为字符型、整型、指针型变量或数组元素,运算结果的数据类型同运算对象的类型一致。

(4)当出现难以区分的若干个“+”或“-”组成运算符串时,C语言规定:从左到右取尽可能多的符号组成运算符。例如,设整型变量a、b的值均为5,则:

a+++b   应理解为(a++)+b,结果为10,运算后a为6,b不变。

a---b   应理解为(a--)-b,结果为0,运算后a为4,b不变。

但如果出现如下形式:

(a++)+(a++)+(a++)

表达式的值是多少呢?有的系统按照从左到右顺序求解括弧内的运算,求完第一个括弧的值后,实现a的自加,a值变为6,再依次求第二个、第三个括弧的值,结果表达式相当于5+6+7,即18。而另一些系统(如Turbo c)把5作为表达式中所有a的值,因此3个a相加,得表达式的值为15,在求出整个表达式的值后再实现自加3次,a的值变为8。应该避免出现这种岐义,程序中尽量不要出现这种现象。

(5)在printf( )函数中,实参数的求值顺序,各系统不一样。在多数系统中对函数的求值顺序是从右到左。例如,i初值为5。

printf("%d,%d",i,i++);

输出结果为:

          6,5

(6)请不要在一个表达式中对同一个变量进行多次诸如i++或++i等运算,例如写成:i++*i++-++i,这种表达式不仅可读性差,而且不同的编译系统对这样的表达式将作不同的处理,因而得到的结果也各不相同。


简洁的C语言字符串复制函数:

char *strcpy(char *strDest, const char *strSrc);
{
assert((strDest!=NULL) && (strSrc !=NULL));
char *address = strDest;
while( (*strDest++ = * strSrc++) != ‘\0’ )
NULL ;
return address ;
}


assert是当括号里的内容为假时程序报错。
先*,后++,然后赋值,然后while里面的循环判断比较。
将*strSrc赋值给*strDest,然后判断是不是已经到达\0(即字符串结尾),同时,执行完赋值后strSrc和strDest指针均后移一位。总的结果即是:将strSrc指向的内容复制到strDest,直到strSrc指向\0.
\0代表字符串的结束符。

源地址:http://hi.baidu.com/lechie/blog/item/469c54101a6420fdc3ce79eb.html
posted @ 2009-10-13 16:51 Basil08 阅读(331) 评论(0) 编辑

1  What will happen after running the "Test"?

#include <iostream.h>

void GetMemory(char *p, int num)
{
    p 
= (char *)malloc(sizeof(char*
 num);
}

int
 main()
{
    
char *str =
 NULL;

    GetMemory(str, 
100
);
    strcpy(str, 
"hello"
);

    
return 0
;
}


分析:由于void GetMemory(char *p, int num)中的*p实际上是主函数中的一个str的一个副本,编译器总是要为函数的每个参数制作临时副本。在本倒中,p申请了新的内存,只是把p把指的内存地址改变了,但str丝毫未变。因为GetMemory没有返回值,因此str并不指向p所申请的那段内存,所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会申请一块内存,但申请的内存却不能有效释放,结果是内存一直被独占,最终造成内存泄露。

答案:程序崩溃。因为GetMemory并不能传递动态内存,Test函数中的str一直都是NULL。

//---------------------------------------------------------------------------------------------------

以下是正常的申请方式:

 

方法一:用指针参数去申请内存时,应用采用指向指针的指针,把str的地址传给函数GetMemory

 

#include <iostream.h>

void GetMemory(char **p, int num)
{
    
*= (char *)malloc(sizeof(char*
 num);
}

int
 main()
{
    
char *str =
 NULL;

    GetMemory(
&str, 100
);
    strcpy(str, 
"hello"
);

    std::cout 
<< *str <<
 std::endl;
    std::cout 
<< str <<
 std::endl;
    std::cout 
<< &str <<
 std::endl;

    
return 0
;
}

 

方法二:函数返回值为指针类型来传递动态内存

 

#include <iostream>

char *GetMemory(char *p, int num)
{
    
return p = (char *)malloc(sizeof(char*
 num);
}

int
 main()
{
    
char *str =
 NULL;

    str 
= GetMemory(str, 100
);
    strcpy(str, 
"hello"
);

    std::cout 
<< *str <<
 std::endl;
    std::cout 
<< str <<
 std::endl;
    std::cout 
<< &str <<
 std::endl;

    
return 0
;
}

  //------------------------------------------------------------------------------------------------

 

 What will happen after running the "Test"?


#include <iostream>

char *GetMemory(void)
{
    
char p[] = "hello world"
;
    
return
 p;
}

int
 main()
{
    
char *str =
 NULL;
    str 
=
 GetMemory();
    std::cout 
<< str <<
 std::endl;

    
return 0
;
}

答案:可能是乱码,也有可能是正常输出。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是NULL,但其原来的内容已经被清除,新内容不可知。

 //------------------------------------------------------------------------------------------------

【内存操作及问题相关知识点】为了能彻底解决动态内存传递的问题,我们回顾一下内存管理的知识要点.
内存分配方式有三种:

从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

 


从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活。

在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

 

原网址:http://blog.csdn.net/seuzyq/archive/2009/10/06/4636849.aspx
posted @ 2009-10-13 10:20 Basil08 阅读(94) 评论(0) 编辑

 静态构造函数用于初始化任何静态数据,或用于执行仅需执行一次的特定操作。在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。

class SimpleClass
{
    
// Static constructor
    static SimpleClass()
    {
        
//
    }
}

 

静态构造函数具有以下特点:

  • 静态构造函数既没有访问修饰符,也没有参数。

  • 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化

  • 无法直接调用静态构造函数。

  • 在程序中,用户无法控制何时执行静态构造函数。

  • 静态构造函数的典型用途是:当类使用日志文件时,将使用这种构造函数向日志文件中写入项。

  • 静态构造函数在为非托管代码创建包装类时也很有用,此时该构造函数可以调用 LoadLibrary 方法。

    在此示例中,类 Bus 有一个静态构造函数和一个静态成员 Drive()。当调用 Drive() 时,将调用静态构造函数来初始化类。

    Code

     

    输出

    The static constructor invoked.

    The Drive method invoked.

     

 

 

 

posted @ 2009-09-29 16:40 Basil08 阅读(43) 评论(0) 编辑
 今天看程序员面试宝典发现了一个问题。在P37的例子中,宝典认为>>比~的优先级高。这是错误的。实际上~比>>的优先级高。程序代码如下:

#include <iostream>

using namespace std;

int main()
{
    unsigned char a=0xA5;
   
unsigned char b=~a>>4;
    printf(
"b=%d\n",b);
   
   
    system(
"PAUSE");
   
return 0;
}
解析:char signed char unsigned char和short int参与运算时会提升为类型int.
a=0XA5 提示为0X000000A5 然后进行求反得到0XFFFFFF5A 然后移位得到0X0FFFFFF5 最终转化成u char 得到0XF5 ,既是输出结果16*15+5=245.(当为char时那么就是变量的最高位补齐,unsigned补位时用0补起 )

这是台网某CPU公司的面试题。程序输出结果是245。虽然认为>>优先级高于~能得出正确的结果,但是我们应该找到正确的原因。

因为unsigned char和char类型变量在参与运算的时候,会首先被提升为int类型,计算完毕再转换成unsigned char 或char类型。从这个正确的角度,就可以得到正确的结果。

我们可以用以下代码进行验证。

char a=0x15;
int b=~a;
printf("b=%08x\n",b);

附录c++运算符优先级:http://www.cppreference.com/operator_precedence.html

Precedence Operator Description Example Associativity
1 ()
[]
->
.
::
++
--
Grouping operator
Array access
Member access from a pointer
Member access from an object
Scoping operator
Post-increment
Post-decrement
(a + b) / 4;
array[4] = 2;
ptr->age = 34;
obj.age = 34;
Class::age = 2;
for( i = 0; i < 10; i++ ) ...
for( i = 10; i > 0; i-- ) ...
left to right
2 !
~
++
--
-
+
*
&
(type)
sizeof
Logical negation
Bitwise complement
Pre-increment
Pre-decrement
Unary minus
Unary plus
Dereference
Address of
Cast to a given type
Return size in bytes
if( !done ) ...
flags = ~flags;
for( i = 0; i < 10; ++i ) ...
for( i = 10; i > 0; --i ) ...
int i = -1;
int i = +1;
data = *ptr;
address = &obj;
int i = (int) floatNum;
int size = sizeof(floatNum);
right to left
3 ->*
.*
Member pointer selector
Member pointer selector
ptr->*var = 24;
obj.*var = 24;
left to right
4 *
/
%
Multiplication
Division
Modulus
int i = 2 * 4;
float f = 10 / 3;
int rem = 4 % 3;
left to right
5 +
-
Addition
Subtraction
int i = 2 + 3;
int i = 5 - 1;
left to right
6 <<
>>
Bitwise shift left
Bitwise shift right
int flags = 33 << 1;
int flags = 33 >> 1;
left to right
7 <
<=
>
>=
Comparison less-than
Comparison less-than-or-equal-to
Comparison greater-than
Comparison geater-than-or-equal-to
if( i < 42 ) ...
if( i <= 42 ) ...
if( i > 42 ) ...
if( i >= 42 ) ...
left to right
8 ==
!=
Comparison equal-to
Comparison not-equal-to
if( i == 42 ) ...
if( i != 42 ) ...
left to right
9 & Bitwise AND flags = flags & 42; left to right
10 ^ Bitwise exclusive OR flags = flags ^ 42; left to right
11 | Bitwise inclusive (normal) OR flags = flags | 42; left to right
12 && Logical AND if( conditionA && conditionB ) ... left to right
13 || Logical OR if( conditionA || conditionB ) ... left to right
14 ? : Ternary conditional (if-then-else) int i = (a > b) ? a : b; right to left
15 =
+=
-=
*=
/=
%=
&=
^=
|=
<<=
>>=
Assignment operator
Increment and assign
Decrement and assign
Multiply and assign
Divide and assign
Modulo and assign
Bitwise AND and assign
Bitwise exclusive OR and assign
Bitwise inclusive (normal) OR and assign
Bitwise shift left and assign
Bitwise shift right and assign
int a = b;
a += 3;
b -= 4;
a *= 5;
a /= 2;
a %= 3;
flags &= new_flags;
flags ^= new_flags;
flags |= new_flags;
flags <<= 2;
flags >>= 2;
right to left
16 , Sequential evaluation operator for( i = 0, j = 0; i < 10; i++, j++ ) ... left to right


出处:http://hi.baidu.com/tju_jierry/blog/item/dfb25a0053c6c10f1c958361.html

posted @ 2009-09-29 11:04 Basil08 阅读(285) 评论(0) 编辑
无疑中发现了这个网站http://www.thinkpage.cn/weather/ 他提供的天气预报的代码,看着样式还很不错,就记录下来以备后用!
这是我设置的一个的效果!

PS:还有几种样式可以设置! url:http://www.thinkpage.cn/weather/Widget.aspx
posted @ 2009-08-10 10:35 Basil08 阅读(160) 评论(0) 编辑

1.JavaScript局部打印

<input id="btnPrint" type="button" value="打印" onclick="javascript:window.print();" />

可以用样式控制,你想让那块打印就打印啊,样式如下:

<style type="text/css" media=print>
.noprint{display : none }
</style>

然后使用样式就可以:

<p class="noprint">不需要打印的地方</p>

=============================================================

2:组件法
WebBrowser是IE内置的浏览器控件,无需用户下载.

一、WebBrowser控件 
  
<object ID='WebBrowser' WIDTH=0 HEIGHT=0 CLASSID='CLSID:8856F961-340A-11D0-A96B-00C04FD705A2'></object> 
二、WebBrowder控件的方法 
//打印 

WebBrowser1.ExecWB(
6,1); 

//打印设置 

WebBrowser1.ExecWB(
8,1); 

//打印预览 

WebBrowser1.ExecWB(
7,1); 

关于这个组件还有其他的用法,列举如下: 
WebBrowser.ExecWB(
1,1) 打开 
Web.ExecWB(
2,1) 关闭现在所有的IE窗口,并打开一个新窗口 
Web.ExecWB(
4,1) 保存网页 
Web.ExecWB(
6,1) 打印 
Web.ExecWB(
7,1) 打印预览 
Web.ExecWB(
8,1) 打印页面设置 
Web.ExecWB(
10,1) 查看页面属性 
Web.ExecWB(
15,1) 好像是撤销,有待确认 
Web.ExecWB(
17,1) 全选 
Web.ExecWB(
22,1) 刷新 
Web.ExecWB(
45,1) 关闭窗体无提示 
但是打印是会把整个页面都打印出来的,页面里面有什么东西就打印出来,我们有时候只需要打印数据表格,这时我们就要写一个样式了:把不想打印的部份隐藏起来:
样式内容:
<style type="text/css" media=print>
.noprint...
{display : none }
</style>
然后使用样式就可以:
<p class="noprint">不需要打印的地方</p>

代码如下:

<script language="javascript"> 
function printsetup()...
// 打印页面设置 
wb.execwb(8,1); 
}
 
function printpreview()...
// 打印页面预览 

wb.execwb(
7,1); 

}
 

function printit() 
...

if (confirm('确定打印吗?')) ...
wb.execwb(
6,6
}
 
}
 
</script> 

<OBJECT classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2" height=0 id=wb name=wb width=0></OBJECT> 
<input type=button name=button_print value="打印" class="noprint" onclick="javascript:printit()"> 
<input type=button name=button_setup value="打印页面设置" class="noprint" onclick="javascript:printsetup();"> 
<input type=button name=button_show value="打印预览" class="noprint" onclick="javascript:printpreview();">
3:
JS 实现简单的页面局部打印 
function preview(oper)
...
{
if (oper < 10)...{
bdhtml
=window.document.body.innerHTML;//获取当前页的html代码
sprnstr="<!--startprint"+oper+"-->";//设置打印开始区域
eprnstr="<!--endprint"+oper+"-->";//设置打印结束区域
prnhtml=bdhtml.substring(bdhtml.indexOf(sprnstr)+18); //从开始代码向后取html

prnhtml
=prnhtml.substring(0,prnhtml.indexOf(eprnstr));//从结束代码向前取html
window.document.body.innerHTML=prnhtml;
window.print();
window.document.body.innerHTML
=bdhtml;


}
 else ...{
window.print();
}


}


使用很简单 将页面内要打印的内容加入中间
<!--startprint1-->XXXXX<!--endprint1-->
再加个打印按纽 onclick
=preview(1)

source:http://blog.chinaunix.net/u/26845/showart_1087849.html

 

posted @ 2009-01-06 11:16 Basil08 阅读(11064) 评论(4) 编辑
      初学数据库编程我们可能会有一些对“空值”的疑问,比如通过编程新建的一个表中所有数据皆显示为<NULL>,手动添加并删除文字后又变成了空白;一个字符串类型的字段,明明没有填值,却不等于"";用ADO.NET从数据库中取值,每遇到有<NULL>的就出错……这需要我们正确认识.NET和SQL Server中几种不同的“空值”。

      1、真正的空值,也就是“没有输入的值”,可以出现在大多数类型的字段中(如果没有别的约束条件),SQL server中表示为null,显示为<NULL>,手工在SQL server企业管理器中输入的方法是按Ctrl+0。它在.NET中对应System.DBNull.Value。在T-SQL命令中,判断一个值是不是空值,要用“is null”而不是“= null”;处理空值有个ISNULL函数,它使用指定的值替换null。用ADO.NET从数据库得到的空值无法自动转化为空字符串或Nothing,须手动检测:如果得到System.DBNull.Value,则赋给数据对象Nothing或其它自定义的有意义的值。

      2、空字符串(零长度字符串),只出现在字符串类型(如nvarchar)的字段中,SQL server中表示为'',显示为空白,手工在SQL server企业管理器中输入时清空一个单元格即可。它在.NET中对应System.String.Empty,也就是我们常用的""。在T-SQL命令中处理空字符串和处理一般的字符串没什么区别。用ADO.NET从数据库得到的空字符串也和一般的字符串没什么区别。

 DBNull简介

      DBNull在DotNet是单独的一个类型 System.DBNull 。它只有一个值 DBNull.Value 。DBNull 直接继承 Object ,所以 DBNull 不是 string , 不是 int , 也不是 DateTime 。。。

      但是为什么 DBNull 可以表示数据库中的字符串,数字,或日期呢?原因是DotNet储存这些数据的类(DataRow等)都是以 object 的形式来储存数据的。对于 DataRow , 它的 row[column] 返回的值永远不为 null , 要么就是具体的为column 的类型的值, 要么就是 DBNull 。 所以 row[column].ToString() 这个写法永远不会在ToString那里发生NullReferenceException。

      DBNull 实现了 IConvertible 。 但是,除了 ToString 是正常的外,其他的ToXXX都会抛出不能转换的错误。

      在 IDbCommand(OleDbCommand,SqlCommand...) 的ExecuteScalar的返回值中,情况可以这样分析:

select 1 这样返回的object是 1
select null 这样返回的是DBNull.Value
select isnull(null,1) 返回的是 1
select top 0 id from table1 这样返回的值是null
select isnull(id,0) from table1 where 1=0 返回的值是null

这里 ExecuteScalar 的规则就是,返回第一列,第一行的数据。如果第一列第一行不为空,那么ExecuteScalar就直接对应的DotNet的值。如果有第一行,但是第一列为空,那么返回的是 DBNull 。如果一行都没有,那么ExecuteScalar就返回null规则就是这样的。这里容易犯的一个错误是,把ExecuteScalar返回DBNull与null的情况混淆,例如:

string username=cmd.ExecuteScalar().ToString();

除非你认为cmd执行后,肯定至少有一行数据,否则这里就会出错。

又或者 select id from usertable where username=@name 这样的sql语句,如果找不到记录,那么ExecuteScalar则会返回null,所以千万不要

int userid=Convert.ToInt32(cmd.ExecuteScalar());

或者你会这样写 SQL 语句:select isnull(id,0) from usertable where username=@name

但是 int userid=Convert.ToInt32(cmd.ExecuteScalar()); 依然会出错,因为上面的语句不成立时,仍然是不返回任何行。

对于IDbDataParameter(OleDDbParameter,SqlParameter..)的Value,如果为null,则代表该参数没有指定,或者是代表DEFAULT。如果为DBNull.Value,则代表SQL中的NULL

所以,如果你要调用存储过程,里面有参数 @val nvarchar(20)="AABB" ,
那么cmd.Parameters["@val"].Value=null 代表使用这个默认的 "AABB"
而cmd.Parameters["@val"].Value=DBNull.Value 代表使用NULL来传给 @val


你可以用Convert.IsDBNull来判断一个值是否DBNull。注意Convert.IsDBNull(null)是false。

补充:DBNull指的是数据库中的“null”,而不是CLR中的“null”。

如很多初学者以为下面是一样的:

cmd.Parameters["@payment_type"].Value = "";

cmd.Parameters["@payment_type"].Value = System.DBNull.Value;

 

“”表示的是空字符串,而System.DBNull.Value代表的是数据库中的NULL,既没有数据。就象老师说“0”不是没有一样

posted @ 2008-12-05 16:42 Basil08 阅读(1359) 评论(0) 编辑
posted @ 2008-11-13 21:46 Basil08 阅读(1503) 评论(3) 编辑
posted @ 2008-10-31 21:45 Basil08 阅读(2866) 评论(1) 编辑
posted @ 2008-10-31 09:37 Basil08 阅读(272) 评论(6) 编辑