c提高

一.内存管理:

内存四区:

1.一个C语言变量的作用域可以是代码块 作用域,函数作用域或者文件作用域。

代码块是{}之间的一段代码

2.register寄存器变量

通常变量在内存当中,如果能把变量放到CPU的寄存器里面,代码执行效率会更高

register int I

3.全局函数和静态函数

在C语言中函数默认都是全局的,使用关键字static可以将函数声明为静态,静态函数只能在当前函数内使用

4.代码区

代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的。

5.静态区

所有的全局变量以及程序中的静态变量都存储到静态区,比较如下两段代码的区别


int a =0;

int main()

{

staticint b =0;

printf("%p, %p\n", &a, &b);

return0;

}


int a =0;

staticint b =0;

int main()

{

printf("%p, %p\n", &a, &b);

return0;

}

6.栈区

栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出。

7.堆heap和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。

堆是一个大容器,它的容量要远远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。

8.堆的分配和释放:

malloc:void *malloc(size_t  _size);  malloc函数在堆中分配参数_size指定大小的内存,函数返回void *指针

free:void free(void *p);  free负责在堆中释放malloc分配的内存,参数p为malloc返回的堆中的内存地址

9.malloc、free用法示例:三种结果相同,区别指针用法

第一种:

void getp(int *p){
	printf("%x\n", p);  //31fa48
	printf("%x\n", &p);  //31f974
	printf("%x\n", *p);  //0
	printf("%x\n", *(&p));   //31fa48
	printf("%x\n", **(&p));   //0

	*p = malloc(sizeof(int) * 10);

}
int main()
{
	int *p = NULL;

	printf("%x\n", &p);   //31fa48

	getp(&p);
	p[0] = 1;
	printf("%d\n", p[0]);
	free(p);
	return 0;
}

第二种:

void getp(int **p){
	printf("%x\n", p);  //31fa48
	printf("%x\n", &p);  //31f974
	printf("%x\n", *p);  //0
	printf("%x\n", *(&p));   //31fa48
	printf("%x\n", **(&p));   //0

	*p = malloc(sizeof(int) * 10);

}
int main()
{
	int *p = NULL;

	printf("%x\n", &p);   //31fa48

	getp(&p);
	p[0] = 1;
	printf("%d\n", p[0]);
	free(p);
	return 0;
}

第三种:

void getp(int *p){
	printf("%x\n", p);  //31fa48
	printf("%x\n", &p);  //31f974
	printf("%x\n", *p);  //0
	printf("%x\n", *(&p));   //31fa48
	printf("%x\n", **(&p));   //0

	**(&p) = malloc(sizeof(int) * 10);

}
int main()
{
	int *p = NULL;

	printf("%x\n", &p);   //31fa48

	getp(&p);
	p[0] = 1;
	printf("%d\n", p[0]);
	free(p);
	return 0;
}

第四种:

int *getp()
{
	return malloc(100);
}
int main(){
	int *p = NULL;

	p = getp();

	free(p);
	return 0;
}

10.操作系统在管理内存的时候,最小单位不是字节,而是内存页

11.malloc申请的内存是随机的,不连续的,如果想要申请连续内存空间,可以用calloc,calloc用法跟malloc相同,如果malloc或calloc申请的内存空间不够用,想要申请更多空间,可以用realloc,realloc会在原有内存的基础之上,在堆中间增加连续的内存空间,如果原有内存没有连续空间可扩展,就会新分配一个空间,将原有内存copy到新内存,然后释放原有内存

malloc跟realloc分配的内存都不是连续的;

memset:把malloc或realloc申请的不连续的内存空间变成连续的

写法:

char *p=malloc(10);

char *p1=calloc(10,sizeof(char));

char *p2=realloc(p1, 20);  //在原有内存p1基础上,在堆中增加内存

char *p3=realloc(NULL ,  5);   //等同于malloc(5)

memset(p , 0 ,10);   //将不连续的p内存空间变成连续的,从第0个到第10个

