当前位置: 首页 > news >正文

企业网站推广哪家好手机系统网站有哪些

企业网站推广哪家好,手机系统网站有哪些,福建祥盛建设有限公司网站,资阳抖音搜索优化#x1f4af;#x1f4af;#x1f4af; 本篇处理的是有关语义误解的问题#xff1a;即程序员的本意是希望表示某种事物#xff0c;而实际表示的却是另外一种事物。在本篇我们假定程序员对词法细节和语法细节的理解没有问题#xff0c;因此着重讨论语义细节。导言#xf… 本篇处理的是有关语义误解的问题即程序员的本意是希望表示某种事物而实际表示的却是另外一种事物。在本篇我们假定程序员对词法细节和语法细节的理解没有问题因此着重讨论语义细节。导言①.指针与数组1.1数组的两个注意点1.1.1确定数组的大小1.1.2获得指向该数组下标为0的元素的指针。1.2指针与数组之间的真正关系1.2.1数组名表示首元素的地址指针1.2.2“二维数组”②.非指针的数组③.作为参数的数组声明3.1一维数组的传参3.2二维数组的传参3.3一级指针传参3.4二级级指针传参④.避免举隅法⑤.空指针并非空字符串注意⑥.边界计算与不对称边界6.1 死循环问题6.1.1死循环的原因是什么呢6.1.2解决方法6.1.3总结6.2 边界问题6.2.1两个原则和一个编程技巧6.3 边界访问⑦.求值顺序7.1短路求值和||⑧.整数溢出⑨.main函数的返回值导言 由于一个程序错误可以从不同层面采用不同方式进行考察而根据程序错误与考察程序的方式之间的相关性可以将程序错误进行划分为各种陷阱与缺陷 ①.词法“陷阱” ②.语法“陷阱” ③.语义“陷阱” ④.连接问题 ⑤.库函数问题 ⑥.预处理器问题 ⑦.可移植性缺陷 本篇重点讲解语义“陷阱” ①.指针与数组 1.1数组的两个注意点 1.1.1确定数组的大小 数组的声明必须确定数组的大小是多少 int a[3];/声明a是一个拥有3个整形的数组 struct arr {int p[4];double x; }b[10];声明了b是一个拥有10个元素的数组每个数组元素是个结构体该结构体中包含了一个拥有4个整形的数组和一个浮点型的变量。 1.1.2获得指向该数组下标为0的元素的指针。 这句话什么意思呢 其实有关数组的操作哪怕它们乍看上去是以数组下标进行运算的实际上都是通过指针进行运算的。 换句话说任何一个数组下标的运算都等同于一个对应的指针运算所以我们完全可以依据指针行为定义数组下标的行为。 那获得该下标为0的元素的指针如果给这个指针加1就能得到指向该数组中下一个元素的指针。 也就是指针一个整数得到的还是指针只不过指针的位置发生改变 注意可不是指针指向的内容发生改变了 int a[10]{0,1,2,3,4,5,6,7,8,9}; int *pa; pp1; //或者写成p;1.2指针与数组之间的真正关系 sizeof(数组名)这里的数组名表示整个数组计算的是整个数组的大小。 sizeof(a)的结果是整个数组a的大小而不是指向数组a首元素地址的大小。数组名这里的数组名表示整个数组取出的是整个数组的地址除此之外所有的数组名都表示首元素的地址指针 这里重点讲解第三个关系 1.2.1数组名表示首元素的地址指针 数组名表示首元素的地址 除了a被用作运算符sizeof的参数和a的情况在其他所有的情况中数组名a都代表着指向数组a中下标为0的元素的指针。 也就是数组名a代表着数组a中首元素的地址。 所以我们可以这样理解*a也就是数组a中下标为0的元素的引用。 *a10;这句代码也就是把首元素的值改成10. 同理*(a1_是数组a中下标为1的元素的引用以此类推可以推出*(ai)即数组a中下标为i的元素的引用而这种写法是如此的常用因为它被简记为a[i]; 所以我们可以这样理解数组下标与指针之间的关系 a[0] 等同于*(a0) //数组名a表示首元素的地址加0还是首元素对首元素的解引用访问的就是首元素而a[0]就是首元素a[1]等同于*(a1) //首元素的地址1表示指向了第二个元素的地址解引用就等于访问第二个元素而a[1]就是第二个元素a[2]等同于*(a2)//首元素的的地址2表示指向了第三个元素的地址解引用等于访问第三个元素而a[2]就是第三个元素 …… …… …… a[i]等同于*(ai)//就相当于数组a中下标为i的元素的访问 也正是这一概念让许多C语言新手对数组与指针之间的关系搞得迷迷糊糊的。 实际上由于ai与ia的含义是相同的因此a[i]和i[a]也具有相同的含义但不要写成这样因为不好理解。 1.2.2“二维数组” 我们可以利用二维数组来揭示指针与数组之间的关系 int arr[10][20];这个代码声明arr是一个数组。该数组是拥有10个数组类型的元素。其中每个元素都是一个拥有20个整形元素的数组(而不是一个拥有20个数组类型的元素每个元素都是一个拥有10个整形的数组)。 根据我们对一维数组的理解arr总是被转换成一个指向arr数组的起始元素的的指针。也就是首元素的地址。 这里还是提醒一下该数组仍然遵循上面的第1条 sizeof(数组名)表示的是整个数组的大小而这个二维数组的整个大小是10 * 20*sizeofint 而这个二维数组它实际上是以数组为元素的数组。它是一维数组里面又套了一个一维数组。 在一维数组里面我们可以比较轻松的利用指针来编写操纵一维数组的程序但是对于二维数组从记法上的便利性来说采用下标的形式才是更好的方式。 如果我们仅仅使用指针来操纵二维数组那我们就必须深刻的理解指针相关的知识不然会常常遇到意想不到的bug。 来我们看一下下面的声明 int a[10]; int arr[10][20]; int *p; int i;想一想arr[3]代表的是什么 a[3]表示一维数组a中第4个元素。 那arr[3]对于二维数组arr是什么意思呢 我读这个二维数组的方式是这个二维数组有10个数组类型。 10个数组元素每个数组元素有20个整形元素。 所以arr[3],就代表着这10个数组元素的第4个数组元素。 其实我们还可以这样理解将二维数组第一个[ ]里看成是行数 第二个[ ]看成列数。 那么有该二维数组有10行20列 arr[0]表示第1行的数组元素 arr[1]表示第2行的数组元素 arr[2]表示第3行的数组元素 arr[3]表示第4行的数组元素 arr[4]表示第5行的数组元素 arr[5]表示第6行的数组元素 arr[6]表示第7行的数组元素 arr[7]表示第8行的数组元素 arr[8]表示第9行的数组元素 arr[9]表示第10行的数组元素 那arr[3]表示的是第4行数组元素。 我们知道每一行的数组元素里面都有着20个整形元素 所以一个arr[3]的大小就是sizeof(arr[3])20*sizeof(int) //这段代码表示什么意思 parr[3];这个语句使得指针p指向了数组arr[3]中下标为0的元素。 为什么是这样呢 因为你看arr[3]表示的是数组该数组里面还有20个元素呢 所以arr[3]表示这个拥有20个整形元素的数组的数组名 数组名代表着什么 代表着首元素的地址所以该语句将arr[3]数组的首元素的地址传给了 p。 那*arr[3]就是对arr[3]这个数组的首元素的地址的访问了也就是它那20个元素的首元素。 *(arr[3]1)这就表示访问第4个数组元素里面的第2个元素 也就是arr[3][1] *(arr[3]3这就表示访问第4个数组元素里面的第3个元素arr[3][2] *(arr[3]4这就表示访问第4个数组元素里面的第4个元素arr[3][3] *(arr[3]5这就表示访问第4个数组元素里面的第5个元素arr[3][4] …… …… *(arr[3]i这就表示访问第4个数组元素里面的第i个元素arr[3][i]这个语句根据前面的类似的道理还可以写成下面的这样 *(arr[3]3这就表示访问第4个数组元素里面的第3个元素arr[3][2] 进一步写成这样---也就是将arr[3]下标形式写成指针形式 *(*(arr3)3)我们不难发现用带方括号的下标形式很明显的要比完全用指针来表达方便多了。 不过还有人经常犯错误,写成下面这样 parr;这个语句是非法因为arr是一个二维数组即”数组的数组“ arr表示的是首元素的地址对吧 你想一想arr首元素是个啥还是个数组呀 所以arr首元素的地址是数组的地址使用arr时会转化为一个指向数组的指针而p是一个指向整形变量的指针可不能将一种类型的指针赋给另一种类型的指针这是非法的。 很显然我们需要一个指向数组的指针来保存arr上一篇博客我已经较为详细的介绍了该如声明一个变量按照使用的方式来声明 我们需要的是一个指针该指针是指向一个数组的该数组的大小是20 int(*ph)[20]; //我们首先构造出(*ph)这个指针 //这个指针指向的是什么类型的呢--是int [20]类型的该语句实现的效果就是*ph是一个拥有20个整形元素的数组 所以ph就是一个指向这样的数组的指针。 所以可以这样写 int arr[10][20]; int(*ph)[20]; pharr;ph也就指向数组arr的第一个元素的地址了也就是数组arr的10个中有着20个元素的数组的元素之一。 利用上面的二维数组可以很好的揭示C语言中数组与指针之间独特的关系从而更清楚的明白理解这两个概念。 ②.非指针的数组 1.在C语言中字符串常量代表的是一块包括字符串中所有字符还有一个’\0’的内存区域的地址。 2.字符串常量是以空字符’\0’作为结束标志。 3.字符串如果不用数组存储那必须要有指针来存储。并且该指针指向的是字符串首字符的地址。 我们如果想让两个字符串合并成一个字符串 给定一个想法 先计算出两个字符串长度计算总长度多少 利用malloc函数开辟一个大小为总长度的空间 将两个字符拷贝过去 注意事项 1.如果利用stren计算字符串长度请记住最后的结果要加上1因为strlen遇到’\0’就停止。最后并没有将’\0’计算进去。 2.malloc申请的空间可能失败需要判断 3.malloc申请的空间在程序结束之前需要释放 ③.作为参数的数组声明 在C语言中我们虽然没有办法将一个数组作为函数参数之间参过去因为不知道数组有多大如果超级大那操作系统可能无法提供足够的空间。 但如果我们使用数组名作为参数那么数组名会立刻被转化为指向该数组第一个元素的指针。 数组传参和指针传参 写代码时难免要把数组或者指针传给函数那函数的参数该怎么设计呢 3.1一维数组的传参 void test(int arr[])//数组传参数组接收 {} void test(int arr[10])//跟上面一样 {} void test(int* arr)//数组传参指针接收 {} void test2(int* arr[20])//数组传参指针接收 {} void test2(int** arr)//数组传参指针接收 {} 因为数组名就是首元素的地址所以数组名传参可以用数组来接收也可以用地址来接收只不过要注意接收的是一级指针还是二级指针。 int main() {int arr[10] { 0 };int* arr2[20] { 0 };test(arr);test2(arr2);return 0; }3.2二维数组的传参 void test(int arr[3][5])//ok二维数组传参二维数组接收 {} void test(int arr[][])//ok这个可不行喔 {} void test(int arr[][5])//ok跟第一个一样注意点二维数组传参函数参数的设计只能省略第一个[ ]的数字。 因为对于一个二维数组可以不知道到多少行但不能不知道一行多少个元素。这样才方便运算。 void test(int *arr)//ok还记得上面说的吗二维数组的数组名相当于第一行的数组地址所以是类型是数组指针类型的应该用数组指针来接收 {} void test(int* arr[5])//ok不行这是个指针 {} void test(int (*arr)[5])//ok这个可以是数组指针指针指向一个五个整形的数组 {} void test(int **arr)//ok不行这个是二级指针 {} int main() {int arr[3][5] {0};test(arr);}3.3一级指针传参 //用一级指针来接收 void print(int *p, int sz) {int i 0;for(i0; isz; i){printf(%d\n, *(pi));} } int main() {int arr[10] {1,2,3,4,5,6,7,8,9};int *p arr;int sz sizeof(arr)/sizeof(arr[0]);//一级指针p传给函数print(p, sz);return 0;}想一想当函数参数为一级指针时可以接收上面参数呢 void test1(int * p) { } //test1函数能接收什么参数 void test2(char* p) { } //test2函数能接收什么参数 3.4二级级指针传参 void test(int** ptr) {printf(num %d\n, **ptr); } int main() {int n 10;int*p n;int **pp p;test(pp);//pp是二级指针test(p);//p是一级指针p就应该用二级指针来接收了return 0;}当函数的参数为二级指针的时候可以接收什么参数 void test(char**p) {} int mian() {char cb;char *pcc;char**pccpc;char *arr[10];test(pc);//指针的地址需要二级指针接收test(ppc)//二级指针二级指针接收test(arr);//数组名表示首元素地址每个元素的类型是char类型的指针然后再取地址当然可以用二级指针接收。 }④.避免举隅法 什么叫举隅法,就是以整体代表部分或者以部分代替整体。 在C语言我们会遇到常见的陷阱混淆指针与指针所指向的数据。 对于字符串的情形我们更是经常犯错误。 比如 char *p,*q; pabc;我们可能一开始初学时认为上面的赋值语句将字符串abc赋给了p 然而实际上并不是这样要记住字符串的不同之处。 实际上p的值是一个指向由’a’,‘b’,‘c’,\0’四个字符组成的数组的起始字符的指针。 如果我们执行下面的语句 qp;让p和q同时指向用一块空间但这个赋值语句并没有将p的数据 赋值给q 只是改变了p原来的指向而已。 所以我们要记住复制指针并不同时复制指针所指向的数据。 ⑤.空指针并非空字符串 在C语言中将一个整数转化为一个指针最后得到的结果都取决与具体的C编译器实现。但有个特殊情况那就是常数0编译器保证由0转化而来的指针不等于任何有效的指针。 所以0通常被写成NULL #define NULL 0;无论是用常数0还是用符号NULL效果是一样的。 但是要记住的重点是 注意 当常数0被转化为指针使用时这个给指针就不能再被访问解引用了。 也就是当使用NULL时就不能再去企图访问这个指针指向的内容了一旦访问就会造成非法。 比如下面这样 char *pNULL; char *labc; if(strcmp(l,p)0);这样就非法访问了因为库函数strcmo的使用会查看它的指针参数所指向内存中的内容的操作因为p为空指针如果访问它就会非法。 printf(p); printf(%s,p);以上两个写法也是未定义的。在不同的环境会出现不同的效果。 ⑥.边界计算与不对称边界 a[10];在C语言中数组下标的范围是0-9,大家应该都不陌生。 而在有些语言中数组下标是1-11有的是0-10等等。 今天我们就来探究一下C语言这样设计的动机是什么。 6.1 死循环问题 我们先来看一段代码 int main() {int i;int arr[] { 1,2,3,4,5,6,7,8,9,10 };for (i 0; i 12; i){printf(xiao tao\n);arr[i] 0;}return 0; }这段代码的本意是要将数组a中所有的元素置为0但却产生了一个出乎意料的副作用,在for语句中比较部分本来是i10,却写成了12因此实际上并不存在的a[10],a[11]都被设置为0也就是内存中在在数组后面的数据被设置为0。然后最终该程序变成了死循环下面将会详细的讲解为什么会出现这样的情况但该部分不是本篇重点如需知道下面的知识请跳过。 你觉得该代码有什么问题呢? 1.越界访问 2.死循环第一个问题越界访问非常容易看出来数组arr只有10个元素下标从0-9而循环12次肯定越界访问了 每次都会打印一个xiao tao并且把对应的arr[i]置为0。 所以最后答案应该就是打印了12次xiao tao然后越界访问出现错误使arr[10]0,arr[11]0了 但最后答案却不是这样。 答案变成了死循环了死循环打印xiao tao 6.1.1死循环的原因是什么呢 这里涉及有关栈空间的知识 1. 内存空间分为栈区堆区和静态区栈区一般存放局部变量函数参数函数返回值等 堆区是用来分配动态开辟的空间的 静态区是存放全局变量static修饰的静态变量等2.局部变量是在栈区存放的 3.栈区的使用习惯 先使用高地址处的空间 再使用低地址处的空间4.数组的地址随着下标的增长地址是由低到高变化的注意 该测试是在VS2019 X86环境下进行其他环境可能不一样结果也就不一样不能一概而论。 在变量i与数组之间一定有两个整形空间吗 答案不一定。 在VS2019 X86环境下变量i与数组之间确实空了两个整形变量空间大小。 而在VC6.0环境下变量i与数组之间没有剩余空间。 在gcc环境下变量i与数组之间有一个整形空间大小 6.1.2解决方法 可能有的人会这样想将变量i定义在数组的下面这样就不会发生死循环了 我们从栈空间使用方面来看这样当然可以避免死循环但是难道我们以后写数组都要把i写在数组的后面吗 这样只能解决当前的问题而不能解决根本。不过现在的编译器大多数会自己修改这个死循环问题比如将变量的i的地址放在数组的下面在release版本就是这样进行优化不会死循环。 我们一般可能想不到这样本质原因但我们可以通过调试来解决这个问题 当让i不断的当i等于10时将arr[10]置0当i等于11时将arr[11]置0然后我们通过调试监视发现arr[12]与i的值相等这时我们就要想到为什么会死循环了arr[12]的地址就等于i的地址将arr[12]修改成0就等于将i改为0了。 将arr[12]置0发现i也变成0了 6.1.3总结 其实这道题是在特殊环境下才能实现的但我们还是要注意的是其中的知识点 1.栈区的使用习惯 先使用高地址的空间 再使用低地址的空间 2.数组随着下标的增长地址不断增大 6.2 边界问题 在所有常见的程序设计错误中最难于察觉的一类是栏杆错误也常被称为差一错误其实总结起来都是边界问题。 比如100米长的围栏每隔10米就需要一根支撑用的栏杆那一共需要多少根栏杆呢 ”显而易见“答案是10不就是100处以10嘛得到结果10需要10根栏杆。 这个答案是错误的正确答案是11根。 仔细想一想一开始支持这10米长的围栏需要两个跟两端各一根然后从第二根开始往后计数每个10米要一根最后加起来就是101 这个1是一开始没有计算的那根。 6.2.1两个原则和一个编程技巧 为了避免”栏杆错误“总结以下两个原则 首先考虑最简单情况下的特例然后将得到的结果往外推。 仔细计算边界绝不能掉以轻心 一个编程技巧 用一个入界点和第一个出界点来表示一个数组范围。 比方说整数x满足x16且x48; 求满足整数x的个数是多少呢 我们可以利用编程技巧将它转变以下 写成x16且x49; 这里的下界就是”入界点“即包含在取值范围之中而上界是”出结点“即不包含在取值范围内。 虽然这样形成了两个不对称左边带有等于右边不带有等于但编程效果是极佳的因为最后的答案就是上界-下界。 对于像C这样的数组下标从0开始的语言不对称边界给程序设计代来了许多便利。 为什么呢 因为这样数组的上界恰是数组元素的个数 因此如果我们要在C语言中定义一个拥有10各元素的数组那么0就是数组下标的第一个入界点而10就是下标中的第一个出界点。 我们经常这样写 int a[10],i; for(i0;i10;i) { a[i]10; }而不是这样写 int a[10],i; for(i1;i10;i) { a[i]10; }是有道理的。所以我们在控制循环时设置变量的范围是通常是设置为不对称形式而不设置称对称形式。 6.3 边界访问 ANSIC标准明确允许这样的用法 数组中实际不存在的”溢界“元素的地址位于数组所占内存之后这个地址是可以用于进行赋值和比较但是如果要引用该元素那就是非法的了。 什么意思呢 就是数组最后一个元素的后面那块空间地址是允许拿来进行赋值和比较的但不允许访问。 该准则与上面的”不对称边界“原则是一致的空间上也形成不对称但是要记住不能访问!!!.一旦访问就是非法访问了。 ⑦.求值顺序 上篇博客我写了关系运算符优先级之间的问题但本篇讲的是求值顺序与它并不相同。 C语言只有4各运算符 和|| 和和存在着规定的求值顺序。其他运算符对其操作数求值的顺序是未定义的。特别的赋值运算符并不保证任何求值顺序 1.条件运算符;有三个操作数在a?b:c中操作数a首先被求值然后根据a的值再去求操作数b或c的值。 2.而逗号运算符首先对左侧操作数求值然后该值被”丢弃“再对右侧操作数求值 7.1短路求值和|| 逻辑与逻辑或||存在着短路求值 什么叫短路求值呢就是首先对左侧操作数求值只有当需要时才会对右侧操作数进行求值。 3.逻辑与 表达式1表达式2 表达式1为假则右边不再进行。 4.逻辑或|| 表达式1||表达式2 表达式1为真则右边不再进行。 int main() {int i 0, a 0, b 2, c 3, d 4;i a b d;printf(a %d\n b %d\n c %d\nd %d\n, a, b, c, d);return 0; } 因为 i a b d; a是后置先使用后所以a0先使用与进行配对然后是假 所以后面b d都不再进行但a这个还是进行的所以a用完后还要给a1 所以a1b2c3d4int main() {int i 0, a 0, b 2, c 3, d 4;i a||b||d;printf(a %d\n b %d\n c %d\nd %d\n, a, b, c, d);return 0; } 这里aa0先使用与||配对为假再1bb自增为3与||配对为真后面的d不再进行了所以 a1,b3,c3,d4;⑧.整数溢出 C语言中存在着两类整数算术运算有符号运算与无符号运算。在无符号算术中没有所谓的”溢出“一说所有的无符号数运算都是以2的n次方为模这里的n是结果中的位数。 如果算术运算符中一位是有符号一个是无符号的有符号的会先转化成无符号数然后进行运算。 当两个操作数都是有符号数时才可能发现”溢出“而且溢出的结果是未定义的。当一个运算的结果发生”溢出“时做出任何假设都是不安全的。 那如何进行检查两个操作数进行运算时是否”溢出“呢 一种正确的方式是将a和b都强制转化为无符号整数 if( (unsigned)a(unsigned)bINT_MAX ) exit(1);这里的INT_MAX是表示最大整数值。 不需要用到无符号算术运算的另一种可行方法是 if(aINT_MAX-b) exit(1);⑨.main函数的返回值 main() { }函数main什么都没写与其他任何函数一样如果没有显示声明返回类型那么函数返回类型就默认为整形。但是这个程序也没有给出任何返回值。 按理说这样不会造成什么危害。一个返回值为整形的函数如果返回失败实际上是返回了某个”垃圾“整数。只要不用到该整数就问题不大。 但严格来说大多数C语言实现是通过函数main的返回值来告知操作系统该函数的执行是否成功。 典型的处理就是main函数返回值为0表示执行成功返回非0表示执行失败。 #include stdio.h int main() {printf(hello world\n);return 0; }#include stdio.h int main() {int arr[10], i;for (i 0; i 11; i){arr[i] 0;}return 0; }如果一个程序的main函数并不返回任何值那么有可能看上去执行失败。 所以即使是最简单的C程序也应该像这样编写代码 #include stdio.h int main() {printf(hello world\n);return 0; }
http://www.w-s-a.com/news/241688/

