无聊在网上找了些C语言的东东练一下手,竟然发现其实还有好多细节之前,没注意到,该好好复习一下先。
解决掉的问题先不发出来,把疑问的先做个笔记,过几天解决了就回来修改补上。
 

#include <stdio.h>
struct{
        int i; 
        char j;
        double a;
        int b[20];
}aaa1; 
main()
{
    aaa1.i = 1;
    aaa1.j = 'a';
    aaa1.a = 0;
    printf("%d\n",sizeof(aaa1.i));
    printf("%d\n",sizeof(aaa1.j));
     printf("%d\n",sizeof(aaa1.b));
      printf("%d\n",sizeof(aaa1.a));
    printf("%d\n",sizeof(aaa1));
    
    getch();

运行结构是:

4

1

80

8

96

问题出在  char j; 这里,单独查看,可以看到 char类型占用一个 byte,但是为什么放都结构体里面的时候,它就占用了 4 个byte 呢?难道结构体有对自己的元素类型占用空间做了强制规定吗?

在dev-c++ 里面,调试了一下:

500)this.width=500;" border="0" src="http://blogimg.chinaunix.net/blog/upfile2/080426204138.jpg">

看到的结构体里面,竟然没有 j 这个元素,取而代之的是 i=97'a' 这又怎么解释呢?

—。—#

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

找到这篇文章,哈哈,我想红色字就是我要的答案了:

intarray[3]={35,56,37}; 
int*pa=array;

  通过指针pa访问数组array的三个单元的方法是:

*pa;//访问了第0号单元 
*(pa+1);//访问了第1号单元 
*(pa+2);//访问了第2号单元

  从格式上看倒是与通过指针访问结构成员的不正规方法的格式一样。

  所有的C/C++编译器在排列数组的单元时,总是把各个数组单元存放在连续的存储区里,单元和单元之间没有空隙。但在存放结构对象的各个成员时,在某种编译环境下,可能会需要字对齐或双字对齐或者是别的什么对齐,需要在相邻两个成员之间加若干个"填充字节",这就导致各个成员之间可能会有若干个字节的空隙。

  所以,例中,即使*pstr访问到了结构对象ss的第一个成员变量a,也不能保证*(pstr+1)就一定能访问到结构成员b。因为成员a和成员b之间可能会有若干填充字节,说不定*(pstr+1)就正好访问到了这些填充字节呢。这也证明了指针的灵活性。要是你的目的就是想看看各个结构成员之间到底有没有填充字节,嘿,这倒是个不错的方法。

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

当全局变量跟局部变量有冲突时,局部变量会把全局变量隐藏掉。据说可以用加 :: 的方式来强制访问全局变量,但是我加了这个符号根本就编译不过去,应该是C++ 才有的吧?

#include<stdio.h>
int main()
{
    int i=3;
    int j;
    j = (++i) + (++i) + (++i);
    printf("i=%d,j=%d", i ,j);

getch();
}

超简单的代码,可是,运行后 i=6,j=16

怎么回事呢??

 
解答:
1、一个变量在一条语句中出现一次以上,不宜使用自加运算。  
2、自加运算是编译器相关的,不同的编译器得到的结果不同。
3、这里面存在一个符号优化的问题,对于j=(++i)+(++i)+(++i):是先算前两项(++i)+(++i),再和最后一个(++i)相加...

一些常被问到的知识点:

什么是标准预定义宏?

ANSIC标准定义了以下6种可供C语言使用的预定义宏:
----------------------------------------------------------------------------
   宏  名                     作    用
----------------------------------------------------------------------------
  __LINE__           在源代码中插入当前源代码行号
  __FILE__           在源代码中插入当前源代码文件名
  __DATE__           在源代码中插入当前编译日期〔注意和当前系统日期区别开来〕
  __TIME__           在源代码中插入当前编译时间〔注意和当前系统时间区别开来〕   
  __STDC__           当要求程序严格遵循ANSIC标准时该标识符被赋值为1。
----------------------------------------------------------------------------

标识符__LINE__和__FILE__通常用来调试程序;标识符__DATE__和__TIME__通常用来在编译后的程序中加入一个时间标志,以区分程序的不同版本;当要求程序严格遵循ANSIC标准时,标识符__STDC__就会被赋值为1;当用C++编译程序编译时,标识符__cplusplus就会被定义。