12.static int f=0;用static声明的变量会在整个进程运行期间一直有效,是在静态区,但只能在当前函数内使用

13.如果一个函数要修改另一个函数的静态变量的值,可以通过调用函数的方式将这个静态变量返回然后对其修改

14.堆内存的使用情况:

情况一:int set[1000];   此时set数组在栈中,超过了栈的存储空间,,可以用malloc在堆中创建超大数组。int *set=malloc(sizeof(int)* 100000);

情况二:int i=0;  scanf("%d",&i); int array[i];  这种方式创建动态数组会报错,,应该用malloc创建动态数组。int *array=malloc(sizeof(int)*i);

二.结构体:

结构体的定义与使用

structman
{
   char name[100];
   int age;
};
struct man m = { "tom", 12 };
struct man m= { .name = "tom", .age = 12 };

1.结构体在内存中是个矩形,而不是一个不规则形状

2.结构体在内存的大小取决于结构体中的内容,同样是int4个字节,char1个字节,但是结构体是4的倍数大小,例:A的大小为8个字节,B的大小为12个字节,c也12个字节

struct A{
	int a;
	char b;
	char c;
}
struct B{
	int a;
	int b;
	char c;
}
struct C{
	char a;
	int b;
	char c;
}

结构体内存大小是以最大长度的内容对齐的,例:D结构体最大长度字节为long long 8个字节,所以都以8对齐,上面的ABC以int(4个字节)对齐,D的大小为24个字节

struct D{
	char a;
	short b;
	char c;
	int e;
	long long d;
}

写成这种方式16个字节:因为short是以2对齐的

struct D {
	char c;
	char a;
	short b;
	int e;
	long long d;
}

3.定义一个结构体的时候可以指定具体元素的位长

	struct test{
		char a : 2;//指定元素为2位长,不是2个字节长
	};

4.结构数组:structman
m[10] = { {"tom",12
}, {"marry",10
}, {"jack",9
} };

5.一个结构体的成员还可以是另一个结构体

struct names{
		char first[100];
		char last[100];
	};

	struct man{
		struct names name;
		int age;
	};
	struct man m = { { "wang", "wu" }, 20 };

6.结构体变量之间可以互相赋值(区别数组)

struct str{

	char s[100];
};
int main(){

	struct str s1, s2;
	strcpy(s1.s, "hello");//把hello赋给s1.s

	//s2 = s1;<span style="white-space:pre">	</span>//把s1赋给s2和下面一行代码相同

	//memcpy(&s2, &s1, sizeof(s1));
	printf("%s\n", s2.s);
	return 0;
}

7.指向结构体的指针:定义方式

struct str a;
struct str *p = &a;
(*p).a = 10;
(*p).b= 20;
上面的定义方式等同于下面
p->a = 10;
p->b = 20;

指针使用示例:

struct A{
	int a;
	int b;
};

struct A array[10] = { 0 };
p = array;
p->a = 1;
p->b = 2;
p++;
p->a = 3;
p->b = 4;

也可以在堆中申请内存创建数组:

struct A{
	int a;
	int b;
};
p = malloc(sizeof(struct A) * 10);
struct A *array = p;

p->a = 1;
p->b = 2;
p++;
p->a = 3;
p->b = 4;

free(array);

7.当结构体中有指针,不能直接给结构体内的指针多次赋值,多次赋值要申请内存

struct str{
	char *name;
	int age;
};

int main(){
	struct str st = { NULL,0 };
	st.age = 30;
	st.name = malloc(100);
	strcpy(st.name, "吴志刚");
	printf("%d,%s\n", st.age, st.name);
	free(st.name);
	return 0;
}

8.结构体作为参数:

struct st{
	char name[1000];
	int age;
};
void print_student(struct student s){
	printf("name=%s,age=%d\n", s.name, s.age);
}
void set_student(struct student s,const char *name,int age){
	strcpy(s->name, name);
	s->age = age;
}
int main(){

	struct student st = { "tom",20 };
	set_student(&st, "mike", 100);
	print_student(st);  //结果打印出mike  100
	return 0;
}