相关文章:

  • dw网站开发删除wordpress主题底部
  • 织梦网站怎样做子域名高德导航怎么看街景地图
  • 宿州专业网站建设株洲网站建设优化
  • 自动生成海报的网站常州建网站公司
  • 网站刷流量对网站有影响吗站长工具欧美高清
  • 百度做网站优化多少钱一年罗庄网站建设
  • 手机网站 自适应屏幕h5网站有哪些
  • 北京企业建站技术临沂网站公众号建设
  • 域名和网站备案一样吗wordpress 封装 app
  • 婚纱摄影网站开题报告c2c模式是什么意思
  • 网站几种颜色wordpress水平菜单
  • php做网站的分站wordpress边下边看
  • 杭州建设实名制报备网站Wordpress外贸网站搭建公司
  • 山西云起时网站建设计算机网站开发实现总结
  • 一个网站做两个优化可以做吗永清网站建设
  • wordpress英文采集wordpress seo 链接
  • 进入建设银行的网站就打不了字工程建设标准化网站
  • 杭州网站推广大全网站建设演讲稿
  • 厦门网站的制作太仓专业网站建设
  • 天津公司网站建设公司哪家好在阿里巴巴国际网站上需要怎么做
  • 网站关键词seo推广公司哪家好无锡市无锡市住房和城乡建设局网站
  • 开远市新农村数字建设网站网站如何做QQ登录
  • 自己做个网站教程高端网站开发哪家强
  • 网站模板免费下载中文版大连网站建设哪家专业
  • 网站建设的基本代理公司注册公司坑人
  • 企业网站被黑后如何处理wordpress邮件发送类
  • 北京网站的网站建设公司建设工程竣工验收消防备案网站
  • 淄博市 网站建设报价wordpress里的发消息给我
  • 网站下拉菜单怎么做游戏网站模板免费下载
  • 阿里云上做网站套模板怎么做一个网站开发小组