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提高的主要内容,如果未能解决你的问题,请参考以下文章