#include <stdio.h>
int main ()
{
    printf("该输出行在源程序中的位置:%d\n", __LINE__ );
    printf("该程序的文件名为:%s\n", __FILE__ );
    printf("当前日期为:%s\n", __DATE__ );
    printf("当前时间为:%s\n", __TIME__ );
    return 0;

}

连接运算符“##”和字符串化运算符"#"有什么作用?[仔细理解]

连接运算符“##”可以把两个独立的字符串连接成一个字符串。在C的宏中,经常用到“##”运算符,请看下例:
    #include
    #define SORT(X)  sort_function ## X
    void main(vOid);
    void main(vOid)
    {
        char *array;
        int  elements,element_size;
        SORT(3) (array,elements,element_size);
    }

在该例中,宏SORT利用“##”运算符把字符串sort_function和经参数x传递过来的字符串连接起来,这意味着语句 SORT(3)(array,elemnts,element_size) 将被预处理程序转换为语句:
    sort_function3(array,elements,element_size);

从宏SORT的用法中你可以看出,如果在运行时才能确定要调用哪个函数,你可以利用“##”运算符动态地构造要调用的函数的名称。

#include<stdio.h>
#define FUNC(X) func ## X
int func1(int a, int b)
{
    return 1;
}
int func2(int a, int b)
{
    return 2;
}

int main()
{
    int a, b, result;
    result = FUNC(1)(a, b);
    printf("---%d---\n", result);
    result = FUNC(2)(a, b);
    printf("---%d---\n", result);
    getchar();
    return 0;

}

符串化运算符"#"运算符能将宏的参数转换为带双引号的字符串,请看下例:

define DEBUG_VALUE(v)  printf(#v"is equal to %d. \n", v)

你可以在程序中用 DEBUG_VALUE 宏检查变量的值,请看下例:

int x=20;

DEBUG_VALUE(x);

上述语句将在屏幕上打印"x is equal to 20"。这个例子说明,宏所使用的“#”运算符是一种非常方便的调试工具。

#include <stdio.h>
#define DEBUG_VALUE_INT(v) printf(#v" is equal to %d.\n",v )
#define DEBUG_VALUE_STR(v) printf(#v" is equal to %s.\n",v )
int main(int)
{
      int x = 0;
      char str[] = "asdfqweqwfdvasdf";
      DEBUG_VALUE_INT(x);
      DEBUG_VALUE_STR(str);
      getchar();
      return 0;

}

怎样删去字符串尾部的空格?

C语言没有提供可删去字符串尾部空格的标准库函数,但是,编写这样的一个函数是很方便的。请看下例:

#include <stdio.h>
# include <string.h>
char * rtrim( char * );
int main()
{
//char * trail_str = "0123456789 "; 把字符串定义成这种形式时,运行程序的时候会出现异常
char trail_str[21] = "0123456789 ";
    printf( "Before calling rtrim(), trail_str is '%s'\n" , trail_str );
    printf( "and has a length of %d. \n" , strlen( trail_str ) );
    rtrim(trail_str);
    printf( "After calling rttim(), trail_ str is '%s'\n", trail_str );
    printf( "and has a length of %d. \n" , strlen( trail_str ) ) ;
    getchar();
    return 0;
}
/* The rtrim() function removes trailing spaces from a string. */
char * rtrim( char * str )
{
    int n = strlen(str) - 1; 
    while( n > 0 ) 
    {
        if( *( str + n ) != ' ' ) 
        {
            //在windows下,将str字符串的某一位设置为值 '\0' 时,会出现异常..
            *( str + n + 1 ) = '\0'; 
            break ; 
        }
        else 
        {
            printf("%c, %d\n", str[n], str[n] ); 
            n--;
        }
    }
    return str; 
}

在上例中,rtrim()是用户编写的一个函数,它可以删去字符串尾部的空格。函数rtrim()从字符串中位于null字符前的那个字符开始往回检查每个字符,当遇到第一个不是空格的字符时,就将该字符后面的字符替换为null字符。因为在C语言中null字符是字符串的结束标志,所以函数rtrim()的作用实际上就是删去字符串尾部的所有空格。

怎样删去字符串头部的空格?

C语言没有提供可删去字符串头部空格的标准库函数,但是,编写这样的一个函数是很方便的。请看下例:

#include <stdio.h> 
#include <string.h>
char *ltrim(char * ); 
char *rtrim(char * );
void main (void)
{

}
char * ltrim(char * str)
{
    strrev(str); /* Call strrev to reverse the string. */
    rtrim(str); /* Call rtrim to remvoe the "trailing" spaces. */
    strrev(str); /* Restore the string's original order. */
    return str ; /* Return a pointer to the string. */
}
char* rtrim(char* str)
{

}

在上例中,删去字符串头部空格的工作是由用户编写的ltrim()函数完成的,该函数调用了6.2的例子中的rtrim()函数和标准C库函数strrev()。ltrim()函数首先调用strrev()函数将字符串颠倒一次,然后调用rtrim()函数删去字符串尾部的空格,最后调用strrev()函数将字符串再颠倒一次,其结果实际上就是删去原字符串头部的空格。

怎样打印字符串的一部分?

使用printf()函数打印字符串的任意部分,请看下例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char * source_str = "THIS IS THE SOURCE STRING" ;
    /* Use printfO to print the first 11 characters of source_str. */
    printf("First 11 characters: ' %11.11s'\n" , source_str);
    /* Use printf() to print only the last 13 characters of source _str. */
    printf("Last 13 characters:'%13.13s'\n", source_str+(strlen(source_str)-13));

}
    输出结果为: 
    First 11 characters: 'THIS IS THE' 
    Last 13 characters:'SOURCE STRING'

