c提高

Posted wzg31796

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;

以上是关于c提高的主要内容,如果未能解决你的问题,请参考以下文章

C 中的共享内存代码片段

22.java方法的定义

[linux][c/c++]代码片段01

C语言代码片段

Sublime Text自定制代码片段(Code Snippets)

c_cpp Atlas300代码片段