定义一个结构体作为参数的时候,尽量使用指针,而不是使用结构变量,这样代码效率高

9.联合体:

联合union是一个能在同一个存储空间存储不同类型数据的类型。

联合体所占的内存长度等于其最长成员的长度,也有叫做共用体。

联合体虽然可以有多个成员,但同一时间只能存放其中一种。

对于联合体来讲最基本的原则是,一次只操作一个成员变量,如果这个变量是指针,那么一定是处理完指针对应的内存之后再来使用其他成员。


unionvariant{

int ivalue;

char cvalue;

double dvalue;

};

int main()

{

union variant var;

var.cvalue =
12;

printf("%d\n", var.ivalue);

printf("%p, %p, %p\n", &(var.cvalue), &(var.ivalue), &(var.dvalue));

return0;

}

三.枚举类型

可以使用枚举(enumeratedtype)声明代表整数常量的符号名称,关键字enum创建一个新的枚举类型。

实际上,enum常量是int类型的。

枚举的本质就是int型的常量。


enumspectrum {red,yellow,green,blue,
white,
black };

enumspectrum color;

color =
black;

if (color !=
red)

1.默认值

默认时,枚举列表中的常量被指定为0,1,2等


enumspectrum {red,yellow,green,blue,
white,
black };

printf("%d, %d\n",red,black);

指定值

可以指定枚举中具体元素的值


enumspectrum {red =10,yellow
=20,green,blue,
white,
black };

printf("%d, %d\n",red,black);

四.typedef:

typedef是一种高级数据特性,它能使某一类型创建自己的名字


typedef
unsigned char
BYTE

1.与#define不同,typedef仅限于数据类型,而不是能是表达式或具体的值

2.typedef是编译器处理的,而不是预编译指令

3typedef比#define更灵活

直接看typedef好像没什么用处,使用BYTE定义一个unsigned char。使用typedef可以增加程序的可移植性。

4.通过typedef定义函数指针


typedefconstchar *(*SUBSTR)(constchar
*,const char *);

constchar *getsubstr(constchar *src,constchar
*str)

{

return strstr(src,str);

}

const
char *func(const
char *(*s)(constchar *,constchar *),
const char *src,constchar *str)


const
char *(*p[3])(constchar *,constchar *);

在程序当中如果是定义一个可读的常量,适合用#define

如果定义的是一个具体的数据类型,那么typedef更加适合。

如果是定义一个函数指针,那么基本就typedef吧.

五.文件操作

1.不论操作什么类型的文件,第一步先打开一个文件,第二步,读写文件,第三步关闭文件。

2.fopen

r 以只读方式打开文件,该文件必须存在。

r+ 以可读写方式打开文件,该文件必须存在。用r+写文件时候,从文件开始位置写入

rb+ 读写打开一个二进制文件,允许读写数据,文件必须存在。

rw+ 读写打开一个文本文件,允许读和写。

w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。

wb

w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。

a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留),如果文件不存在,a的行为和w是一样的

a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)

“b”只对windows有效,对于unix来讲是无效,

3.文件操作helloworld案例:

写入文件

int main(){

	char s[1024] = { 0 };
	FILE *p = fopen("D:\\temp\\a.txt", "w");//用写的方式打开一个文件
	//w意思就是如果文件不存在,就建立一个,如果文件存在就覆盖
	while(1){
		memset(s, 0, sizeof(s));
		gets(p);
		if (strcmp(s, "exit") == 0)
			break;
		int len = strlen(s);
		s[len] = '\n';
		fputs(s, p);
	}
	fclose(p);//关闭这个文件
	printf("end\n");
	return 0;
}</span>

读出文件:

int main() {

	char s[1024] = { 0 };
	FILE *p = fopen("D:\\temp\\a.txt", "r");//用读的方式打开一个文件
	while (!feof(p)) {						//feof(p)如果已经到了文件结尾,函数返回真
		memset(s, 0, sizeof(s));
		fgets(s, sizeof(s), p);
		printf("%s", s);
	}
	fclose(p);//关闭这个文件
	return 0;
}</span>