在上例中,第一次调用printf()函数时,通过指定参数"%11.11s",迫使printf()函数只打印11个字符的长度,因为源字符串的长度大于11个字符,所以在打印时源字符串将被截掉一部分,只有头11个字符被打印出来。第二次调用printf()函数时,它将源字符串的最后13个字符打印出来,其实现过程为:
(1)用strlen()函数计算出source_str字符串的长度,即strlen(source_str)。
(2)将source_str的长度减去13(13是将要打印的字符数),得出source_str中剩余字符数,且pstrlen(source_str)-13。
(3)将strlen(source_str)-13和source_str的地址相加,得出指向source_str中倒数第13个字符的地址的指针;即source_str+(strlen(source_str)-13)。这个指针就是printf()函数的第二个参数。
(4)通过指定参数“%13.13s”,迫使printf()函数只打印13个字符的长度,其结果实际上就是打印源字符串的最后13个字符。

用malloc()函数更好还是用calloc()函数更好?

函数malloc()和calloc()都可以用来分配动态内存空间,但两者稍有区别。malloc()函数有一个参数,即要分配的内存空间的大小:    
    void *malloc(size_t size);    
calloc()
函数有两个参数,分别为元素的数目和每个元素的大小,两个参数的乘积就是要分配的空间的大小:    
    void *calloc(size_t numElementssize_t sizeOfElement);
如果调用成功,函数malloc()和calloc()都将返回所分配的内存空间的首地址。
malloc()函数和calloc()函数的主要区别是前者不能初始化所分配的内存空间,而后者能
。如果由malloc()函数分配的内存空间原来没有被使用过,则其中的每一位可能都是0;反之,如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。也就是说,使用malloc()函数的程序开始时(内存空间还没有被重新分配)能正常运行,但经过一段时间后(内存空间已被重新分配)可能会出现问题。

calloc()函数会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为零;如果你是为指针类型的元素分配内存,那么这些元素通常(但无法保证)会被初始化为空指针;如果你是为实数类型的元素分配内存,那么这些元素可能(只在某些计算机中)会被初始化为浮点型的零。

malloc()函数和calloc()函数的另一点区别是calloc()函数会返回一个由某种对象组成的数组,但malloc()函数只返回一个对象。为了明确是为一个数组分配内存空间,有些程序员会选用calloc()函数。但是,除了是否初始化所分配的内存空间这一点之外,绝大多数程序员认为以下两种函数调用方式没有区别:
    calloc( numElements,sizeOfElement );
    malloc( numElements * sizeOfElement );

