Loading

一道编程题引发的C中关于数组、指针的思考

7-163 谷歌的招聘

由一道编程题引发的C中关于数组、指针的思考

先来看三种数组定义方式

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

int main(){
    //方式1
    int array_1[4] = {1};

    //方式2,变长数组
    int n2;
    scanf("%d",&n2);
    int array_2[n2]; //使用变长数组
    printf("%d\n",sizeof (array_2) /  4 );

    //方式3,使用malloc函数动态分配内存
    int m=4;
    int *array_3 = (int*)malloc(m * sizeof(int));
    printf("%d",sizeof (array_3) / 4);
}

这三种都是在C语言中定义数组的方法,但它们在数组大小决定方式、内存分配位置和生命周期等方面有所不同。

  1. 固定大小的数组
    这是最基本的数组定义方式。在这种方式中,数组的大小在编译时就已经确定了。
    这种数组在上分配内存,生命周期与其所在的函数相同。当函数返回时,这种数组会自动被销毁。
  2. 变长数组
    在这种方式中,数组的大小是在运行时决定的。这种类型的数组在C99标准中被引入。
    这种数组在栈(Stack)上分配内存,而栈内存的大小通常比堆内存(Heap)小得多。当函数返回时,这种数组会自动被销毁。

注意,虽然变长数组在C99中被引入,但在C11标准中,它们被转移到了可选功能中(optional feature)。并且,一些编译器(例如GCC)默认允许变长数组,但一些其他编译器(例如Clang)则不允许。因此,使用变长数组的可移植性可能会有问题。

  1. 使用malloc函数动态分配内存
    在这种方式中,数组的大小也是在运行时决定的。但这种数组在堆(Heap)上分配内存,堆内存通常比栈内存大得多。
    这种数组的生命周期直到你显式地调用free函数来释放它为止。这意味着,即使函数返回,这种数组也不会被自动销毁,除非你显式地销毁它。
    使用malloc函数动态分配内存的一个主要优点是,可以在运行时分配大量的内存。但是,需要记住在不再需要数组时释放它,否则可能会导致内存泄漏。

内存泄漏:内存泄漏是一种常见的编程问题,特别是在手动内存管理的编程语言(如C或C++)中。它发生在当程序持续地分配内存但未能相应地释放它时。未被释放的内存块随着时间的推移会累积起来,导致可用内存逐渐减少,这可能会降低程序的性能,甚至导致程序崩溃。
更具体地说,当你在C语言中使用malloc、calloc或realloc函数分配内存时,操作系统会为你的程序分配一块内存。这块内存会一直保留,直到你显式地调用free函数来释放它。如果你忘记了释放这块内存,或者由于错误的程序逻辑而未能释放它,那么这块内存就会“泄漏”,它将无法被程序的其他部分使用,即使程序可能不再需要它。

上述代码存在错误

在第三种方法中。试图通过sizeof (array_3) / 4来获取动态分配数组的长度。
但是,这并不会给出正确的结果,因为array_3是一个指针,sizeof (array_3)将返回指针的大小,而不是它指向的内存块的大小。在大多数系统上,一个指针的大小是8字节(对于64位系统),所以sizeof (array_3) / 4的结果将是2,而不是期望的数组长度。要获取动态分配的数组长度,需要自己保存这个信息。

另外的问题:
第二种方式的array_2不也是一个指针吗,为什么方式二可以正确获取数组大小?

在C语言中,数组名确实可以被看作是一个指向数组首元素的指针。但是,静态数组(包括固定大小的数组和变长数组)和动态数组(由malloc等函数分配的数组)在这方面有一些关键的不同。

对于静态数组(包括方式1和方式2的数组),虽然数组名可以被当作一个指针来使用,但它实际上并不是一个真正的指针。数组名更像是一个指向数组首元素的常量指针,并且编译器知道这个数组的大小。因此,当你在静态数组上使用sizeof运算符时,你会得到整个数组的大小,而不是指针的大小。

但是,对于动态数组(方式3的数组),malloc返回的是一个真正的指针。这个指针指向分配的内存块的首地址,但编译器并不知道这个内存块的大小。因此,在动态数组上使用sizeof运算符时,只会得到指针的大小,而不是整个数组的大小。
这就是为什么可以通过sizeof(array_2) / sizeof(int)来获取方式2的数组的长度,但不能通过sizeof(array_3) / sizeof(int)来获取方式3的数组的长度的原因。在动态分配内存时,需要自己保存数组的长度信息。

image

image

#include <stdio.h>
#include <stdbool.h>
#include <math.h>

bool isPrime(int n){
    if(n == 1) return false;
    for(int i=2;i < n; i++){
        if(n % i == 0){
            return false;
        }
    }
    return true;
}

int main(){
    int n,k,tmp,m=0;
    int num[1000];
    scanf("%d %d",&n, &k);
    //把数据存到数组
    for(int i=0; i<n; i++){
        scanf("%1d",&tmp);
        num[i] = tmp;
    }
    //开始从第i位寻找连续k位素数
    for(int i=0; i<=n-k; i++){
        int account=k-1;
        for(int j=i; j<i+k; j++){   //循环k次,计算数字
            m += num[j] * (int)pow(10,account);
            account--;
        }
        if(isPrime(m)){
            printf("%0*d", k, m);   //*作为宽度指定符
            return 0;
        }
        m=0;    //准备重新寻找
    }
    printf("404");
    return 0;
}
  • printf中,*作为宽度指定符
posted @ 2024-04-27 17:00  _rainyday  阅读(59)  评论(0)    收藏  举报