4.二进制和文本模式的区别

——在windows系统中,文本模式下,文件以"\r\n"代表换行。若以文本模式打开文件,并用fputs等函数写入换行符"\n"时,函数会自动在"\n"前面加上"\r"。即实际写入文件的是"\r\n" 。

——在类Unix/Linux系统中文本模式下,文件以"\n"代表换行。所以Linux系统中在文本模式和二进制模式下并无区别。

对于GBK编码的汉字,一个汉字两个字节,对于utf8来讲一个汉字3个字节,但如果英文字母都是一个字节

5.getc和putc函数


int main()

{

FILE *fp = fopen("a.txt",
"r");

char c;

while ((c = getc(fp)) !=EOF)

{

printf("%c", c);

}

fclose(fp);

return0;

}


int main()

{

FILE *fp = fopen("a.txt",
"w");

constchar *s ="hello world";

int i;

for (i =0; i < strlen(s); i++)

{

putc(s[i], fp);

}

fclose(fp);

return0;

}

6.EOF与feof函数文件结尾

程序怎么才能知道是否已经到达文件结尾了呢?EOF代表文件结尾

如果已经是文件尾,feof函数返回true。

7.fprintf,fscanf,fgets,fputs函数(都是操作文件的一行,不是单个字符)

这些函数都是通过FILE*来对文件进行读写。

——fprintf:功能和printf一样,fprintf是把数据输出到文件中,fprintf(p,"%s" ,buf);  p是要输出的文件,buf是输出的值

——fscanf与scanf用法基本一致,fscanf是从一个文件读取输入,scanf是从键盘读取输入,用法:fscanf(p , "%s"  ,buf);第一个参数是获取文件内容的指针,第二三个参数与scanf相同,fscanf不会读取行尾的’\n’,

——fgets会将行尾的’\n’读取到buf里面,用法:

int main() {

	FILE *p = fopen("D:\\temp\\a.txt", "r");//用读的方式打开一个文件
	while (!feof(p)) {//feof(p)如果已经到了文件结尾,函数返回真

		char s[1024] = { 0 };
		memset(s, 0, sizeof(s));
		fgets(s, sizeof(s), p);  //通过p读取文件内容赋值给s,第二个参数控制读取数据多少
		printf("%s", s);
	}
	fclose(p);//关闭这个文件
	return 0;
}

不论fprintf还是fputs都不会自动向行尾添加\n,需要代码中往buf的行尾写\n才可以达到换行的目录

8.stat函数

#include <sys/stat.h>

函数的第一个参数代表文件名,第二个参数是structstat结构。

得到文件的属性,包括文件建立时间,文件大小等信息。

9.fseek函数

函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere为基准,偏移offset(指针偏移量)个字节的位置,函数返回0。如果执行失败则不改变stream指向的位置,函数返回一个非0值。

实验得出,超出文件末尾位置,还是返回0。往回偏移超出首位置,还是返回0,请小心使用。

第二个参数负数代表向前移动,整数代表向后移动。

第一个参数stream为文件指针

第二个参数offset为偏移量,单位:字节,正数表示正向偏移,负数表示负向偏移

第三个参数origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET

SEEK_SET: 文件开头

SEEK_CUR: 当前位置

SEEK_END: 文件结尾


fseek(fp, 3,
SEEK_SET);

10.ftell函数

函数ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数。在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置。


longlen=ftell(fp)

11.fgetpos,fsetpos函数

fseek与ftell返回的是long类型,如果文件很大,超过long的范围,那么该函数会有问题,fgetpos与fsetpos函数可以处理更大的文件类型

返回值:成功返回0,否则返回非0


fpos_t ps = 0;

fgetpos(fp, &ps);


fpos_t ps = 2;

fsetpos(fp, &ps);

12.fflush函数

fflush函数可以将缓冲区中任何未写入的数据写入文件中。

修改配置文件,希望修改实时生效,那么每次修改完成之后我们fflush一次