需要解释的一点是,理论上(按照ANSIC标准)指针的算术运算只能在一个指定的数组中进行,但是在实践中,即使C编译程序或翻译器遵循这种规定,许多C程序还是冲破了这种限制。因此,尽管malloc()函数并不能返回一个数组,它所分配的内存空间仍然能供一个数组使用(对realloc()函数来说同样如此,尽管它也不能返回一个数组)。总之,当你在calloc()函数和malloc()函数之间作选择时,你只需考虑是否要初始化所分配的内存空间,而不用考虑函数是否能返回一个数组。

NULL和NUL有什么不同?

NULL是在头文件中专门为空指针定义的一个宏。NUL是ASCII字符集中第一个字符的名称,它对应于一个零值。C语言中没有NUL这样的预定义宏。注意:在ASCII字符集中,数字0对应于十进制值80,不要把数字0和'\0'(NUL)的值混同起来。

NULL可以被定义为(void *)0,而NUL可以被定义为'\0'。NULL和NUL都可以被简单地定义为0,这时它们是等价的,可以互换使用,但这是一种不可取的方式。为了使程序读起来更清晰,维护起来更容易,你在程序中应该明确地将NULL定义为指针类型,而将NUL定义为字符类型。

在程序退出main()函数之后,还有可能执行一部分代码吗?

可以,但这要借助C库函数atexit()。利用atexit()函数可以在程序终止前完成一些“清理”工作——如果将指向一组函数的指针传递给atexit()函数,那么在程序退出main()函数后(此时程序还未终止)就能自动调用这组函数。在使用atexit()函数时你要注意这样两点:

第一: 由atexit()函数指定的要在程序终止前执行的函数要用关键字void说明,并且不能带参数;

第二: 由atexit()函数指定的函数在入栈时的顺序和调用atexit()函数的顺序相反,即它们在执行时遵循后进先出(LIFO)的原则。

