http://www.cnfug.org/journal/systems/2004/000081.html
#include <iostream>
class A
{
public:
A(int i)
{
m_A = i;
}
~A()
{
}
static void print()
{
std::cout<< "A" <<std::endl;
}
friend class B;
protected:
int m_A;
private:
};
class B
{
public:
B(int i)
{
m_B = i;
}
static void print()
{
std::cout<< "B" << std::endl;
}
void show(B b)
{
b.a->m_A = 3;
b.m_B = 2;
}
protected:
private:
A* a;
int m_B;
};
template<class T1, class T2>
class CTestTemplate
{
public:
CTestTemplate(T1 t)
{
m_number = t;
}
void print()
{
T2::print();
std::cout<< m_number<< std::endl;
}
protected:
private:
T1 m_number;
};
int main(int argc, char* argv[])
{
CTestTemplate<int, B> testtem(3);
testtem.print();
}
class A
{
public:
A(int i)
{
m_A = i;
}
~A()
{
}
static void print()
{
std::cout<< "A" <<std::endl;
}
friend class B;
protected:
int m_A;
private:
};
class B
{
public:
B(int i)
{
m_B = i;
}
static void print()
{
std::cout<< "B" << std::endl;
}
void show(B b)
{
b.a->m_A = 3;
b.m_B = 2;
}
protected:
private:
A* a;
int m_B;
};
template<class T1, class T2>
class CTestTemplate
{
public:
CTestTemplate(T1 t)
{
m_number = t;
}
void print()
{
T2::print();
std::cout<< m_number<< std::endl;
}
protected:
private:
T1 m_number;
};
int main(int argc, char* argv[])
{
CTestTemplate<int, B> testtem(3);
testtem.print();
}
IE浏览器里输入:javascript.document.cookie="name=xiangdong"
chrome里读取:
console.log(document.cookie)
language1=zh; uin=7srsOd27A3NlR3MU5LVzWg%3D%3D
chrome里设置:
document.cookie="name=xiangdong"
"name=xiangdong"
console.log(document.cookie)
name=xiangdong; language1=zh; uin=7srsOd27A3NlR3MU5LVzWg%3D%3D
===============================================
<script langrage=javascript>
// writeCookie("myCookie", "my name", 24);
// Stores the string "my name" in the cookie "myCookie" which expires after 24 hours.
// The hours parameter is optional; if hours is left out, the cookie value expires at the end of the visitor's browser session.
function writeCookie(name, value, hours)
{
var expire = "";
if(hours != null)
{
expire = new Date((new Date()).getTime() + hours * 3600000);
expire = "; expires=" + expire.toGMTString();
}
document.cookie = name + "=" + escape(value) + expire;
}
// Example:
// alert( readCookie("myCookie") );
function readCookie(name)
{
var cookieValue = "";
var search = name + "=";
if(document.cookie.length > 0)
{
offset = document.cookie.indexOf(search);
if (offset != -1)
{
offset += search.length;
end = document.cookie.indexOf(";", offset);
if (end == -1) end = document.cookie.length;
cookieValue = unescape(document.cookie.substring(offset, end))
}
}
return cookieValue;
}
</script>
<body>
<script>
writeCookie("name","xiangdong2",24);
alert( readCookie("name") );
</script>
</body>
chrome里读取:
console.log(document.cookie)
language1=zh; uin=7srsOd27A3NlR3MU5LVzWg%3D%3D
chrome里设置:
document.cookie="name=xiangdong"
"name=xiangdong"
console.log(document.cookie)
name=xiangdong; language1=zh; uin=7srsOd27A3NlR3MU5LVzWg%3D%3D
===============================================
<script langrage=javascript>
// writeCookie("myCookie", "my name", 24);
// Stores the string "my name" in the cookie "myCookie" which expires after 24 hours.
// The hours parameter is optional; if hours is left out, the cookie value expires at the end of the visitor's browser session.
function writeCookie(name, value, hours)
{
var expire = "";
if(hours != null)
{
expire = new Date((new Date()).getTime() + hours * 3600000);
expire = "; expires=" + expire.toGMTString();
}
document.cookie = name + "=" + escape(value) + expire;
}
// Example:
// alert( readCookie("myCookie") );
function readCookie(name)
{
var cookieValue = "";
var search = name + "=";
if(document.cookie.length > 0)
{
offset = document.cookie.indexOf(search);
if (offset != -1)
{
offset += search.length;
end = document.cookie.indexOf(";", offset);
if (end == -1) end = document.cookie.length;
cookieValue = unescape(document.cookie.substring(offset, end))
}
}
return cookieValue;
}
</script>
<body>
<script>
writeCookie("name","xiangdong2",24);
alert( readCookie("name") );
</script>
</body>
function forIn(o){
var a = [];
for(var k in o){
a.push(k + "=" + o[k]);
}
return a.join("\n");
}
alert(forIn(document.del.elements));
alert(document.del.action);
var a = [];
for(var k in o){
a.push(k + "=" + o[k]);
}
return a.join("\n");
}
alert(forIn(document.del.elements));
alert(document.del.action);
if (document.xiaozu.xiaozu.value.indexOf(" ")>=0)
{
alert("小组名前后不能有空格字符.");
return false;
}
{
alert("小组名前后不能有空格字符.");
return false;
}
背景:指针传入函数和变量传入函数也一样,变量有变量本身,及变量的地址,而指针也一样,有指针本身,和指针的地址,下面根据代码来实践一下这个问题。
C语言指针传递详解:http://www.cnblogs.com/archimedes/p/c-transfer-point.html
从函数返回对象经常使用以下两种技术:
使用malloc在函数内部分配内存并返回其地址,调用者负责释放返回的内存
传递一个对象给函数,让函数修改它,这样分配和释放对象的内存都是调用者的责任
先讲难度大一点的,指针的地址传入函数里,传递指针的指针-将指针传递给函数的时候,传递的是值,如果希望修改原指针而不是指针的副本,就需要传递指情况一,针的指针,如下,allocateArray.c :
gcc -g -o allocateArray allocateArray.c
[root@test pointerparam]# ./allocateArray
45
45
45
45
45
用gdb看一下其指针地址,为何这样就能实现在函数里malloc后,在外面依然能够获取到malloc里的值呢?是因为传入的指针的地址,相当于这个malloc的内存根本没有退出函数后销毁,而且传入的地址是指针的地址,不是指针,这两点保证了其地址是同一个地址,不是副本,所以,函数退出后还在,需要外面作free(;vector),vector=NULL:
(gdb) b 4
Breakpoint 1 at 0x40053a: file allocateArray.c, line 4.
(gdb) b 18
Breakpoint 2 at 0x4005ad: file allocateArray.c, line 18.
(gdb) r
Breakpoint 2, main () at allocateArray.c:18
18 allocateArray(&vector,5,45);
(gdb) p &vector
$1 = (int **) 0x7fff3cb989f0 //函数外的地址: 0x7fff3cb989f0
(gdb) c
Continuing.
Breakpoint 1, allocateArray (arr=0x7fff3cb989f0, size=5, value=45) at allocateArray.c:5
5 *arr = (int*)malloc(size*sizeof(int));
(gdb) p arr
$2 = (int **) 0x7fff3cb989f0 //这个地址在函数里也一直是传入的地址: 0x7fff3cb989f0
(gdb) n
6 if(*arr != NULL){
(gdb) p arr
$4 = (int **) 0x7fff3cb989f0
(gdb) n
7 if(*arr != NULL){
(gdb) n
8 for(i=0;i<size;i++){
(gdb) n
9 *(*arr+i) = value;
(gdb) n
main () at allocateArray.c:19
............next............
19 for(i = 0; i < 5; i++) {
(gdb) n
20 printf("%d\n", vector[i]);
(gdb) p &vector
$6 = (int **) 0x7fff3cb989f0 //发现没到函数里转一圈后,这个地址一直是: 0x7fff3cb989f0
(gdb) n
45
19 for(i = 0; i < 5; i++) {//打印出函数里赋的值是没有问题的..正常运行结束。
情况二:下面这个版本的allocateArray函数传递了一个数组指针、数组的长度和用来初始化数组元素的值,返回指针只是为了方便
[root@test pointerparam]# gcc allocateArray3.c
[root@test pointerparam]# ./a.out
45
45
45
45
45
这个值是变了,但指针是没有变的,也就是说指针做了它该做的工作,并没有像第一种那样: allocateArray(&vector,5,45);实现对指针本身地址通过函数进行了修改,这儿只是对指针里的值做了修改,是不一样的。
用gdb来跟踪一下这个指针的传指针值的操作:
[root@test pointerparam]# gdb allocateArray3
(gdb) b 15
Breakpoint 1 at 0x400571: file allocateArray3.c, line 15.
(gdb) b 5
Breakpoint 2 at 0x400536: file allocateArray3.c, line 5.
(gdb) r
Starting program: /tmp/pointerparam/allocateArray3
Breakpoint 1, main () at allocateArray3.c:15
15 int* vector = (int*)malloc(5 * sizeof(int));
(gdb) p vector
$1 = (int *) 0x0 //此时是光一个指针还没有分配指针指和的malloc真实数据地址
(gdb) n
16 allocateArray(vector, 5, 45);
(gdb) p vector
$2 = (int *) 0xb447010 //分配地址:0xb447010 这个值会带入进去,并在里面对其作赋值操作,出函数后这个值还在,因为在传入前就已经分配好空间,在函数里只是赋值,把东西放进这个空间,函数返回后空间并没有销毁,因为是在函数外。
(gdb) c
Continuing.
Breakpoint 2, allocateArray (arr=0xb447010, size=5, value=45) at allocateArray3.c:6
6 if(arr != NULL) {
(gdb) c
Continuing.
45
45
45
45
45
情况三,指针值传入函数里面,这样会出现一个segment default的,情况三作一下修改:
allocateArray2.c
gcc -g -o allocateArray2 allocateArray2.c
[root@test pointerparam]# ./allocateArray2
Segmentation fault
如这样写呢? *arr = (int*)malloc(size*sizeof(int));
如果想这样,编译都会报错,如下:
porinter.c:6:10: 警告:赋值时将指针赋给整数,未作类型转换 [默认启用]
因为文件名传入的是一个指针,而*arr是一个值,不再是一个指针了。
而传入的是指针的指针就不一样了,如前面的例子1:void allocateArray(int ** arr,int size,int value){
那么因为函数int ** arr是指针的指针,也就是这个指针是可以修改的,这个*arr它不是一个值了,而是一个指针,所以,它可以给它malloc一个空间,并把这个空间给到*arr这个脂针地址里去,这块一定要区分开来,否则指向指针这一块的概念就没彻底理解清楚。
再理解前面引用的Url里的这一段话,加强深入理解传入指向指针的指针是可以修改指针的地址,指针也理一个数据,和int char是一样的东西,它也是能被修改的,而一维指针可以修改int char,int这样的值,但指针地址不变,而指针的指针它的地址都能被修改,这就是指针的精华人所在,摘录如下:
传递指针可以让多个函数访问指针所引用的对象,而不用把对象声明为全局可访问,要在某个函数中修改数据,需要用指针传递数据,当数据是需要修改的指针的时候,就要传递指针的指针,传递参数(包括指针)的时候,传递的是它们的值,也就是说,传递给函数的是参数值的一个副本,也就是说这儿数据是需要修改的指针的时候,就要传递指针的指针,而咱们只传了指针,修改后退出函数这个指针并没有变,销毁函数后,没有对指针作出修改,等于空做了一次运算,像做梦一样,函数并没改变什么,所以出现错误。
为何会出现segment default的情况?是因为指针传入函数后进行了malloc,而这个指针是在函数里经过malloc时给修改了指向地址,而这个malloc的空间因为函数退出而回收了指针传值地址,也就是其并没有记得下来,其malloc出来的存放整数的空间还在,但退出函数时就丢了,为此,在外面打印一个不存在的地址,当然会出现了segment default的情况,gdb分析如下:
(gdb) b 18
Breakpoint 1 at 0x40059a: file allocateArray2.c, line 18.
(gdb) b 19
Breakpoint 2 at 0x4005ad: file allocateArray2.c, line 19.
(gdb) b 4
Breakpoint 3 at 0x40053a: file allocateArray2.c, line 4.
(gdb) r
Starting program: /tmp/pointerparam/allocateArray2
Breakpoint 1, main () at allocateArray2.c:18
18 allocateArray(vector,5,45);
(gdb) n
Breakpoint 3, allocateArray (arr=0x0, size=5, value=45) at allocateArray2.c:5 //arr传入是0x0,也就是副本vector的地址。
5 arr = (int*)malloc(size*sizeof(int));
(gdb) n
6 if(arr != NULL){
(gdb) p arr
$1 = (int *) 0x14c3c010 //经malloc后是0x14c3c010
(gdb) c
Continuing.
Breakpoint 2, main () at allocateArray2.c:19
19 for(i = 0; i < 5; i++) {
(gdb) p vector //返回main函数后,这个vector还是0x0,并没有经过函数而改变,当然,下面对其进行打印会Segmentation fault.
$2 = (int *) 0x0
(gdb) n
20 printf("%d\n", vector[i]);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00000000004005c3 in main () at allocateArray2.c:20
20 printf("%d\n", vector[i]);
回顾总结:
allocateArray.c allocateArray2.c
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
void allocateArray(int *arr,int size,int value){ void allocateArray(int ** arr,int size,int value){
int i; int i;
arr = (int*)malloc(size*sizeof(int)); *arr = (int*)malloc(size*sizeof(int));
if(arr != NULL){ if(*arr != NULL){
if(arr != NULL){ if(*arr != NULL){
for(i=0;i<size;i++){ for(i=0;i<size;i++){
arr[i] = value; *(*arr+i) = value;
} }
} }
} }
} }
int main(){ int main(){
int i; int i;
int *vector = NULL; int *vector = NULL;
allocateArray(vector,5,45); allocateArray(&vector,5,45);
for(i = 0; i < 5; i++) { for(i = 0; i < 5; i++) {
printf("%d\n", vector[i]); printf("%d\n", vector[i]);
} }
free(vector); free(vector);
} }
结论是malloc在函数里都得销毁掉,详细如下所述:
C语言是传值调用的,左边的你传递进去vector的地址,右边的是你传递了vector这个指针的地址值,所以左边的allocateArray函数内对arr的修改不会对函数外vector的值有什么影响,但是右边就不一样了,对arr的修改就是对vector变量所在的空间中的值的修改,也就是修改了vector的值,所以左边的allocateArray函数内对arr的修改不会对函数外vector的值有什么影响,那这个左边的malloc有没有运行完后还在呢? 右边这个如果不free会有内存泄漏的呀。
两边的都要销毁,只是左边的你在函数外没办法销毁。
【活跃】回忆未来-向东-Jàck 15/3/18 星期三 11:13:40
哈哈,了解了,多谢兄弟啊,相当感谢,我都说这malloc这玩意用时要注意才是。搞不好就泄漏了呢。
11:13:53
【潜水】Now&Fight 15/3/18 星期三 11:13:53
嗯嗯
阅读全文
C语言指针传递详解:http://www.cnblogs.com/archimedes/p/c-transfer-point.html
从函数返回对象经常使用以下两种技术:
使用malloc在函数内部分配内存并返回其地址,调用者负责释放返回的内存
传递一个对象给函数,让函数修改它,这样分配和释放对象的内存都是调用者的责任
先讲难度大一点的,指针的地址传入函数里,传递指针的指针-将指针传递给函数的时候,传递的是值,如果希望修改原指针而不是指针的副本,就需要传递指情况一,针的指针,如下,allocateArray.c :
gcc -g -o allocateArray allocateArray.c
[root@test pointerparam]# ./allocateArray
45
45
45
45
45
用gdb看一下其指针地址,为何这样就能实现在函数里malloc后,在外面依然能够获取到malloc里的值呢?是因为传入的指针的地址,相当于这个malloc的内存根本没有退出函数后销毁,而且传入的地址是指针的地址,不是指针,这两点保证了其地址是同一个地址,不是副本,所以,函数退出后还在,需要外面作free(;vector),vector=NULL:
(gdb) b 4
Breakpoint 1 at 0x40053a: file allocateArray.c, line 4.
(gdb) b 18
Breakpoint 2 at 0x4005ad: file allocateArray.c, line 18.
(gdb) r
Breakpoint 2, main () at allocateArray.c:18
18 allocateArray(&vector,5,45);
(gdb) p &vector
$1 = (int **) 0x7fff3cb989f0 //函数外的地址: 0x7fff3cb989f0
(gdb) c
Continuing.
Breakpoint 1, allocateArray (arr=0x7fff3cb989f0, size=5, value=45) at allocateArray.c:5
5 *arr = (int*)malloc(size*sizeof(int));
(gdb) p arr
$2 = (int **) 0x7fff3cb989f0 //这个地址在函数里也一直是传入的地址: 0x7fff3cb989f0
(gdb) n
6 if(*arr != NULL){
(gdb) p arr
$4 = (int **) 0x7fff3cb989f0
(gdb) n
7 if(*arr != NULL){
(gdb) n
8 for(i=0;i<size;i++){
(gdb) n
9 *(*arr+i) = value;
(gdb) n
main () at allocateArray.c:19
............next............
19 for(i = 0; i < 5; i++) {
(gdb) n
20 printf("%d\n", vector[i]);
(gdb) p &vector
$6 = (int **) 0x7fff3cb989f0 //发现没到函数里转一圈后,这个地址一直是: 0x7fff3cb989f0
(gdb) n
45
19 for(i = 0; i < 5; i++) {//打印出函数里赋的值是没有问题的..正常运行结束。
情况二:下面这个版本的allocateArray函数传递了一个数组指针、数组的长度和用来初始化数组元素的值,返回指针只是为了方便
[root@test pointerparam]# gcc allocateArray3.c
[root@test pointerparam]# ./a.out
45
45
45
45
45
这个值是变了,但指针是没有变的,也就是说指针做了它该做的工作,并没有像第一种那样: allocateArray(&vector,5,45);实现对指针本身地址通过函数进行了修改,这儿只是对指针里的值做了修改,是不一样的。
用gdb来跟踪一下这个指针的传指针值的操作:
[root@test pointerparam]# gdb allocateArray3
(gdb) b 15
Breakpoint 1 at 0x400571: file allocateArray3.c, line 15.
(gdb) b 5
Breakpoint 2 at 0x400536: file allocateArray3.c, line 5.
(gdb) r
Starting program: /tmp/pointerparam/allocateArray3
Breakpoint 1, main () at allocateArray3.c:15
15 int* vector = (int*)malloc(5 * sizeof(int));
(gdb) p vector
$1 = (int *) 0x0 //此时是光一个指针还没有分配指针指和的malloc真实数据地址
(gdb) n
16 allocateArray(vector, 5, 45);
(gdb) p vector
$2 = (int *) 0xb447010 //分配地址:0xb447010 这个值会带入进去,并在里面对其作赋值操作,出函数后这个值还在,因为在传入前就已经分配好空间,在函数里只是赋值,把东西放进这个空间,函数返回后空间并没有销毁,因为是在函数外。
(gdb) c
Continuing.
Breakpoint 2, allocateArray (arr=0xb447010, size=5, value=45) at allocateArray3.c:6
6 if(arr != NULL) {
(gdb) c
Continuing.
45
45
45
45
45
情况三,指针值传入函数里面,这样会出现一个segment default的,情况三作一下修改:
allocateArray2.c
gcc -g -o allocateArray2 allocateArray2.c
[root@test pointerparam]# ./allocateArray2
Segmentation fault
如这样写呢? *arr = (int*)malloc(size*sizeof(int));
如果想这样,编译都会报错,如下:
porinter.c:6:10: 警告:赋值时将指针赋给整数,未作类型转换 [默认启用]
因为文件名传入的是一个指针,而*arr是一个值,不再是一个指针了。
而传入的是指针的指针就不一样了,如前面的例子1:void allocateArray(int ** arr,int size,int value){
那么因为函数int ** arr是指针的指针,也就是这个指针是可以修改的,这个*arr它不是一个值了,而是一个指针,所以,它可以给它malloc一个空间,并把这个空间给到*arr这个脂针地址里去,这块一定要区分开来,否则指向指针这一块的概念就没彻底理解清楚。
再理解前面引用的Url里的这一段话,加强深入理解传入指向指针的指针是可以修改指针的地址,指针也理一个数据,和int char是一样的东西,它也是能被修改的,而一维指针可以修改int char,int这样的值,但指针地址不变,而指针的指针它的地址都能被修改,这就是指针的精华人所在,摘录如下:
传递指针可以让多个函数访问指针所引用的对象,而不用把对象声明为全局可访问,要在某个函数中修改数据,需要用指针传递数据,当数据是需要修改的指针的时候,就要传递指针的指针,传递参数(包括指针)的时候,传递的是它们的值,也就是说,传递给函数的是参数值的一个副本,也就是说这儿数据是需要修改的指针的时候,就要传递指针的指针,而咱们只传了指针,修改后退出函数这个指针并没有变,销毁函数后,没有对指针作出修改,等于空做了一次运算,像做梦一样,函数并没改变什么,所以出现错误。
为何会出现segment default的情况?是因为指针传入函数后进行了malloc,而这个指针是在函数里经过malloc时给修改了指向地址,而这个malloc的空间因为函数退出而回收了指针传值地址,也就是其并没有记得下来,其malloc出来的存放整数的空间还在,但退出函数时就丢了,为此,在外面打印一个不存在的地址,当然会出现了segment default的情况,gdb分析如下:
(gdb) b 18
Breakpoint 1 at 0x40059a: file allocateArray2.c, line 18.
(gdb) b 19
Breakpoint 2 at 0x4005ad: file allocateArray2.c, line 19.
(gdb) b 4
Breakpoint 3 at 0x40053a: file allocateArray2.c, line 4.
(gdb) r
Starting program: /tmp/pointerparam/allocateArray2
Breakpoint 1, main () at allocateArray2.c:18
18 allocateArray(vector,5,45);
(gdb) n
Breakpoint 3, allocateArray (arr=0x0, size=5, value=45) at allocateArray2.c:5 //arr传入是0x0,也就是副本vector的地址。
5 arr = (int*)malloc(size*sizeof(int));
(gdb) n
6 if(arr != NULL){
(gdb) p arr
$1 = (int *) 0x14c3c010 //经malloc后是0x14c3c010
(gdb) c
Continuing.
Breakpoint 2, main () at allocateArray2.c:19
19 for(i = 0; i < 5; i++) {
(gdb) p vector //返回main函数后,这个vector还是0x0,并没有经过函数而改变,当然,下面对其进行打印会Segmentation fault.
$2 = (int *) 0x0
(gdb) n
20 printf("%d\n", vector[i]);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00000000004005c3 in main () at allocateArray2.c:20
20 printf("%d\n", vector[i]);
回顾总结:
allocateArray.c allocateArray2.c
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
void allocateArray(int *arr,int size,int value){ void allocateArray(int ** arr,int size,int value){
int i; int i;
arr = (int*)malloc(size*sizeof(int)); *arr = (int*)malloc(size*sizeof(int));
if(arr != NULL){ if(*arr != NULL){
if(arr != NULL){ if(*arr != NULL){
for(i=0;i<size;i++){ for(i=0;i<size;i++){
arr[i] = value; *(*arr+i) = value;
} }
} }
} }
} }
int main(){ int main(){
int i; int i;
int *vector = NULL; int *vector = NULL;
allocateArray(vector,5,45); allocateArray(&vector,5,45);
for(i = 0; i < 5; i++) { for(i = 0; i < 5; i++) {
printf("%d\n", vector[i]); printf("%d\n", vector[i]);
} }
free(vector); free(vector);
} }
结论是malloc在函数里都得销毁掉,详细如下所述:
C语言是传值调用的,左边的你传递进去vector的地址,右边的是你传递了vector这个指针的地址值,所以左边的allocateArray函数内对arr的修改不会对函数外vector的值有什么影响,但是右边就不一样了,对arr的修改就是对vector变量所在的空间中的值的修改,也就是修改了vector的值,所以左边的allocateArray函数内对arr的修改不会对函数外vector的值有什么影响,那这个左边的malloc有没有运行完后还在呢? 右边这个如果不free会有内存泄漏的呀。
两边的都要销毁,只是左边的你在函数外没办法销毁。
【活跃】回忆未来-向东-Jàck 15/3/18 星期三 11:13:40
哈哈,了解了,多谢兄弟啊,相当感谢,我都说这malloc这玩意用时要注意才是。搞不好就泄漏了呢。
11:13:53
【潜水】Now&Fight 15/3/18 星期三 11:13:53
嗯嗯
阅读全文
拖动到快速启动:
鼠标右键(注意是右不是左)点桌面图标后不放,拖动到下面(在这之前就要留好任务栏左边的空隙)操作如下:在下面的左侧有一个快说启动的(有时因为锁定了任务栏会变得得窄看不到),得在任务栏里取消锁定任务栏,再拉长一点儿,这样就能看到桌面图标了。
有人把“显示桌面”按钮删除了,不知道怎么恢复,可以采用如下方法:
打开“记事本”,在里面输入下面内容:
[Shell]
Command=2
IconFile=explorer.exe,3
[Taskbar]
Command=ToggleDesktop
把这个文件保存为:“显示桌面.scf”.随便放到一个地方(比如桌面).
然后把它拖到"快速启动"栏里即可。
在运行里面输入“regsvr32 /n /i:u shell32”回车,在弹出框点击“确定”。
当系统提示“shell32中的dllinstall成功”时,再次点击“确定”。
不知道什么时候,在快速查看有关“启动”的文章">启动栏的显示桌面的快捷方式不见了。
没有了他很不方便。
先新建一个txt文件,用记事本打开,填入如下内容
[Shell]
Command=2
IconFile=explorer.exe,3
[Taskbar]
Command=ToggleDesktop
保存为“显示桌面.scf”,然后把他拖到快速启动栏,就能用了。
但这仅仅是能用,显示桌面.scf的存放位置放哪,万一哪天被删除了,不就又没了。
我们要找到快速启动栏的文件目录位置
Documents and Settings\用户名\Application Data\Microsoft\Internet Explorer\Quick Launch
存放在这里就安全了。
鼠标右键(注意是右不是左)点桌面图标后不放,拖动到下面(在这之前就要留好任务栏左边的空隙)操作如下:在下面的左侧有一个快说启动的(有时因为锁定了任务栏会变得得窄看不到),得在任务栏里取消锁定任务栏,再拉长一点儿,这样就能看到桌面图标了。
有人把“显示桌面”按钮删除了,不知道怎么恢复,可以采用如下方法:
打开“记事本”,在里面输入下面内容:
[Shell]
Command=2
IconFile=explorer.exe,3
[Taskbar]
Command=ToggleDesktop
把这个文件保存为:“显示桌面.scf”.随便放到一个地方(比如桌面).
然后把它拖到"快速启动"栏里即可。
在运行里面输入“regsvr32 /n /i:u shell32”回车,在弹出框点击“确定”。
当系统提示“shell32中的dllinstall成功”时,再次点击“确定”。
不知道什么时候,在快速查看有关“启动”的文章">启动栏的显示桌面的快捷方式不见了。
没有了他很不方便。
先新建一个txt文件,用记事本打开,填入如下内容
[Shell]
Command=2
IconFile=explorer.exe,3
[Taskbar]
Command=ToggleDesktop
保存为“显示桌面.scf”,然后把他拖到快速启动栏,就能用了。
但这仅仅是能用,显示桌面.scf的存放位置放哪,万一哪天被删除了,不就又没了。
我们要找到快速启动栏的文件目录位置
Documents and Settings\用户名\Application Data\Microsoft\Internet Explorer\Quick Launch
存放在这里就安全了。
想写一个C程序,输入N,就能生成N位数的所有排列,谁能帮助我?比如: 输入3,就会输出0,1,2,3,4,5,6,7,8,9中三个数字所组成的任意三位数
http://www.lifewithqmail.org/LWQ-CN.html#preparation
http://www.google.cn/search?hl=zh-CN&newwindow=1&client=firefox-a&rls=org.mozilla%3Azh-CN%3Aofficial&q=%E9%82%AE%E4%BB%B6%E4%BC%A0%E8%BE%93%E6%B5%81%E7%A8%8B+blog&btnG=Google+%E6%90%9C%E7%B4%A2&meta=&aq=f&oq=
http://www.google.cn/search?hl=zh-CN&newwindow=1&client=firefox-a&rls=org.mozilla%3Azh-CN%3Aofficial&q=%E9%82%AE%E4%BB%B6%E4%BC%A0%E8%BE%93%E6%B5%81%E7%A8%8B+blog&btnG=Google+%E6%90%9C%E7%B4%A2&meta=&aq=f&oq=
"VIM工作在与VI不兼容模式下
"set nocompatible
set nocp
"不备份文件
set nobackup
" use mouse everywhere
set mouse=a (再用secure时后要是选择了拖动自动复制,最好不要改选项)
" wrap lines
set wrap
"显示行号
"set nu
"设置匹配模式,类似当输入一个左括号时会匹配相应的那个右括号
set showmatch
"去除vim的GUI版本中的toolbar
set guioptions-=T
"VIM的状态栏标尺
"set ruler
set ru
"检测文件的类型
filetype on
"记录历史的行数
set history=1000
"背景使用黑色
set background=dark
"查找时高亮显示关键字
set hls
"查找时自动找到第一个单词
set incsearch
#设置配色方案
colorscheme murphy
"设置TAB的宽度为4个空格
"set ts=4
set tabstop=4
"行间交错的宽度为4个空格
set shiftwidth=4
"语法高亮度显示
syntax on
"使用自动对齐
"set autoindent
set ai
"智能的选择对齐方式
"set smartindent
set si
"which tags files CTRL-] will search
set tags=./tags,./../tags,./../../tags,./**/tags
"支持C/C++的缩进
set cin
"方便使用taglist
nmap <F8> : Tlist <CR>
"方便使用A.vim插件
nmap <F7> :A<CR>
"方便执行python程序
map <F12> :!python.exe %<CR>
"把tab展开为空格
set expandtab
if(has("gui_running"))
" 图形界面下的设置
else
" 字符界面下的设置
endif
"set nocompatible
set nocp
"不备份文件
set nobackup
" use mouse everywhere
set mouse=a (再用secure时后要是选择了拖动自动复制,最好不要改选项)
" wrap lines
set wrap
"显示行号
"set nu
"设置匹配模式,类似当输入一个左括号时会匹配相应的那个右括号
set showmatch
"去除vim的GUI版本中的toolbar
set guioptions-=T
"VIM的状态栏标尺
"set ruler
set ru
"检测文件的类型
filetype on
"记录历史的行数
set history=1000
"背景使用黑色
set background=dark
"查找时高亮显示关键字
set hls
"查找时自动找到第一个单词
set incsearch
#设置配色方案
colorscheme murphy
"设置TAB的宽度为4个空格
"set ts=4
set tabstop=4
"行间交错的宽度为4个空格
set shiftwidth=4
"语法高亮度显示
syntax on
"使用自动对齐
"set autoindent
set ai
"智能的选择对齐方式
"set smartindent
set si
"which tags files CTRL-] will search
set tags=./tags,./../tags,./../../tags,./**/tags
"支持C/C++的缩进
set cin
"方便使用taglist
nmap <F8> : Tlist <CR>
"方便使用A.vim插件
nmap <F7> :A<CR>
"方便执行python程序
map <F12> :!python.exe %<CR>
"把tab展开为空格
set expandtab
if(has("gui_running"))
" 图形界面下的设置
else
" 字符界面下的设置
endif
#include <stdlib.h>
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
LDAPMessage *res,*e;
int i,version;
char *server;
int port;
char *dn;
char *a;
BerElement *ptr;
char **vals;
char **ppValue = NULL;
char *sdn;
server="10.210.72.141";
port = 389;
//联接服务器
printf("hello the world");
if( (ld = ldap_open(server, port )) == NULL )
{
printf("NO CONNECT");
exit( 1 );
}else{
printf("ldap_open successful\n");
}
version = LDAP_VERSION2;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
if(ldap_simple_bind_s(ld,"cn=Directory Manager","1234qwer")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s by xiangdong2" );
exit( 1 );
}else{
printf("Ldap_bind succesful\n");
}
sdn="dc=sina,dc=net";
if (ldap_search_s(ld,sdn,LDAP_SCOPE_SUBTREE,"(entDefaultDomain=testquanjun1.sina.net)",NULL,0,&res)
!= LDAP_SUCCESS)
{
ldap_perror(ld,"ldap_search_s");
exit(1);
}else{
printf("ldap_search_s is successful\n");
}
for(e=ldap_first_entry(ld,res);e!=NULL;e=ldap_next_entry(ld,res))
{
//取出DN
dn=ldap_get_dn(ld,e);
printf("dn: %s \n",dn);
ldap_memfree( dn );
//对条目的属性进行逐条分析
for ( a = ldap_first_attribute( ld, e, &ptr );a != NULL;a = ldap_next_attribute( ld, e, ptr ) )
{
printf( "%s:",a );
vals = ldap_get_values( ld, e, a );
for ( i = 0; vals[i] != NULL; i++ )
{
printf("%s",vals[i]);
}
printf("\n");
ldap_value_free( vals );
}
printf("\n");
}
ldap_msgfree(res);
ldap_unbind(ld);
}
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
LDAPMessage *res,*e;
int i,version;
char *server;
int port;
char *dn;
char *a;
BerElement *ptr;
char **vals;
char **ppValue = NULL;
char *sdn;
server="10.210.72.141";
port = 389;
//联接服务器
printf("hello the world");
if( (ld = ldap_open(server, port )) == NULL )
{
printf("NO CONNECT");
exit( 1 );
}else{
printf("ldap_open successful\n");
}
version = LDAP_VERSION2;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
if(ldap_simple_bind_s(ld,"cn=Directory Manager","1234qwer")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s by xiangdong2" );
exit( 1 );
}else{
printf("Ldap_bind succesful\n");
}
sdn="dc=sina,dc=net";
if (ldap_search_s(ld,sdn,LDAP_SCOPE_SUBTREE,"(entDefaultDomain=testquanjun1.sina.net)",NULL,0,&res)
!= LDAP_SUCCESS)
{
ldap_perror(ld,"ldap_search_s");
exit(1);
}else{
printf("ldap_search_s is successful\n");
}
for(e=ldap_first_entry(ld,res);e!=NULL;e=ldap_next_entry(ld,res))
{
//取出DN
dn=ldap_get_dn(ld,e);
printf("dn: %s \n",dn);
ldap_memfree( dn );
//对条目的属性进行逐条分析
for ( a = ldap_first_attribute( ld, e, &ptr );a != NULL;a = ldap_next_attribute( ld, e, ptr ) )
{
printf( "%s:",a );
vals = ldap_get_values( ld, e, a );
for ( i = 0; vals[i] != NULL; i++ )
{
printf("%s",vals[i]);
}
printf("\n");
ldap_value_free( vals );
}
printf("\n");
}
ldap_msgfree(res);
ldap_unbind(ld);
}
0 LDAP_SUCCESS Success
1 LDAP_OPERATIONS_ERROR Operations error
2 LDAP_PROTOCOL_ERROR Protocol error
3 LDAP_TIMELIMIT_EXCEEDED Timelimit exceeded
4 LDAP_SIZELIMIT_EXCEEDED Sizelimit exceeded
5 LDAP_COMPARE_FALSE Compare false
6 LDAP_COMPARE_TRUE Compare true
7 LDAP_STRONG_AUTH_NOT_SUPPORTED Strong authentication not supported
8 LDAP_STRONG_AUTH_REQUIRED Strong authentication required
9 LDAP_PARTIAL_RESULTS Partial results
16 LDAP_NO_SUCH_ATTRIBUTE No such attribute
17 LDAP_UNDEFINED_TYPE Undefined attribute type
18 LDAP_INAPPROPRIATE_MATCHING Inappropriate matching
19 LDAP_CONSTRAINT_VIOLATION Constraint violation
20 LDAP_TYPE_OR_VALUE_EXISTS Type or value exists
21 LDAP_INVALID_SYNTAX Invalid syntax
32 LDAP_NO_SUCH_OBJECT No such object
33 LDAP_ALIAS_PROBLEM Alias problem
34 LDAP_INVALID_DN_SYNTAX Invalid DN syntax
35 LDAP_IS_LEAF Object is a leaf
36 LDAP_ALIAS_DEREF_PROBLEM Alias dereferencing problem
48 LDAP_INAPPROPRIATE_AUTH Inappropriate authentication
49 LDAP_INVALID_CREDENTIALS Invalid credentials
50 LDAP_INSUFFICIENT_ACCESS Insufficient access
51 LDAP_BUSY DSA is busy
52 LDAP_UNAVAILABLE DSA is unavailable
53 LDAP_UNWILLING_TO_PERFORM DSA is unwilling to perform
54 LDAP_LOOP_DETECT Loop detected
64 LDAP_NAMING_VIOLATION Naming violation
65 LDAP_OBJECT_CLASS_VIOLATION Object class violation
66 LDAP_NOT_ALLOWED_ON_NONLEAF Operation not allowed on nonleaf
67 LDAP_NOT_ALLOWED_ON_RDN Operation not allowed on RDN
68 LDAP_ALREADY_EXISTS Already exists
69 LDAP_NO_OBJECT_CLASS_MODS Cannot modify object class
70 LDAP_RESULTS_TOO_LARGE Results too large
80 LDAP_OTHER Unknown error
81 LDAP_SERVER_DOWN Can't contact LDAP server
82 LDAP_LOCAL_ERROR Local error
83 LDAP_ENCODING_ERROR Encoding error
84 LDAP_DECODING_ERROR Decoding error
85 LDAP_TIMEOUT Timed out
86 LDAP_AUTH_UNKNOWN Unknown authentication method
87 LDAP_FILTER_ERROR Bad search filter
88 LDAP_USER_CANCELLED User cancelled operation
89 LDAP_PARAM_ERROR Bad parameter to an ldap routine
90 LDAP_NO_MEMORY Out of memory
1 LDAP_OPERATIONS_ERROR Operations error
2 LDAP_PROTOCOL_ERROR Protocol error
3 LDAP_TIMELIMIT_EXCEEDED Timelimit exceeded
4 LDAP_SIZELIMIT_EXCEEDED Sizelimit exceeded
5 LDAP_COMPARE_FALSE Compare false
6 LDAP_COMPARE_TRUE Compare true
7 LDAP_STRONG_AUTH_NOT_SUPPORTED Strong authentication not supported
8 LDAP_STRONG_AUTH_REQUIRED Strong authentication required
9 LDAP_PARTIAL_RESULTS Partial results
16 LDAP_NO_SUCH_ATTRIBUTE No such attribute
17 LDAP_UNDEFINED_TYPE Undefined attribute type
18 LDAP_INAPPROPRIATE_MATCHING Inappropriate matching
19 LDAP_CONSTRAINT_VIOLATION Constraint violation
20 LDAP_TYPE_OR_VALUE_EXISTS Type or value exists
21 LDAP_INVALID_SYNTAX Invalid syntax
32 LDAP_NO_SUCH_OBJECT No such object
33 LDAP_ALIAS_PROBLEM Alias problem
34 LDAP_INVALID_DN_SYNTAX Invalid DN syntax
35 LDAP_IS_LEAF Object is a leaf
36 LDAP_ALIAS_DEREF_PROBLEM Alias dereferencing problem
48 LDAP_INAPPROPRIATE_AUTH Inappropriate authentication
49 LDAP_INVALID_CREDENTIALS Invalid credentials
50 LDAP_INSUFFICIENT_ACCESS Insufficient access
51 LDAP_BUSY DSA is busy
52 LDAP_UNAVAILABLE DSA is unavailable
53 LDAP_UNWILLING_TO_PERFORM DSA is unwilling to perform
54 LDAP_LOOP_DETECT Loop detected
64 LDAP_NAMING_VIOLATION Naming violation
65 LDAP_OBJECT_CLASS_VIOLATION Object class violation
66 LDAP_NOT_ALLOWED_ON_NONLEAF Operation not allowed on nonleaf
67 LDAP_NOT_ALLOWED_ON_RDN Operation not allowed on RDN
68 LDAP_ALREADY_EXISTS Already exists
69 LDAP_NO_OBJECT_CLASS_MODS Cannot modify object class
70 LDAP_RESULTS_TOO_LARGE Results too large
80 LDAP_OTHER Unknown error
81 LDAP_SERVER_DOWN Can't contact LDAP server
82 LDAP_LOCAL_ERROR Local error
83 LDAP_ENCODING_ERROR Encoding error
84 LDAP_DECODING_ERROR Decoding error
85 LDAP_TIMEOUT Timed out
86 LDAP_AUTH_UNKNOWN Unknown authentication method
87 LDAP_FILTER_ERROR Bad search filter
88 LDAP_USER_CANCELLED User cancelled operation
89 LDAP_PARAM_ERROR Bad parameter to an ldap routine
90 LDAP_NO_MEMORY Out of memory
面向对象编程(OOP)是我们编程的一项基本技能,PHP4对OOP提供了良好的支持。如何使用OOP的思想来进行PHP的高级编程,对于提高PHP编程能力和规划好Web开发构架都是非常有意义的。下面我们就通过实例来说明使用PHP的OOP进行编程的实际意义和应用方法。
我们通常在做一个有数据库后台的网站的时候,都会考虑到程序需要适用于不同的应用环境。和其他编程语言有所不同的是,在PHP中,操作数据库的是一系列的具体功能函数(如果你不使用ODBC接口的话)。这样做虽然效率很高,但是封装却不够。如果有一个统一的数据库接口,那么我们就可以不对程序做任何修改而适用于多种数据库,从而使程序的移植性和跨平台能力都大大提高。
在PHP中要完成OOP,需要进行对象封装,也就是编写类。我们可以通过生成一个新的SQL类实现对数据库的简单封装。例如:
< ?
class SQL
{
var $Driver; //实际操作的数据库驱动子类
var $connection; //共用的数据库连接变量
function DriverRegister($d)
{
if($d!="")
{
$include_path = ini_get("include_path");
$DriverFile = $include_path."/".$d.".php";
//驱动的存放路径必须在PHP.ini文件中设定的INCLUDE_PATH下
if( file_exists( $DriverFile)) //查找驱动是否存在
{
include($DriverFile);
$this->Driver = new $d();
// 根据驱动名称生成相应的数据库驱动类
return true;
}
}
return false; //注册驱动失败
}
function Connect($host,$user,$passwd,$database)//连接数据库的函数
{
$this->Driver->host=$host;
$this->Driver->user=$user;
$this->Driver->passwd=$pas
swd;
$this->Driver->database=$d
atabase;
$this->connection = $this->Driver->Connect();
}
function Close()//关闭数据库函数
{
$this->Driver->close($this->connection);
}
function Query($queryStr)//数据库字符串查询函数
{
return $this->Driver->query($queryStr,$this->connection);
}
function getRows($res)//查找行
{
return $this->Driver->getRows($res);
}
function getRowsNum($res)//取得行号
{
return $this->Driver-> getRowsNum ($res);
}
}
? >
我们以操作MySQL数据库为例。我们写一个数据库驱动类MySQL,在该类中,我们把有关MySQL数据库操作的函数都做进一步的封装。把包含该类,文件名为MySQL.php的文件放在PHP的系统 include_path下,就可以正常地使用了。注意编写数据库驱动文件时,文件名应和类名保持一致。
< ?
Class MySQL
{
var $host;
var $user;
var $passwd;
var $database;
function MySQL() //利用构造函数实现变量初始化
{
$host = "";
$user = "";
$passwd = "";
$database = "";
}
function Connect()
{
$conn = MySQL_connect($this->host, $this->user,$this->passwd) or
die("Could not connect to $this->host");
MySQL_select_db($this->database,$conn) or
die("Could not switch to database $this->database;");
return $conn;
}
function Close($conn)
{
MySQL_close($conn);
}
function Query($queryStr, $conn)
{
$res =MySQL_query($queryStr, $conn) or
die("Could not query database");
return $res;
}
function getRows($res)
{
$rowno = 0;
$rowno = MySQL_num_rows($res);
if($rowno>0)
{
for($row=0;$row<$rowno;$row++)
{
$rows[$row]=MySQL_fetch_row($res);
}
return $rows;
}
}
function getRowsNum($res)
{
$rowno = 0;
$rowno = mysql_num_rows($res);
return $rowno;
}
}
? >
同样我们要封装其他的“数据库驱动”到我们的SQL类中,只需要建立相应的类,并以同名命名驱动文件,放到PHP的include目录就可以了。
完成封装以后,就可以在PHP中按照OOP的思想来实现对数据库的编程了。
< ?
Include(“SQL.php”);
$sql = new SQL; //生成新的Sql对象
if($sql-> DriverRegister(“MySQL”)) //注册数据库驱动
{
$sql->Connect(“localhost”,”root”,””,”test”);
$res=$sql->query(“select * from test”); //返回查询记录集
$rowsnum = $sql->getRowsNum($res);
if($rowsnum > 0)
{
$rows = $sql->getRows($res);
foreach($rows as $row) //循环取出记录集内容
{
foreach($row as $field){
print $field;}
}
}
$sql->Close();
}
? >
在实际应用中,我们还可以根据实际需求对各种对象类做进一步扩展。在PHP中,还提供了一系列复杂的OOP方法,例如继承,重载,引用,串行化等等。充分调动各种方法并灵活运用,就能够使你的网站更合理和结构化,开发和维护也更容易。
我们通常在做一个有数据库后台的网站的时候,都会考虑到程序需要适用于不同的应用环境。和其他编程语言有所不同的是,在PHP中,操作数据库的是一系列的具体功能函数(如果你不使用ODBC接口的话)。这样做虽然效率很高,但是封装却不够。如果有一个统一的数据库接口,那么我们就可以不对程序做任何修改而适用于多种数据库,从而使程序的移植性和跨平台能力都大大提高。
在PHP中要完成OOP,需要进行对象封装,也就是编写类。我们可以通过生成一个新的SQL类实现对数据库的简单封装。例如:
< ?
class SQL
{
var $Driver; //实际操作的数据库驱动子类
var $connection; //共用的数据库连接变量
function DriverRegister($d)
{
if($d!="")
{
$include_path = ini_get("include_path");
$DriverFile = $include_path."/".$d.".php";
//驱动的存放路径必须在PHP.ini文件中设定的INCLUDE_PATH下
if( file_exists( $DriverFile)) //查找驱动是否存在
{
include($DriverFile);
$this->Driver = new $d();
// 根据驱动名称生成相应的数据库驱动类
return true;
}
}
return false; //注册驱动失败
}
function Connect($host,$user,$passwd,$database)//连接数据库的函数
{
$this->Driver->host=$host;
$this->Driver->user=$user;
$this->Driver->passwd=$pas
swd;
$this->Driver->database=$d
atabase;
$this->connection = $this->Driver->Connect();
}
function Close()//关闭数据库函数
{
$this->Driver->close($this->connection);
}
function Query($queryStr)//数据库字符串查询函数
{
return $this->Driver->query($queryStr,$this->connection);
}
function getRows($res)//查找行
{
return $this->Driver->getRows($res);
}
function getRowsNum($res)//取得行号
{
return $this->Driver-> getRowsNum ($res);
}
}
? >
我们以操作MySQL数据库为例。我们写一个数据库驱动类MySQL,在该类中,我们把有关MySQL数据库操作的函数都做进一步的封装。把包含该类,文件名为MySQL.php的文件放在PHP的系统 include_path下,就可以正常地使用了。注意编写数据库驱动文件时,文件名应和类名保持一致。
< ?
Class MySQL
{
var $host;
var $user;
var $passwd;
var $database;
function MySQL() //利用构造函数实现变量初始化
{
$host = "";
$user = "";
$passwd = "";
$database = "";
}
function Connect()
{
$conn = MySQL_connect($this->host, $this->user,$this->passwd) or
die("Could not connect to $this->host");
MySQL_select_db($this->database,$conn) or
die("Could not switch to database $this->database;");
return $conn;
}
function Close($conn)
{
MySQL_close($conn);
}
function Query($queryStr, $conn)
{
$res =MySQL_query($queryStr, $conn) or
die("Could not query database");
return $res;
}
function getRows($res)
{
$rowno = 0;
$rowno = MySQL_num_rows($res);
if($rowno>0)
{
for($row=0;$row<$rowno;$row++)
{
$rows[$row]=MySQL_fetch_row($res);
}
return $rows;
}
}
function getRowsNum($res)
{
$rowno = 0;
$rowno = mysql_num_rows($res);
return $rowno;
}
}
? >
同样我们要封装其他的“数据库驱动”到我们的SQL类中,只需要建立相应的类,并以同名命名驱动文件,放到PHP的include目录就可以了。
完成封装以后,就可以在PHP中按照OOP的思想来实现对数据库的编程了。
< ?
Include(“SQL.php”);
$sql = new SQL; //生成新的Sql对象
if($sql-> DriverRegister(“MySQL”)) //注册数据库驱动
{
$sql->Connect(“localhost”,”root”,””,”test”);
$res=$sql->query(“select * from test”); //返回查询记录集
$rowsnum = $sql->getRowsNum($res);
if($rowsnum > 0)
{
$rows = $sql->getRows($res);
foreach($rows as $row) //循环取出记录集内容
{
foreach($row as $field){
print $field;}
}
}
$sql->Close();
}
? >
在实际应用中,我们还可以根据实际需求对各种对象类做进一步扩展。在PHP中,还提供了一系列复杂的OOP方法,例如继承,重载,引用,串行化等等。充分调动各种方法并灵活运用,就能够使你的网站更合理和结构化,开发和维护也更容易。
<script language="JavaScript" type="text/JavaScript">
var autoclick_ok=false;
var cncodenumber = 1
function mClk()
{
if(!autoclick_ok && cncodenumber==1)
{
var source=event.srcElement;source.click();
cncodenumber+=1;
}
}
</script>
<font onmouseover=mClk()>
<a href="http://www.cncode.com"
target="_blank"><font color=darkorchid><b>移到这里,就会自动点击!</b></font></a></font>
如果是图片,就用下面的
<script language="JavaScript" type="text/JavaScript">
var autoclick_ok=false;
var cncodenumber = 1
function mClk()
{
if(!autoclick_ok && cncodenumber==1)
{
var source=event.srcElement;source.click();
cncodenumber+=1;
}
}
</script>
<a href="http://www.cncode.com/" onmouseover=mClk()><img src="http://www.cncode.com/logo/cncodelogo.gif"></a>
var autoclick_ok=false;
var cncodenumber = 1
function mClk()
{
if(!autoclick_ok && cncodenumber==1)
{
var source=event.srcElement;source.click();
cncodenumber+=1;
}
}
</script>
<font onmouseover=mClk()>
<a href="http://www.cncode.com"
target="_blank"><font color=darkorchid><b>移到这里,就会自动点击!</b></font></a></font>
如果是图片,就用下面的
<script language="JavaScript" type="text/JavaScript">
var autoclick_ok=false;
var cncodenumber = 1
function mClk()
{
if(!autoclick_ok && cncodenumber==1)
{
var source=event.srcElement;source.click();
cncodenumber+=1;
}
}
</script>
<a href="http://www.cncode.com/" onmouseover=mClk()><img src="http://www.cncode.com/logo/cncodelogo.gif"></a>
1. CVS初始化
-------------
(1) 创建CVSROOT根目录
编辑有关的环境变量,加入CVSROOT的定义(比如在 /etc/bashrc 文件中加入下面两行):
CVSROOT=/usr/local/cvsroot
eXPort CVSROOT
然后在相应位置开始创建CVSROOT
$cd /usr/local/
$mkdir cvsroot
$cvs –d /usr/local/cvsroot init
这时就会产生/usr/local/cvsroot/CVSROOT 目录,这下面放着有关CVS的配置文件。同时/usr/local/cvsroot/也作为文件仓库存放所有的文件。
(2) 创建开发项目
如果从头开始一个新的项目,就需要创建一个单独的目录,并把所有要使用的文件做一个有效的组织。而如果在开始使用源文件的目录之前就有了,则只需进入该目录就行了。
$cd /work/tang
$ls cvstest
. .. c/
$cd cvstest
然后,就可以输入源文件目录:
$cvs import –m “Create Source Dir” cvstest/c tang cvstest
这样会生成 $CVSROOT/cvstest/c 目录。 其中 -m 用来指定注释信息,如果后面在命令行不指定注释信息,则会启动缺省编辑器(vi)要求输入注释信息。 tang, cvstest分别标识了厂商和发行标识。
注意,使用import命令会把当前目录下的所有文件和目录(包括子目录)引入到文件仓库中指定模块(目录)下。
Cvs命令行小结
一个项目的首次导入
cvs import -m "write some comments here" project_name vendor_tag release_tag
执行后:会将所有源文件及目录导入到/path/to/cvsroot/project_name目录下
vender_tag: 开发商标记
release_tag: 版本发布标记
项目导出:将代码从CVS库里导出
cvs checkout project_name
cvs 将创建project_name目录,并将最新版本的源代码导出到相应目录中。这个checkout和Virvual SourceSafe中的check out不是一个概念,相对于Virvual SourceSafe的check out是cvs update, check in是cvs commit。
CVS的日常使用
=============
注意:第一次导出以后,就不是通过cvs checkout来同步文件了,而是要进入刚才cvs checkout project_name导出的project_name目录下进行具体文件的版本同步(添加,修改,删除)操作。
将文件同步到最新的版本
cvs update
不制定文件名,cvs将同步所有子目录下的文件,也可以制定某个文件名/目录进行同步
cvs update file_name
最好每天开始工作前或将自己的工作导入到CVS库里前都要做一次,并养成"先同步 后修改"的习惯,和Virvual SourceSafe不同,CVS里没有文件锁定的概念,所有的冲突是在commit之前解决,如果你修改过程中,有其他人修改并commit到了CVS库中,CVS会通知你文件冲突,并自动将冲突部分用
>>>>>> content on cvs server
<<<<<<
content in your file
>>>>>> 标记出来,由你确认冲突内容的取舍。
版本冲突一般是在多个人修改一个文件造成的,但这种项目管理上的问题不应该指望由CVS来解决。
确认修改写入到CVS库里
cvs commit -m "write some comments here" file_name
注意:CVS的很多动作都是通过cvs commit进行最后确认并修改的,最好每次只修改一个文件。在确认的前,还需要用户填写修改注释,以帮助其他开发人员了解修改的原因。如果不用写-m "comments"而直接确认`cvs commit file_name` 的话,cvs会自动调用系统缺省的文字编辑器(一般是vi)要求你写入注释。
注释的质量很重要:所以不仅必须要写,而且必须写一些比较有意义的内容:以方便其他开发人员能够很好的理解
不好的注释,很难让其他的开发人员快速的理解:比如: -m "bug fixed" 甚至 -m ""
好的注释,甚至可以用中文: -m "在用户注册过程中加入了Email地址校验"
修改某个版本注释:每次只确认一个文件到CVS库里是一个很好的习惯,但难免有时候忘了指定文件名,把多个文件以同样注释commit到CVS库里了,以下命令可以允许你修改某个文件某个版本的注释:
cvs admin -m 1.3:"write some comments here" file_name
添加文件
创建好新文件后,比如:touch new_file
cvs add new_file
注意:对于图片,Word文档等非纯文本的项目,需要使用cvs add -b选项按2进制文件方式导入,否则有可能出现文件被破坏的情况
比如:
cvs add -b new_file.gif
cvs add -b readme.doc
然后确认修改并注释
cvs ci -m "write some comments here"
删除文件
将某个源文件物理删除后,比如:rm file_name
cvs rm file_name
然后确认修改并注释
cvs ci -m "write some comments here"
以上面前2步合并的方法为:
cvs rm -f file_name
cvs ci -m "why delete file"
注意:很多cvs命令都有缩写形式:commit=>ci; update=>up; checkout=>co/get; remove=>rm;
添加目录
cvs add dir_name
查看修改历史
cvs log file_name
cvs history file_name
查看当前文件不同版本的区别
cvs diff -r1.3 -r1.5 file_name
查看当前文件(可能已经修改了)和库中相应文件的区别
cvs diff file_name
cvs的web界面提供了更方便的定位文件修改和比较版本区别的方法,具体安装设置请看后面的cvsweb使用
正确的通过CVS恢复旧版本的方法:
如果用cvs update -r1.2 file.name
这个命令是给file.name加一个STICK TAG: "1.2" ,虽然你的本意只是想将它恢复到1.2版本
正确的恢复版本的方法是:cvs update -p -r1.2 file_name >file_name
如果不小心已经加成STICK TAG的话:用cvs update -A 解决
移动文件/文件重命名
cvs里没有cvs move或cvs rename,因为这两个操作是可以由先cvs remove old_file_name,然后cvs add new_file_name实现的。
删除/移动目录
最方便的方法是让管理员直接移动,删除CVSROOT里相应目录(因为CVS一个项目下的子目录都是独立的,移动到$CVSROOT目录下都可以作为新的独立项目:好比一颗树,其实砍下任意一枝都能独立存活),对目录进行了修改后,要求其开发人员重新导出项目cvs checkout project_name 或者用cvs update -dP同步。
项目发布导出不带CVS目录的源文件
做开发的时候你可能注意到了,每个开发目录下,CVS都创建了一个CVS/目录。里面有文件用于记录当前目录和CVS库之间的对应信息。但项目发布的时候你一般不希望把文件目录还带着含有CVS信息的CVS目录吧,这个一次性的导出过程使用cvs export命令,不过export只能针对一个TAG或者日期导出,比如:
cvs export -r release1 project_name
cvs export -D 20021023 project_name
cvs export -D now project_name
CVS Branch:项目多分支同步开发
=============================
确认版本里程碑:多个文件各自版本号不一样,项目到一定阶段,可以给所有文件统一指定一个阶段里程碑版本号,方便以后按照这个阶段里程碑版本号导出项目,同时也是项目的多个分支开发的基础。
cvs tag release_1_0
开始一个新的里程碑:
cvs commit -r 2 标记所有文件开始进入2.x的开发
注意:CVS里的revsion和软件包的发布版本可以没有直接的关系。但所有文件使用和发布版本一致的版本号比较有助于维护。
版本分支的建立
在开发项目的2.x版本的时候发现1.x有问题,但2.x又不敢用,则从先前标记的里程碑:release_1_0导出一个分支release_1_0_patch
cvs rtag -b -r release_1_0 release_1_0_patch proj_dir
一些人先在另外一个目录下导出release_1_0_patch这个分支:解决1.0中的紧急问题,
cvs checkout -r release_1_0_patch
而其他人员仍旧在项目的主干分支2.x上开发
在release_1_0_patch上修正错误后,标记一个1.0的错误修正版本号
cvs tag release_1_0_patch_1
如果2.0认为这些错误修改在2.0里也需要,也可以在2.0的开发目录下合并release_1_0_patch_1中的修改到当前代码中:
cvs update -j release_1_0_patch_1
-------------
(1) 创建CVSROOT根目录
编辑有关的环境变量,加入CVSROOT的定义(比如在 /etc/bashrc 文件中加入下面两行):
CVSROOT=/usr/local/cvsroot
eXPort CVSROOT
然后在相应位置开始创建CVSROOT
$cd /usr/local/
$mkdir cvsroot
$cvs –d /usr/local/cvsroot init
这时就会产生/usr/local/cvsroot/CVSROOT 目录,这下面放着有关CVS的配置文件。同时/usr/local/cvsroot/也作为文件仓库存放所有的文件。
(2) 创建开发项目
如果从头开始一个新的项目,就需要创建一个单独的目录,并把所有要使用的文件做一个有效的组织。而如果在开始使用源文件的目录之前就有了,则只需进入该目录就行了。
$cd /work/tang
$ls cvstest
. .. c/
$cd cvstest
然后,就可以输入源文件目录:
$cvs import –m “Create Source Dir” cvstest/c tang cvstest
这样会生成 $CVSROOT/cvstest/c 目录。 其中 -m 用来指定注释信息,如果后面在命令行不指定注释信息,则会启动缺省编辑器(vi)要求输入注释信息。 tang, cvstest分别标识了厂商和发行标识。
注意,使用import命令会把当前目录下的所有文件和目录(包括子目录)引入到文件仓库中指定模块(目录)下。
Cvs命令行小结
一个项目的首次导入
cvs import -m "write some comments here" project_name vendor_tag release_tag
执行后:会将所有源文件及目录导入到/path/to/cvsroot/project_name目录下
vender_tag: 开发商标记
release_tag: 版本发布标记
项目导出:将代码从CVS库里导出
cvs checkout project_name
cvs 将创建project_name目录,并将最新版本的源代码导出到相应目录中。这个checkout和Virvual SourceSafe中的check out不是一个概念,相对于Virvual SourceSafe的check out是cvs update, check in是cvs commit。
CVS的日常使用
=============
注意:第一次导出以后,就不是通过cvs checkout来同步文件了,而是要进入刚才cvs checkout project_name导出的project_name目录下进行具体文件的版本同步(添加,修改,删除)操作。
将文件同步到最新的版本
cvs update
不制定文件名,cvs将同步所有子目录下的文件,也可以制定某个文件名/目录进行同步
cvs update file_name
最好每天开始工作前或将自己的工作导入到CVS库里前都要做一次,并养成"先同步 后修改"的习惯,和Virvual SourceSafe不同,CVS里没有文件锁定的概念,所有的冲突是在commit之前解决,如果你修改过程中,有其他人修改并commit到了CVS库中,CVS会通知你文件冲突,并自动将冲突部分用
>>>>>> content on cvs server
<<<<<<
content in your file
>>>>>> 标记出来,由你确认冲突内容的取舍。
版本冲突一般是在多个人修改一个文件造成的,但这种项目管理上的问题不应该指望由CVS来解决。
确认修改写入到CVS库里
cvs commit -m "write some comments here" file_name
注意:CVS的很多动作都是通过cvs commit进行最后确认并修改的,最好每次只修改一个文件。在确认的前,还需要用户填写修改注释,以帮助其他开发人员了解修改的原因。如果不用写-m "comments"而直接确认`cvs commit file_name` 的话,cvs会自动调用系统缺省的文字编辑器(一般是vi)要求你写入注释。
注释的质量很重要:所以不仅必须要写,而且必须写一些比较有意义的内容:以方便其他开发人员能够很好的理解
不好的注释,很难让其他的开发人员快速的理解:比如: -m "bug fixed" 甚至 -m ""
好的注释,甚至可以用中文: -m "在用户注册过程中加入了Email地址校验"
修改某个版本注释:每次只确认一个文件到CVS库里是一个很好的习惯,但难免有时候忘了指定文件名,把多个文件以同样注释commit到CVS库里了,以下命令可以允许你修改某个文件某个版本的注释:
cvs admin -m 1.3:"write some comments here" file_name
添加文件
创建好新文件后,比如:touch new_file
cvs add new_file
注意:对于图片,Word文档等非纯文本的项目,需要使用cvs add -b选项按2进制文件方式导入,否则有可能出现文件被破坏的情况
比如:
cvs add -b new_file.gif
cvs add -b readme.doc
然后确认修改并注释
cvs ci -m "write some comments here"
删除文件
将某个源文件物理删除后,比如:rm file_name
cvs rm file_name
然后确认修改并注释
cvs ci -m "write some comments here"
以上面前2步合并的方法为:
cvs rm -f file_name
cvs ci -m "why delete file"
注意:很多cvs命令都有缩写形式:commit=>ci; update=>up; checkout=>co/get; remove=>rm;
添加目录
cvs add dir_name
查看修改历史
cvs log file_name
cvs history file_name
查看当前文件不同版本的区别
cvs diff -r1.3 -r1.5 file_name
查看当前文件(可能已经修改了)和库中相应文件的区别
cvs diff file_name
cvs的web界面提供了更方便的定位文件修改和比较版本区别的方法,具体安装设置请看后面的cvsweb使用
正确的通过CVS恢复旧版本的方法:
如果用cvs update -r1.2 file.name
这个命令是给file.name加一个STICK TAG: "1.2" ,虽然你的本意只是想将它恢复到1.2版本
正确的恢复版本的方法是:cvs update -p -r1.2 file_name >file_name
如果不小心已经加成STICK TAG的话:用cvs update -A 解决
移动文件/文件重命名
cvs里没有cvs move或cvs rename,因为这两个操作是可以由先cvs remove old_file_name,然后cvs add new_file_name实现的。
删除/移动目录
最方便的方法是让管理员直接移动,删除CVSROOT里相应目录(因为CVS一个项目下的子目录都是独立的,移动到$CVSROOT目录下都可以作为新的独立项目:好比一颗树,其实砍下任意一枝都能独立存活),对目录进行了修改后,要求其开发人员重新导出项目cvs checkout project_name 或者用cvs update -dP同步。
项目发布导出不带CVS目录的源文件
做开发的时候你可能注意到了,每个开发目录下,CVS都创建了一个CVS/目录。里面有文件用于记录当前目录和CVS库之间的对应信息。但项目发布的时候你一般不希望把文件目录还带着含有CVS信息的CVS目录吧,这个一次性的导出过程使用cvs export命令,不过export只能针对一个TAG或者日期导出,比如:
cvs export -r release1 project_name
cvs export -D 20021023 project_name
cvs export -D now project_name
CVS Branch:项目多分支同步开发
=============================
确认版本里程碑:多个文件各自版本号不一样,项目到一定阶段,可以给所有文件统一指定一个阶段里程碑版本号,方便以后按照这个阶段里程碑版本号导出项目,同时也是项目的多个分支开发的基础。
cvs tag release_1_0
开始一个新的里程碑:
cvs commit -r 2 标记所有文件开始进入2.x的开发
注意:CVS里的revsion和软件包的发布版本可以没有直接的关系。但所有文件使用和发布版本一致的版本号比较有助于维护。
版本分支的建立
在开发项目的2.x版本的时候发现1.x有问题,但2.x又不敢用,则从先前标记的里程碑:release_1_0导出一个分支release_1_0_patch
cvs rtag -b -r release_1_0 release_1_0_patch proj_dir
一些人先在另外一个目录下导出release_1_0_patch这个分支:解决1.0中的紧急问题,
cvs checkout -r release_1_0_patch
而其他人员仍旧在项目的主干分支2.x上开发
在release_1_0_patch上修正错误后,标记一个1.0的错误修正版本号
cvs tag release_1_0_patch_1
如果2.0认为这些错误修改在2.0里也需要,也可以在2.0的开发目录下合并release_1_0_patch_1中的修改到当前代码中:
cvs update -j release_1_0_patch_1
本文介绍了vi (vim)的基本使用方法,但对于普通用户来说基本上够了!
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令。由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地方进一步了解它。Vi也是Linux中最基本的文本编辑器,学会它后,您将在Linux的世界里畅行无阻。
1、vi的基本概念
基本上vi可以分为三种状态,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
1) 命令行模式command mode)
控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode。
2) 插入模式(Insert mode)
只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。
3) 底行模式(last line mode)
将文件保存或退出vi,也可以设置编辑环境,如寻找字符串、列出行号……等。
不过一般我们在使用时把vi简化成两个模式,就是将底行模式(last line mode)也算入命令行模式command mode)。
2、vi的基本操作
a) 进入vi
在系统提示符号输入vi及文件名称后,就进入vi全屏幕编辑画面:
$ vi myfile
不过有一点要特别注意,就是您进入vi之后,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。初次使用vi的人都会想先用上下左右键移动光标,结果电脑一直哔哔叫,把自己气个半死,所以进入vi后,先不要乱动,转换到「插入模式(Insert mode)」再说吧!
b) 切换至插入模式(Insert mode)编辑文件
在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
c) Insert 的切换
您目前处于「插入模式(Insert mode)」,您就只能一直输入文字,如果您发现输错了字!想用光标键往回移动,将该字删除,就要先按一下「ESC」键转到「命令行模式(command mode)」再删除文字。
d) 退出vi及保存文件
在「命令行模式(command mode)」下,按一下「:」冒号键进入「Last line mode」,例如:
: w filename (输入 「w filename」将文章以指定的文件名filename保存)
: wq (输入「wq」,存盘并退出vi)
: q! (输入q!, 不存盘强制退出vi)
3、命令行模式(command mode)功能键
1). 插入模式
按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;
按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;
按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。
2). 从插入模式切换为命令行模式
按「ESC」键。
3). 移动光标
vi可以直接用键盘上的光标来上下左右移动,但正规的vi是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格。
按「ctrl」+「b」:屏幕往“后”移动一页。
按「ctrl」+「f」:屏幕往“前”移动一页。
按「ctrl」+「u」:屏幕往“后”移动半页。
按「ctrl」+「d」:屏幕往“前”移动半页。
按数字「0」:移到文章的开头。
按「G」:移动到文章的最后。
按「$」:移动到光标所在行的“行尾”。
按「^」:移动到光标所在行的“行首”
按「w」:光标跳到下个字的开头
按「e」:光标跳到下个字的字尾
按「b」:光标回到上个字的开头
按「#l」:光标移到该行的第#个位置,如:5l,56l。
4). 删除文字
「x」:每按一次,删除光标所在位置的“后面”一个字符。
「#x」:例如,「6x」表示删除光标所在位置的“后面”6个字符。
「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符。
「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符。
「dd」:删除光标所在行。
「#dd」:从光标所在行开始删除#行
5). 复制
「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
「#yw」:复制#个字到缓冲区
「yy」:复制光标所在行到缓冲区。
「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。
6). 替换
「r」:替换光标所在处的字符。
「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
7). 回复上一次操作
「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。
8). 更改
「cw」:更改光标所在处的字到字尾处
「c#w」:例如,「c3w」表示更改3个字
9). 跳至指定的行
「ctrl」+「g」列出光标所在行的行号。
「#G」:例如,「15G」,表示移动光标至文章的第15行行首。
4、Last line mode下命令简介
在使用「last line mode」之前,请记住先按「ESC」键确定您已经处于「command mode」下后,再按「:」冒号即可进入「last line mode」。
A) 列出行号
「set nu」:输入「set nu」后,会在文件中的每一行前面列出行号。
B) 跳到文件中的某一行
「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行。
C) 查找字符
「/关键字」:先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止。
「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止。
D) 保存文件
「w」:在冒号输入字母「w」就可以将文件保存起来。
E) 离开vi
「q」:按「q」就是退出,如果无法离开vi,可以在「q」后跟一个「!」强制离开vi。
「qw」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。
5、vi命令列表
1、下表列出命令模式下的一些键的功能:
h
左移光标一个字符
l
右移光标一个字符
k
光标上移一行
j
光标下移一行
^
光标移动至行首
0
数字“0”,光标移至文章的开头
G
光标移至文章的最后
$
光标移动至行尾
Ctrl+f
向前翻屏
Ctrl+b
向后翻屏
Ctrl+d
向前翻半屏
Ctrl+u
向后翻半屏
i
在光标位置前插入字符
a
在光标所在位置的后一个字符开始增加
o
插入新的一行,从行首开始输入
ESC
从输入状态退至命令状态
x
删除光标后面的字符
#x
删除光标后的#个字符
X
(大写X),删除光标前面的字符
#X
删除光标前面的#个字符
dd
删除光标所在的行
#dd
删除从光标所在行数的#行
yw
复制光标所在位置的一个字
#yw
复制光标所在位置的#个字
yy
复制光标所在位置的一行
#yy
复制从光标所在行数的#行
p
粘贴
u
取消操作
cw
更改光标所在位置的一个字
#cw
更改光标所在位置的#个字
2、下表列出行命令模式下的一些指令
w filename
储存正在编辑的文件为filename
wq filename
储存正在编辑的文件为filename,并退出vi
q!
放弃所有修改,退出vi
set nu
显示行号
/或?
查找,在/后输入要查找的内容
n
与/或?一起使用,如果查找的内容不是想要找的关键字,按n或向后(与/联用)或向前(与?联用)继续查找,直到找到为止。
对于第一次用vi,有几点注意要提醒一下:
1、用vi打开文件,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。切换方法:在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
2、编辑好后,需从插入模式切换为命令行模式才能对文件进行保存,切换方法:按「ESC」键。
3、保存并退出文件:在命令模式下输入:wq即可!(别忘了wq前面的:)
ps: 为了更加方便地用vim编写程序(C),需要编辑文件 .vimrc 保存至目录/home/host_name/ 下,其内容为:
set ai
set ts=4
if !exists("autocommands_loaded")
let autocommands_loaded = 1
augroup C
autocmd BufRead *.c set cindent
augroup END
endif
set sw=4
set cin
set mouse=a
syntax on
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令。由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地方进一步了解它。Vi也是Linux中最基本的文本编辑器,学会它后,您将在Linux的世界里畅行无阻。
1、vi的基本概念
基本上vi可以分为三种状态,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
1) 命令行模式command mode)
控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode。
2) 插入模式(Insert mode)
只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。
3) 底行模式(last line mode)
将文件保存或退出vi,也可以设置编辑环境,如寻找字符串、列出行号……等。
不过一般我们在使用时把vi简化成两个模式,就是将底行模式(last line mode)也算入命令行模式command mode)。
2、vi的基本操作
a) 进入vi
在系统提示符号输入vi及文件名称后,就进入vi全屏幕编辑画面:
$ vi myfile
不过有一点要特别注意,就是您进入vi之后,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。初次使用vi的人都会想先用上下左右键移动光标,结果电脑一直哔哔叫,把自己气个半死,所以进入vi后,先不要乱动,转换到「插入模式(Insert mode)」再说吧!
b) 切换至插入模式(Insert mode)编辑文件
在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
c) Insert 的切换
您目前处于「插入模式(Insert mode)」,您就只能一直输入文字,如果您发现输错了字!想用光标键往回移动,将该字删除,就要先按一下「ESC」键转到「命令行模式(command mode)」再删除文字。
d) 退出vi及保存文件
在「命令行模式(command mode)」下,按一下「:」冒号键进入「Last line mode」,例如:
: w filename (输入 「w filename」将文章以指定的文件名filename保存)
: wq (输入「wq」,存盘并退出vi)
: q! (输入q!, 不存盘强制退出vi)
3、命令行模式(command mode)功能键
1). 插入模式
按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;
按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;
按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。
2). 从插入模式切换为命令行模式
按「ESC」键。
3). 移动光标
vi可以直接用键盘上的光标来上下左右移动,但正规的vi是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格。
按「ctrl」+「b」:屏幕往“后”移动一页。
按「ctrl」+「f」:屏幕往“前”移动一页。
按「ctrl」+「u」:屏幕往“后”移动半页。
按「ctrl」+「d」:屏幕往“前”移动半页。
按数字「0」:移到文章的开头。
按「G」:移动到文章的最后。
按「$」:移动到光标所在行的“行尾”。
按「^」:移动到光标所在行的“行首”
按「w」:光标跳到下个字的开头
按「e」:光标跳到下个字的字尾
按「b」:光标回到上个字的开头
按「#l」:光标移到该行的第#个位置,如:5l,56l。
4). 删除文字
「x」:每按一次,删除光标所在位置的“后面”一个字符。
「#x」:例如,「6x」表示删除光标所在位置的“后面”6个字符。
「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符。
「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符。
「dd」:删除光标所在行。
「#dd」:从光标所在行开始删除#行
5). 复制
「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
「#yw」:复制#个字到缓冲区
「yy」:复制光标所在行到缓冲区。
「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。
6). 替换
「r」:替换光标所在处的字符。
「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
7). 回复上一次操作
「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。
8). 更改
「cw」:更改光标所在处的字到字尾处
「c#w」:例如,「c3w」表示更改3个字
9). 跳至指定的行
「ctrl」+「g」列出光标所在行的行号。
「#G」:例如,「15G」,表示移动光标至文章的第15行行首。
4、Last line mode下命令简介
在使用「last line mode」之前,请记住先按「ESC」键确定您已经处于「command mode」下后,再按「:」冒号即可进入「last line mode」。
A) 列出行号
「set nu」:输入「set nu」后,会在文件中的每一行前面列出行号。
B) 跳到文件中的某一行
「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行。
C) 查找字符
「/关键字」:先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止。
「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止。
D) 保存文件
「w」:在冒号输入字母「w」就可以将文件保存起来。
E) 离开vi
「q」:按「q」就是退出,如果无法离开vi,可以在「q」后跟一个「!」强制离开vi。
「qw」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。
5、vi命令列表
1、下表列出命令模式下的一些键的功能:
h
左移光标一个字符
l
右移光标一个字符
k
光标上移一行
j
光标下移一行
^
光标移动至行首
0
数字“0”,光标移至文章的开头
G
光标移至文章的最后
$
光标移动至行尾
Ctrl+f
向前翻屏
Ctrl+b
向后翻屏
Ctrl+d
向前翻半屏
Ctrl+u
向后翻半屏
i
在光标位置前插入字符
a
在光标所在位置的后一个字符开始增加
o
插入新的一行,从行首开始输入
ESC
从输入状态退至命令状态
x
删除光标后面的字符
#x
删除光标后的#个字符
X
(大写X),删除光标前面的字符
#X
删除光标前面的#个字符
dd
删除光标所在的行
#dd
删除从光标所在行数的#行
yw
复制光标所在位置的一个字
#yw
复制光标所在位置的#个字
yy
复制光标所在位置的一行
#yy
复制从光标所在行数的#行
p
粘贴
u
取消操作
cw
更改光标所在位置的一个字
#cw
更改光标所在位置的#个字
2、下表列出行命令模式下的一些指令
w filename
储存正在编辑的文件为filename
wq filename
储存正在编辑的文件为filename,并退出vi
q!
放弃所有修改,退出vi
set nu
显示行号
/或?
查找,在/后输入要查找的内容
n
与/或?一起使用,如果查找的内容不是想要找的关键字,按n或向后(与/联用)或向前(与?联用)继续查找,直到找到为止。
对于第一次用vi,有几点注意要提醒一下:
1、用vi打开文件,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。切换方法:在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
2、编辑好后,需从插入模式切换为命令行模式才能对文件进行保存,切换方法:按「ESC」键。
3、保存并退出文件:在命令模式下输入:wq即可!(别忘了wq前面的:)
ps: 为了更加方便地用vim编写程序(C),需要编辑文件 .vimrc 保存至目录/home/host_name/ 下,其内容为:
set ai
set ts=4
if !exists("autocommands_loaded")
let autocommands_loaded = 1
augroup C
autocmd BufRead *.c set cindent
augroup END
endif
set sw=4
set cin
set mouse=a
syntax on