13.fread和fwrite函数

size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);

注意:这 个函数以二进制形式对文件进行操作,不局限于文本文件

返回值:返回实际写入或读取的数据块数目

只要读取到文件最后,没有完整的读取一个数据块出来,fread就返回0

第一个参数代表void *,写入或者读取的缓冲区

第二个参数是代表写入或读取的时候最小单位的大小

第三个参数是代表写入或读取几个单位

第四个参数是FILE *

14.fread与feof

注意以下两段代码的区别


while (!feof(p))

{

fread(&buf,
1, sizeof(buf), p);

}


while (fread(&buf,1,sizeof(buf), p))

15.从一个文件读出数据,然后对其排序,又写入另一个文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void swap(int *a, int *b)//交换参数的值
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void pupple(int *p, int n)//冒泡排序
{
    int i;
    int j;
    for(i = 0; i< n; i++)
    {
        for(j = 1; j < n - i; j++)
        {
            if (p[j - 1] > p[j])
            {
                swap(&p[j - 1], &p[j]);
            }
        }
    }
}

int main(void)//在堆建立一个数组对文件内容进行排序
{
    int index = 0;//这是个计数器
    char buf[100];

    FILE *p = fopen("D:\\temp\\a.txt", "r");//第一次打开a.txt目的是要知道这个文件有多少行
    while(!feof(p))//如果没有到达文件结尾,那么循环继续,第一次循环的时候并不是要处理文件的内容,只是统计文件的行数
    {
        memset(buf, 0, sizeof(buf));//每次读取文件一行之前都把这个buffer清空
        fgets(buf, sizeof(buf), p);//从文件中读取一行
        index++;
    }
    fclose(p);

    int *array = calloc(sizeof(int), index);//在堆中建立一个动态数组,动态数组的成员数量和a.txt文件的行一样多

    p = fopen("D:\\temp\\a.txt", "r");
    index = 0;//计数器从0重新开始
    while(!feof(p))//如果没有到达文件结尾,那么循环继续
    {
        memset(buf, 0, sizeof(buf));//每次读取文件一行之前都把这个buffer清空
        fgets(buf, sizeof(buf), p);//从文件中读取一行
        array[index] = atoi(buf);//将读取到的一行转化为int,赋值给数组成员
        index++;
    }
    fclose(p);
    pupple(array, index);//将数组排序
    p = fopen("D:\\temp\\b.txt", "w");//用写的方式打开b.txt
    int i;
    for(i = 0; i < index; i++)
    {
        memset(buf, 0, sizeof(buf));//每次操作之前都把buffer清空
        sprintf(buf, "%d\n", array[i]);//将数组的成员转化为字符串
        fputs(buf, p);
    }
    fclose(p);
    return 0;
}
时间: 2024-10-13 12:04:36

c提高的相关文章

使用JDBC如何提高访问数据库的性能?

1. 使用数据连接池(Connection Pool), 避免使用DriverManager.getConnection. 2. 合理的配置数据连接池参数,设置数据连接池的初始大小,最大连接数,连接超时时间等. 3. 选择合适的事务等级,按照不同的数据库操作类型选择不同的事务等级. 4. 及时关闭Connection,不关闭的话会严重影响系统的性能,甚至造成系统罢工. 5. 优化Statement 1) 选择合适的Statement, 根据不同的数据库操作选择Statement, Prepare

如果提高工作效率(转载)

效率由心生,快速提高工作效率秘诀 来源: Veda原型  发布时间: 2012-03-19 15:13  阅读: 2348 次  原文链接   全屏阅读  [收藏] 现代人都很忙,但忙的可能没有效率,可能在"忙人"摸象,也就是瞎忙.也许你的效率可以提升20倍,也许你的激情和潜能可以提升10倍!秘诀就在于目标管理.时间管理.精力管理.如何在短时间内完成更多的事情.如何从痛苦的修行中悟道.如何尊崇内心的自由.如何有更多的时间去享受生活.如何动态平衡工作和生活?!这里有能大大提升工作效率和时

