Repick up C:Pointers and dynamic memory

60 阅读6分钟

image.png

image.png

程序开始执行时,OS就分配了内存,用来存放栈,假设分配了1M,实际局部变量和栈帧的分配是在运行时,如果运行时栈帧增长的大小超过预留的大小,如果有无穷递归,bad,所以在运行中是不允许栈增长的,超过预先分配的空间大小,就会导致崩溃。栈大小在开始运行的时候就已经固定了。

局部变量里,有个很大的数组,但是数组大小需要根据具体参数来定,这时需要用到堆(heap)。在应用程序的整个生命周期,大小是不固定的。ps:这里的堆和数据结构里的堆不同,此处堆为空闲的内存池。

image.png

image.png

动态分配的内存,不需要在整个生命周期都存在,需要人为手动释放。

image.png

如果堆上没有足够的空间分配,则会返回null。

image.png

分配内存的函数 malloc void* malloc(size_t size) calloc void* calloc(size_t num, size_t soze) realloc void* realloc(void* ptr, size_t size) 第一个参数:指向已分配内存的起始地址的指针 第二个参数:新的内存块大小

image.png

不能解引用一个void类型的指针-》转成特定类型的类型,再解引用,因为malloc函数只会返回一个void类型的指针,不关心存储内存的类型,需要类型转换。

malloc不会申请内存后,不会初始化,calloc会初始化为0.

realloc-可以修改内存块的大小

#include<stdio.h>
#include<stdlib.h>
int main() 
{
        int n;
        printf("press what you want to create number of array:");
        scanf("%d", &n);
        int *A=(int*)malloc(n*sizeof(int));
        for (int i = 0; i < n; i++) {
                A[i] = i + 1;
        }
        for (int i = 0; i < n; i++) {
                printf("%d ", A[i]);
        }

        return 0;
}

image.png

#include<stdio.h>
#include<stdlib.h>
int main() 
{
        int n;
        printf("press what you want to create number of array:");
        scanf("%d", &n);
        int *A=(int*)calloc(n,sizeof(int));
        for (int i = 0; i < n; i++) {
                A[i] = i + 1;
        }
        for (int i = 0; i < n; i++) {
                printf("%d ", A[i]);
        }

        return 0;
}

image.png

#include<stdio.h>
#include<stdlib.h>
int main() 
{
        int n;
        printf("press what you want to create number of array:");
        scanf("%d", &n);
        int *A=(int*)calloc(n,sizeof(int));
        /*for (int i = 0; i < n; i++) {
                A[i] = i + 1;
        }*/
        for (int i = 0; i < n; i++) {
                printf("%d ", A[i]);
        }

        return 0;
}

image.png

#include<stdio.h>
#include<stdlib.h>
int main() 
{
        int n;
        printf("press what you want to create number of array:");
        scanf("%d", &n);
        int *A=(int*)malloc(n*sizeof(int));
        /*for (int i = 0; i < n; i++) {
                A[i] = i + 1;
        }*/
        for (int i = 0; i < n; i++) {
                printf("%d ", A[i]);
        }

        return 0;
}

image.png

由此可见,malloc和calloc的区别在于,一个不会进行初始化,一个会初始化为0.

#include<stdio.h>
#include<stdlib.h>
int main() 
{
        int n;
        printf("press what you want to create number of array:");
        scanf("%d", &n);
        int *A=(int*)malloc(n*sizeof(int));
        for (int i = 0; i < n; i++) {
                A[i] = i + 1;
        }
        for (int i = 0; i < n; i++) {
                printf("%d ", A[i]);
        }
        int* B = (int*)realloc(A, 2 * n * sizeof(int));
        //free(A);
        printf("Prev block add=%d,new add=%d\n", A, B);
        for (int i = 0; i < 2*n; i++) {
                printf("%d ", B[i]);
        }

        return 0;
}

利用realloc扩展数组大小,如果原先分配的空间地址相邻部分有足够的大小,会进行扩展,如果没有足够的空间大小,会在一个新的空间,并且把旧值拷贝过去。

image.png

只保留一半的数据:

#include<stdio.h>
#include<stdlib.h>
int main() 
{
        int n;
        printf("press what you want to create number of array:");
        scanf("%d", &n);
        int *A=(int*)malloc(n*sizeof(int));
        for (int i = 0; i < n; i++) {
                A[i] = i + 1;
        }
        for (int i = 0; i < n; i++) {
                printf("%d ", A[i]);
        }
        int* B = (int*)realloc(A,  (n/2) * sizeof(int));
        //free(A);
        printf("Prev block add=%d,new add=%d\n", A, B);
        for (int i = 0; i < n; i++) {
                printf("%d ", B[i]);
        }

        return 0;
}

image.png

32ad6c0a3569abe84834b7b24a64a90.png

