xshell与Linux系统文件编码的不同所造成的乱码问题,如果不能修改Linux的编码,那么可以试着修改xshell的编码。
addr.sin_port
与Int
并不是同一种结构,htons
就是用来进行网络字节顺序和主机字节顺序转换的。一定要看好括号的范围
例如:connect(client_socket, (struct sockaddr*)&server_addr, server_addr_length)<0
错误:connect(client_socket, (struct sockaddr*)&server_addr, server_addr_length<0)
例如:(fd=open(filebag.data, O_WRONLY|O_CREAT)) < 0
错误:(fd=open(filebag.data, O_WRONLY|O_CREAT) < 0)
还是不会报错,但是最后fd会为0
虽然并不会报错,但是connect
就会一直失败,erron
会提示参数错误。erron
全局错误变量可以起到错误提示作用,包含于erron.h
中。变量名要与类名区分开来,标准的命名规则还是很有用的。
sdout
会有缓存,printf
中的内容并不会及时输出,这时可以加上"\n"
或者fflush(sdout)
,就会强制刷新缓存区。open
与fopen
有很大区别,返回值和参数都不一样。open
函数还有第四个参数,用来设置创建的文件的权限。有时候不设置没问题,有时候有问题,所以还是设置一下吧。test
是Linux
的一个指令,所以$test
没有输出,而$./test
指明了为文件,所以可以输出。直接在
case
后面定义变量会报错,如果不加这种限制,可能就会出现这种情况 :
case 1:
int x;
case 2:
x = 0;
因为case
的域实际上是连在一起的,所以在编译器编译时,并不会认为有错误,但是程序在实际运行时,直接跳到了case2
,那么x
明明没有被定义,却被使用,就会出错。解决方法:在case
后面加上花括号。
C里面并没有
bool
类型C中的
if
非零为真,零为假。指针实际上也为一个int数值,所以可以进行真or假判断。FILE *
类型的指针实际上是指向一个结构体。perror(s)
会优先输出s,再根据errno的值输出错误信息。只有char类型数组才需要‘/0’
区分开
'r'
与"r"
前者其实为int
类型,而后者可以视为一个指针。fopen
的参数就应该使用"r"区分开
"\0"
与'\0'
,前者是一个指针,后者是一个字符。但是如果使用"\0"
,会警告将指针赋给整数,而有时候结果却并不会出错。使用%d输出"\0"
,会输出符号+部分数字。或许是因为char的长度为1,Int的长度为4??malloc
地址一定要memset
,要不然错误free
会报错。只要使用
malloc
为char *ptr
申请哪怕1个字节的空间,你就可以将一个很长的字符串给他,而且还可以正常输出,但是free
的时候会报错。epoll_event.data
是一个union
,fd
和ptr
只能选一个!在
epoll_ctl
的时候,一定要确保epoll_event.data
和epoll_event.events
的值是正确的。
typedef struct queryStruct
{
char type[10];
char id[10];
char name[30];
char pass[30];
char *sendMess;
} queryDataStruct;
//用来向线程中传入相关信息
typedef struct threadStruct
{
int epollfd;
int clienfd;
struct epoll_event stev;
queryDataStruct *query;
} threadDataStruct;
//教训:向epoll_event stev.events中加入了数据,但是却没有管stev.data.ptr,所以虽然开头用
epoll_ctl(epollfd, EPOLL_CTL_ADD, clienfd, &(events[i]));
//添加成功,因为前面把threadDataStruct的指针给了events[i].data.ptr
//但是后面,在其他函数中,只能使用自己的结构体作为参数
epoll_ctl(threadData->epollfd, EPOLL_CTL_DEL, threadData->clienfd,&(threadData->stev));
//又没有往threadData->stev.data.ptr中放值,造成地址类型的错误
不能把一个公用的全局指针从
epoll
读取块直接拿到epoll
写入块中使用。因为读取块是用的clienfd=1
,而写入块可能就是用的clienfd=22。
一个客户端连接时没有影响,多个客户端连接,应该就会出现数据误传的情况。结构体可以直接包含非自身结构体变量。
只要是C风格的
char
字符串,那么最后必然会带上一个\0
。而strlen
计算,碰到\0
就会停止计数。所以在send
数据,要使用sizeof
(但是对指针只计算指针的大小,不计算数据大小)或者strlen(str)+1
。epoll事件使用ET读写模式,在服务端将缓存区数据读取完毕之后,当缓存区有新数据可读时,又会再次触发事件通知。ET只通知一次,指的是服务端自己缓存区取得一次数据(即有数据,然后读完算一次),而和客户端怎么取的没有关系。如果在处理读事件时,将数据的读取交给另外的线程处理,主线程继续循环处理监听到的events事件,那么就可能出现一个fd被放入多个线程的情况。这时就要在结构体中加一个判断变量,在将其放入线程前判断其前面是否已经被放入。
send
函数的参数如果超过发送数据的实际大小,那么就会发送重复的数据。所以最好将参数设置为数据的大小。send
函数每次发送都会从参数的开头地址发送,recv
接收时也是这样。(和文件的读取不一样)。所以C在循环读取数据并放入同一个字符数组中时,记得移动指针。sprintf
函数的格式化功能还是挺强的,使用时要把参数确定好。例如:
sprintf(cLen, "%-10d", iLen); //位数不够时用\0填充
sprintf(cLen, "%d", iLen); //位数不够时用' '填充
- 例如下面这样:
char *str1;
char *str2;
char *str3;
str1 = (char *)malloc(11);
str2 = (char *)malloc(100);
strcpy(str1, "UUUUUUUUUU");
strcpy(str2, "QQQQQQQQQQQQQQQQQQQQQQQ");
str3 = str1 + 5;
str3 = str2;
printf("str1 = %s\n", str1);
return 0;
是没有用的,因为以前学习数据结构时,经常使用例如
/*
struct queue
{
struct queue *next;
int data;
}*/
struct queue *ptr = head;
ptr->next = 一个指针
head->next = 一个指针 //这两个是等效的
ptr = 一个指针
head = 一个指针 //这两个是不一样的
原因:head->next
是head
自身包含的地址指向的一段内存,而head则是自身包含的地址。当ptr = head
后,并不是说现在ptr
就和head
等价了(大学四年一直误以为此),只是prt
和head
中包含的地址是一样的,当你用ptr->next
进行操作的时候,是操作ptr
包含的地址指向的空间,所以无论是对ptr
还是对head
进行操作,都是等同的。但是在对ptr
和head
进行操作的时候,你操作的就是两个完全不同的变量了,所以操作不等同。ptr = head
,只是ptr
和head
中保存的地址一样了,而不是ptr
本身的地址和head一样了。
就好像你把甲的仓库钥匙复制给了乙一份,那么甲和乙操作的仓库就是同一个仓库了,这时候你把乙的钥匙换了,那么甲的钥匙并不会跟着乙的一起变化。
可以使用
realloc
实现动态数组,虽然感觉并没有什么用。另外,为了减少realloc的次数,在分配空间和减少空间时,都可以预分配一定空间。char类型数组后面一定要有一个
\0
,如果你要用一个数组从一个字符串中复制出10个值,那么这个数组的大小起码要为11,如果大小为10,那么再你输出这个数组时,有可能连带输出后面地址的值。能不用
malloc
就不要用,能不用多线程就不要用。指针定义和
free
后指NULL
是一个好习惯。str[i++]
和str[++i]
也遵循先给后加和先加后给原则,即中括号并没有小括号的作用,它并没有优先级。由于二进制不能精确表示小数,所以
double
和float
有时候并不是精确的,只是在printf
时会输出近似值。但是如果使用int
强制转换,会完全丢失小数部分,然后就表现为比原数小1。解决办法:int(math + 0.5)
。C语言没有默认参数。
以前从来没有注意过,在
C
中不能单独输出一个中文字符串中的一个中文字符。一个中文字符占两个char
。中文字符最小都是一个长度为2的字符串?const struct *head
,那么head
中变量值都不可以改变。math>>1
将math
变为二进制,然后左移1位,位数不足补零。最好不要对有符号数使用,移位之后的位数不能超过有效位数。采用math+math>>1
,符合条件的情况下等同于1.5*math,但是速度要块很多。无锁数据结构的基本操作
CAS
,将一个变量的值与A
值比较,如果相等,那么将变量的值变为B
值。没有加锁和解锁过程,性能影响较小,避免死锁和活锁的情况。但是可能会产生ABA
问题。C语言接口。一组回调函数(函数指针)+函数上下文(指向一个或一组数据)。根据自己的需要让接口内的函数指针指向不同的函数,而调用是统一调用接口的。
C语言容器。其实也是一个接口,也就是说也有一组回调函数和函数上下文。先实现容器接口,然后再用实现了的容器实现需要的结构。原来是用双向链表和动态数组分别实现队列的接口,那么抽象出容器后,我们先用双线链表和动态数组实现容器,然后再用容器实现队列。虽然中间多了一步,但是下次要实现栈的是时候,就可以直接使用容器直接来实现了。