指针也一个变量,只是存放的是地址,地址是操作系统随机分配的。*p是指指向这个地址的内容。指针向的内容必须和指针的类型一样。
注:切记不要讲一个整数直接赋值给指针,因为这样会出现未知的错误。也不要使用野指针(就是指向无效的地址),避免野指针的方法,定义的时候就赋一个初值;或者指向一个null(其实就是0)。
无类型指针:void*p;如果定义的时候不确定使用指针的类型。任何一种类型都可以给void类型的指针赋值,但是不一定意思是正确的。
指针的赋值:不同类型的指针不可以相互赋值。
指针常量与指向常量的指针:const int*p指向常量的指针是指不能通过*p的方式改变存储器的值,但是指向什么是可以变化的;int*const p指针常量,是指不能改变指向的值,但是可以通过*p改变存储器的值。
指针与数组:指针和数组代表的都是地址;虽然使用指针和数组是一样的,但是sizeof的时候,大小是不一样的,在相同的操作系统当中,不管指针指向的存储器是什么类型,指针本身的大小是不变的,32为操作系统都是4个位元组来表达的。
指针的运算:移动的位数和指针的类型相关,p+=5位移sizeof(int)*5个位元组,如果char p1=(char*)buf,p1++的话,位移sizeof(char)*5个位元组;p1++是移动一个字节,0x12345678输出的值是56,存储器是存放是小端对齐,和硬件相关。注:Buf++是不可以这样的,数组的名称是不可以直接作为左值的,因为数组的名称只是代表一个地址,但不是一个变量。
指针数组:数组中的元素全是指针,eg:int*p[5],sizeof(p)=20不管什么类型的都是一样的。
指针的指针:就是代表指针的地址。Int**pp=&p;使用**pp++来操作i的值,多级的指针以此类推。环状指针:P=(int*)pppp;****pppp代表自己;
P=(int*)&pppp;****pppp代表指向自己的地址。
指向二维数组的指针:int buf[2][3],buf[0]代表的是第一行数组的名称,sizeof(buf[0])是12。Int*p[5]和Int(*p1)[5]区:sizeof(p1)为4,;Int(*p1)[5]只是一个指针,但是指向一个int[5]这样的一个存储器。p++位移4,p1++位移了20个位元组,将int[]作为一个基本类型。
求数组的平均值:只使用指针,可以先用数组来写,然后再用指针来替换,因为用到了数组的每一个值,数组是a[i][j],要是指针的话就是*(*(p+i)+j)来表示。
指针主要是用在作为函数的参数。参数的传递是单向的,实参向形参传递。指针的优先级较低,*n++是先加加然后才取地址。因为传递的是地址,到了函数里面然后将地址的值取出来处理,处理完之后值就会被修改。
交换数字:如果我们使用值传递的话,是不可以交换数据的,因为在函数中使用的是形参,不可以改变;但是,可以使用指针,因为这样传递过去的是地址,然后我们直接对地址的操作,这样在完成之后,返回的时候也就改变了;在不使用任何中间变量的情况下,可以将两个值相加放在a,然后将a-b赋给b,这个时候b的值就是a的值,然后再用a-b赋给a,这个时候达到了交换的目的。
如果将数组作为函数的参数,C语言将数组名解析为指针,但是丢失了维度,那么就需要加一个参数来表示函数的维度,作为参数的时候a[10]==a[](代表参数是数组的名称,不确定有多少元素)==*a。
Dll的使用:1.将dll拷贝到与生成的exe相同的目录下
2.将lib拷贝到与.c档相同目录下,同时将.h档拷贝过来
3.将.h档包含进来
4.引用lib的库档#pragma comment(lib,”库文件名称”)
在linux下,将.h与.c和makefile都传到一个目录下,然后make一下,生成一个linux的dll,是.so档。这里不需要引用lib档。Gcc-o a a.c-L.-ldll这样使用。如果要显示中文,编码的格式必须一致。
使用网络的时候,需要查看防火墙有没有打开。
其实指针本质就是一个变量。如果将数组的名字作为函数的参数,数组名就成为了指针了。
指针常量(定义的时候就得初始化,以后没有机会赋值)和指向常量的指针;
指针与数组:使用的时候是完全一样的a[1] == p[1] ==*(p+1),内部的处理都是一样的。
指针数组和指向数组的指针:操作的时候移动的位数不同
找数组的最大值:可以使用返回值,也可以使用函数的参数,但是这时候参数必须是指针类型。在处理函数的时候,如果参数有数组,就需要加一个参数来表示数组的个数,这样程序就够完美。
注:数组元素的地址直接相减,得到的是位移数,而不是字节数,除非将地址强制转换为int类型。&a[1] -&a[0] = 1; (int)&a[1] -(int)&a[0] = 4;这样代表的就不是地址了。
二维数组作为函数的参数(int a[][3]) == (int (*a)[3])后面的3不可以省略,那样就不可以判断出数组是什么样的了。Sizeof(a)/sizeof(a[0])行的维度;sizeof(a[0])/sizeof(int)列的维度。
函数的返回值是指针:和其他的返回值也是类似,也是可以返回指针的。
指向函数的指针:只写函数的名称代表的是函数的地址。因为函数也是一段代码,也是有内存地址的。主函数也是有地址的。定义一个函数指针void (*p)()这是定义了一个没有参数,没有返回值的函数指针。将函数的原型去掉函数名之后,加一个(*p)就是代表函数指针。使用函数指针和使用函数一样,也是有参数的。C语言中,如果参数是(),代表可以有参数也可以没有参数。因为在设计的时候没有考虑到。void (*p)()与这个void *p()是有区别的,第一个是声明了一个函数指针,第二个是声明了一个函数,返回值是指针类型。
函数指针作为函数的参数,为了避免函数出错,这个时候要判断指针是否为空,在一个函数内部调用另一个函数。函数的返回值是一个地址,并且地址是一个函数地址。
If-else:else后面是没有任何条件了,如果相加条件的话可以使用else if。
下午讲的是一个小的聊天程序,使用UDP,在linux下与windows聊天。使用dll时候,首先要将环境配置好。使用的recv_socket()是一个阻塞的函数,知道消息到达,函数才返回。在linux下使用的话,因为不能在当前目录下寻找文件,加so文件的时候,将前面的lib和后面的.so省略,vi.bash_profile
在里面加:.就好了,使用. .bash_profile立即生效。
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
Export LD_LIBRARY_PATH
当我们在接受端添加一个system(buf)的时候,导致可以操作对方的电脑。而且在执行完之后,换可以给对方发送一个消息,换可以将system的执行结果返回。这就是一个小点的木马。也可以两个人之间聊天,单向通话。而且我们可以指定ip地址。
同步通话(类似QQ聊天),多线程程序,一个线程的代码是相互独立的。Sleep位于windows.h头文件中。多线程需要process.h头文件,_beginthread()创建一个线程,这样两个线程互不干扰,可以同步执行,相当于操作系统会在启动一个线程,会自动调用_beginthread()里面的函数。
在linux下面,多线程使用有点小区别,需要包含pthread.h头文件,使用函数pthread_create(),并且在编译的时候需要一个库文件pthread。
Memset()、memcpy()、memmove()的使用:
Memset(buf,0,sizeof(int))初始化指针单位是字节。与buf[10] = {0}结果是一样的,但是这个只能在定义的时候使用,memset()在程序任何地方需要清空的地方使用。指针不可以使用sizeof()。
Memcpy(,,int n)拷贝 n代表的是字节,不是个数,过大的时候出现内存越界。对于数组的移位适合。
Memmove(,,int n)做内存移动的时候,不要有内存的重叠区域。
字符指针和字符串:
Constchar *s;//不能通过s来改变
Main(int argc,char **argv)
Argc 执行程序的时候有几个参数
Args[][] 参数
|
|