[NOIP2009] 提高组 洛谷P1073 最优贸易

题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路,双向通行的道路在统计条数时也计为 1 条. C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价 格不一定相同.但是,同一种商品在同一个城市的买入价和卖出价始终是相同的. 商人阿龙来到 C 国旅游.当他得知同一种商品在不同城市的价格可能会不同这一信息 之后,便决定在旅游的

2016年程序员如何提高自己的方法有哪些?

作为软件开发行业,新技术在不断的更新,如何在新的时代实现自己的人生价值,唯一的办法就是为自己树立一个更高的目标,一个人有了目标后就会有了努力的方向,那么在2016年程序员如何提高自己的方法有哪些?新霸哥简单的总结了一下主要的有下面的这些方面来努力就能有所作为的. 一,方向很重要,选好方向才有学习的动力 如今技术新技术在不断的被挖掘出来,选择一个合适的方向是很重要的.新霸哥觉得有些技术虽然很重要但是不是任何人都能掌握的,遇到这种情况的时候首先要学会取舍,舍弃看不懂的知识,与其在一个不懂的问题上长期

关于提高字节流问题暨第四次java作业

import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException; public class CopyFile { /** * @param args */ public static void main(String[] args) { try { FileInputStream fis = new FileInputStream ("a.mp3"); FileOutpu

(转载)提高ASP.NET Web应用性能的技巧

在这篇文章中,将介绍一些提高 ASP.NET Web 应用性能的方法和技巧.众所周知,解决性能问题是一项繁琐的工作,当出现性能问题,每个人都会归咎于编写代码的开发人员. 那性能问题到底该如何解决?以下是应用系统发布前,作为 .NET 开发人员需要检查的点. 1.debug=「false」 当创建 ASP.NET Web应用程序,默认设置为「true」.开发过程中,设置为「true」是非常有用多,但在应用程序发布部署时,需将其设置为「false」. ? 1 <compilation default

JavaScript 总结几个提高性能知识点

前段时间花时间看了大半的<High Performance JavaScript>这本书啊,然后就开始忙项目了,庆幸最忙的一周已经熬过去了.由于空不出时间,这个月写的学习笔记也不多,忙完最苦X的一周,这两天晚上也算是挑灯夜读了...终于是在残血之际将这本书shut down了... 既然读完了,总归是要学到些什么的.说说对这本书的看法先吧,整体的来说,内容还是不错的,就是感觉有点老了(作为前端小白,也可能是自身水平有限,未能体会到其中真意).看这本书的过程中也是写了挺多代码用以测试的,并且对本

《机器学习实战》学习笔记:利用Adaboost元算法提高分类性能

一. 关于boosting算法的起源 boost 算法系列的起源来自于PAC Learnability(直译过来称为:PAC 可学习性).这套理论主要研究的是什么时候一个问题是可被学习的. 我们知道,可计算性在计算理论中已经有定义,而可学习性正是PAC Learnability理论所要定义的内容.另外,在计算理论中还有很大一部分精力花在研究问题是可计算的时候,其复杂度又是什么样的.因此,在计算学习理论中,也有研究可学习的问题的复杂度的内容,主要是样本复杂度 (Sample Complexity)

IOS基础知识提高

第三章类/属性/方法/选择器 1.区分类和对象,类是具有相同属性和行为的一组对象的集合,而对象是具体存在的实体,就有明确定义的状态和行为 2.OO最基本的思想:抽象法 抽象法可以帮助我们发现事物的因果,结构和表现形式,区分主要和次要 3.Objective-c文件扩展名 .h类的头文件,声明class,type,function,constant: .m类的实现源文件,可以包含Objective-c和c代码: .mm可以包含Objective-c和c语言C++代码 [email protecte

SQL中使用WITH AS提高性能,使用公用表表达式(CTE)简化嵌套SQL

一.WITH AS的含义     WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNION ALL的不同部分,作为提供数据的部分. 特别对于UNION ALL比较有用.因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可.如果WITH AS短语所定