95af3ed396ddc5b24a4196d1eb80dab.png

afc1d29a51e7a5aa2fddb455f983bc7.png

4c7ccb115ebacc2ea23dc10202273f7.png

55ae3733b507fd1713d1ebc64d9dc8f.png

f29beaef73fb1e87181d1f82ee78926.png

C/C++中如何创建和使用函数指针

#include<stdio.h>
int Add(int a, int b){
        return a+b;
}

int main(){
        int c;
        int (*p)(int,int);//pointer to function that should take
        //(int,int) as argument/parameter and return int
        p=&Add;
        c=(*P)(2,3);//解引用函数,然后传参;de-referencing and executing the function.
        printf("%d\n",c);
        return 0;

}


image.png

#include<stdio.h>
//int Add(int a, int b){
//	return a+b;
//}
void printHello(){
        printf("hello\n");

}

int main(){
        void (*ptr)();
        ptr=printHello;
        prt();
        return 0;

}

image.png

函数指针的使用场景

函数指针作为函数传参

#include<stdio.h>

void A(){
        printf("hello\n");

}
void B(void (*ptr)()){  //function pointer as argument
        ptr(); //call-back function that "ptr" points to
}
int main(){
        void (*p)()=A;
        B(p);
        //以上两句等价于
        //B(A); //A此时就是回调函数,函数B可以通过函数指针来回调A

}



为什么B要间接地通过指针来调用A

普通冒泡排序

#include<stdio.h>
void bubbleSort(int *A,int n)
{
        int i,j,temp;
        for(i=0;i<n;i++){
                for(j=0;j<n-1;j++){
                        if(A[j]>A[i]){//compare A[j] with A[j+1] and Swap if needed
                                temp=A[j];
                                A[j]=A[j+1];
                                A[j+1]=temp;
                        }
                }
        }
}

int main()
{
        int A[]={3,2,1,5,6,4};//sort in increasing order=>{1,2,3,4,5,6}
        BubbleSort(A,6);
        for(i=0;i<6;i++){
                printf("%d ",A[i]);
        }

        return 0;
}

使用函数指针

 #include<stdio.h>
//callback function should compare two integers, should return 1 if first element has
//higher rank, 0 if elements are equal and -1 if second element has higher rank
int compare(int a,int b)
{
        if(a>b)
                return 1;
        else
                return -1;
}
void bubbleSort(int *A,int n,int (*compare)(int,int))
{
        int i,j,temp;
        for(i=0;i<n;i++){
                for(j=0;j<n-1;j++){
                        if(compare(A[j],A[i])>0){
                                temp=A[j];
                                A[j]=A[j+1];
                                A[j+1]=temp;
                        }
                }
        }
}

int main()
{
        int A[]={3,2,1,5,6,4};//sort in increasing order=>{1,2,3,4,5,6}
        BubbleSort(A,6,compare);
        for(i=0;i<6;i++){
                printf("%d ",A[i]);
        }

        return 0;
}

待比较的元素通过引用来传,地址通过指针传递

const关键字不能修改指针指向的值,使用void指针因为qsort函数是通用的设计,qsort能够对任何数组排序,不仅仅是整型数组,只是需要给出循环逻辑。

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
//callback function should compare two integers, should return 1 if first element has
//higher rank, 0 if elements are equal and -1 if second element has higher rank
//int compare(int a,int b)
/*{
        if(a>b)
                return 1;
        else
                return -1;
}*/
int absolute_compare(int a, int b)
{
        if(ads(a)>abs(b))
                return 1;
        return -1;
}
void bubbleSort(int *A,int n,int (*compare)(int,int))
{
        int i,j,temp;
        for(i=0;i<n;i++){
                for(j=0;j<n-1;j++){
                        if(compare(A[j],A[i])>0){
                                temp=A[j];
                                A[j]=A[j+1];
                                A[j+1]=temp;
                        }
                }
        }
}
int compare(const void* a, const void* b)//const关键字不能修改指针指向的值,使用void指针因为qsort函数是通用的设计,qsort能够对任何数组排序,不仅仅是整型数组
{
        int A=*((int*)a);
        int B=*((int*)b);
        return A-B;
}
int main()
{
        int A[]={3,2,1,5,6,4};//sort in increasing order=>{1,2,3,4,5,6}
        //BubbleSort(A,6,compare);
        BubbleSort(A,6,absolute_compare);
        qsort(A,6,sizeof(int),compare);
        for(i=0;i<6;i++){
                printf("%d ",A[i]);
        }
        return 0;
}


Conclusion:

内存地址 计算机内存~字节数组,每个字节有唯一的地址。 按字节可寻址,寻址的最小数据对象是一个字节。

小端存储,大端存储

image.png

指针

image.png

image.png

image.png

image.png

来源于B站fengmuzi2003的视频分享,仅供自学。