#include<stdlib.h>
#include<stdio.h>
void my_exit1(void)
{
    printf("my_exit1() function !\n");

void my_exit2(void)
{
    printf("my_exit2() function !\n");

int main()
{
    atexit ( my_exit1 );
    atexit ( my_exit2 );
    printf("now, eixt this program...\n");
    exit(0);
}
输出结果为:

now, eixt this program...
my_exit2() function !
my_exit1() function !

数组作为函数的常数时,可以通过sizeof运算符得到函数数组的大小吗?

不可以。当把数组作为函数的参数时,你无法在程序运行时通过数组参数本身告诉函数该数组的大小,因为函数的数组参数相当于指向该数组第一个元素的指针。这意味着把数组传递给函数的效率非常高,也意味着程序员必须通过某种机制告诉函数数组参数的大小。为了告诉函数数组参数的大小,人们通常采用以下两种方法:

第一种方法是将数组和表示数组大小的值一起传递给函数,例如memcpy()函数就是这样做的:
    memcpy( dest,source,length );

第二种方法是引入某种规则来结束一个数组,例如在C语言中字符串总是以ASCII字符NUL('\0')结束,而一个指针数组总是以空指针结束。请看下述函数,它的参数是一个以空指针结束的字符指针数组,这个空指针告诉该函数什么时候停止工作:
    void printMany( char *strings[] )    
    {
        int i = 0;   
        while( strings[i] != NULL )
        {
            puts(strings[i]);
            ++i;
        }
    }

正象9.5中所说的那样,C程序员经常用指针来代替数组下标,因此大多数C程序员通常会将上述函数编写得更隐蔽一些:
    void printMany( char *strings[] )
    {
        while( *strings )
        {
            puts(*strings++);
        }
    }

尽管你不能改变一个数组名的值,但是strings是一个数组参数,相当于一个指针,因此可以对它进行自增运算,并且可以在调用puts()函数时对strings进行自增运算 [注意辨别这种情况:对“int array[10] 数组的array不能进行自加运算”]。

array_name和&array_name有什么不同?

前者是指向数组中第一个元素的指针,后者是指向整个数组的指针。注意: 笔者建议读者读到这里时暂时放下本书,写一下指向一个含MAX个元素的字符数组的指针变量的说明。希望你不要敷衍了事,因为只有这样你才能真正了解C语言表示复杂指针的句法的奥秘。下文将介绍如何获得指向整个数组的指针。

数组是一种类型,它有三个要素,即基本类型(数组元素的类型),大小(当数组被说明为不完整类型时除外),数组的值(整个数组的值)。你可以用一个指针指向整个数组的值:
    char a[MAX];    /*array of MAX characters*/
    char *p = a;     
    char *pa = &a;  
在运行了上述这段代码后,你就会发现p和pa的打印结果是一个相同的值,即p和pa指向同一个地址。但是,p和pa指向的对象是不同的。

上述定义和以下定义是相同的,它们的含义都是“ap是一个含MAX个字符指针的数组”: char *ap[MAX].

以下这种定义并不能获得一个指向整个数组的值的指针:char *(ap[MAX]).

怎样判断一个字符是数字、字母或其它类别的符号?

在头文件ctype.h中定义了一批函数,它们可用来判断一个字符属于哪一类别。下面列出了这些函数:
---------------------------------------------------------------------------------------
   函数         字符类别               返回非零值的字符
---------------------------------------------------------------------------------------
  isdigit()     十进制数               0--9
  isxdigit()    十六进制数             0--9,a—f,或A--F
  isalnum()     字母数字符号           0--9,a--Z,或A--Z
  isalpha()     字母                   a—z或A--Z
  islower()     小写字母               a—z
  isupper()     大写字母               A--Z
  isspace()     空白符                 空格符,水平制表符,垂直制表符,换行符,换页符,或回车符
  isgraph()     非空白字符             任何打印出来不是空白的字符(ASCII码从21到7E)
  isprint()     可打印字符             所有非空白字符,加上空格符
  ispunct()     标点符                 除字母数字符号以外的所有非空白字符
  iscntrl()     控制字符               除可打印字符外的所有字符(ASCII码从00到1F,加上7F)

----------------------------------------------------------------------------------------

与前文提到过的使用标准库函数的好处相似,调用上述这些宏而不是自己编写测试字符类别的程序也有三点好处。首先,这些宏运算速度快,因为它们的实现方式通常都是利用位屏蔽技术来检查一个表,所以即使是进行一项相当复杂的检查,也比真正去比较字符的值要快得多。其次,这些宏都是正确的。如果你自己编写一个测试程序,你很容易犯逻辑上或输入上的错误,例如引入了一个错误的字符(或漏掉了一个正确的字符)。第三,这些宏是可移植的。信不信由你,并非所有的人都使用同样的含PC扩充字符的ASCII字符集。也许今天你还不太在意,但是,当你发现你的下一台计算机使用的是Unicode字符集而不是ASCII字符集,你就会庆幸自己原来没有按照字符集中的字符值来编写程序。

其他字符转换函数:

isascii(测试字符是否为ASCII 码字符)

int isascii(int c);

检查参数c是否为ASCII码字符,也就是判断c的范围是否在0到127之间。若参数c为ASCII码字符,则返回TRUE,否则返回NULL(0)。

toascii(将整型数转换成合法的ASCII 码字符)

int toascii(int c);

toascii()会将参数c转换成7位的unsigned char值,第八位则会被清除,此字符即会被转成ASCII码字符。将转换成功的ASCII码字符值返回。

tolower(将大写字母转换成小写字母)

int tolower(int c);

若参数c为大写字母则将该对应的小写字母返回。返回转换后的小写字母,若不须转换则将参数c值返回。

toupper(将小写字母转换成大写字母)

int toupper(int c);

若参数c为小写字母则将该对映的大写字母返回。返回转换后的大写字母,若不须转换则将参数c值返回。

以isalmun为例,说明这些函数的用法[剩余的其他函数跟它类似]:
int isalnum ( int c )
检查参数c是否为英文字母或阿拉伯数字,若参数c为字母或数字,则返回TRUE,否则返回NULL。此为宏定义,非真正函数。

#include<stdio.h>
#include <ctype.h>
int main()
{
    char str[]=123c@#FDsP[e?;
    int i;
    for( i = 0; str[i] != 0; i++ )
    {
        if( isalnum( str[i] ) ) 
            printf("%c is an alphanumeric character\n", str[i] ); 
    }
}

C 语言疑难杂症 [转:http://blog.chinaunix.net/uid-20688544-id-1894880.html]的更多相关文章

  1. 原博客地址http://blog.chinaunix.net/uid/20656672.html弃用

    原博客地址http://blog.chinaunix.net/uid/20656672.html弃用

  2. 原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(10年前数百篇oracle/teradata性能优化、故障处理案例)

    原博客地址http://blog.chinaunix.net/uid/20656672.html不再维护(数百篇oracle/teradata性能优化.故障处理原创文章) 858871 top 500 ...

  3. http://blog.chinaunix.net/uid-20577907-id-3519578.html

    http://blog.chinaunix.net/uid-20577907-id-3519578.html

  4. http://blog.chinaunix.net/uid-9845710-id-1996675.html snmpd配置

    http://blog.chinaunix.net/uid-9845710-id-1996675.html http://lihuipeng.blog.51cto.com/3064864/643960 ...

  5. http://m.blog.csdn.net/article/details?id=8237698

    http://m.blog.csdn.net/article/details?id=8237698

  6. http://m.blog.csdn.net/article/details?id=49132747

    http://m.blog.csdn.net/article/details?id=49132747

  7. http://m.blog.csdn.net/article/details?id=2630620

    http://m.blog.csdn.net/article/details?id=2630620

  8. C语言 字符串处理函数 转自 http://blog.chinaunix.net/uid-25885064-id-3175049.html

     C字符串处理函数 2012-04-13 18:14:16 分类: C/C++ void *memccpy (void *dest, const void *src, int c, size_t n) ...

  9. JavaSript模块规范 - AMD规范与CMD规范介绍 (转载lovenyf.blog.chinaunix.net)

    JavaSript模块化   在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发?       模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题 ...

随机推荐

  1. (数据科学学习手札51)用pymysql来操控MySQL数据库

    一.简介 pymysql是Python中专门用来操控MySQL数据库的模块,通过pymysql,可以编写简短的脚本来方便快捷地操控MySQL数据库,本文就将针对pymysql的基本功能进行介绍: 二. ...

  2. Springboot启动报Multiple Dockets with the same group name are not supported. The following duplicate groups were discovered.

    解决方法: 属于bean重复,根据错误提示剔除多于的Bean引用!

  3. 20155308&20155316 2017-2018-1 《信息安全系统设计基础》实验一

    20155308&20155316 2017-2018-1 <信息安全系统设计基础>实验一 此次实验我和黄月同学一起做了1.2.3.5项,第4项在实验课上做完了,但是没有按时提交. ...

  4. 优步UBER司机全国各地最新奖励政策汇总(持续更新...)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://didi-uber.com/archiv ...

  5. 【LG4587】[FJOI2016]神秘数

    [LG4587][FJOI2016]神秘数 题面 洛谷 题解 首先我们想一想暴力怎么做 对于一段区间\([l,r]\) 我们先将它之间的数升序排序 从左往右扫, 设当前我们可以表示出的数为\([1,x ...

  6. 【LG5019】[NOIP2018]道路铺设

    [LG5019][NOIP2018]道路铺设 题面 洛谷 题解 \(NOIP\) 抄 \(NOIP\)差评 设当前做到了位置\(i\) 且\(h_i\) \(-\) \(h_i\)\(_+\)\(_1 ...

  7. L018-crond的生产场景经验小节

    L018-crond的生产场景经验小节 怎么说呢,其实L018这节课还是巩固crond的知识,前半堂课主要是解决上堂课老师留的作业(在L017已经更新,拉到最后),然后剩下的半堂客主要是讲解了一些生产 ...

  8. javaweb(十九)——JSP标签

    一.JSP标签介绍 JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护. 二.JSP常用标签 ...

  9. 使用Photon引擎进行unity网络游戏开发(一)——Photon引擎简介

    使用Photon引擎进行unity网络游戏开发(一)--Photon引擎简介 Photon PUN Unity 网络游戏开发 Photon引擎简介: 1. 服务器引擎: 服 务 器 引 擎 介 绍 服 ...

  10. SICP读书笔记 1.3

    SICP CONCLUSION 让我们举起杯,祝福那些将他们的思想镶嵌在重重括号之间的Lisp程序员 ! 祝我能够突破层层代码,找到住在里计算机的神灵! 目录 1. 构造过程抽象 2. 构造数据抽象 ...