在C语言中声明数组但不指定初始大小

17

编写程序以操纵如下所示的温度细节。
- 输入要计算的天数。- 主函数
- 输入摄氏温度 - 输入函数
- 将摄氏温度转换为华氏温度。- 分离函数
- 找到华氏度的平均温度。

如何制作没有数组初始大小的程序?

#include<stdio.h>
#include<conio.h>
void input(int);
int temp[10];
int d;
void main()
{
    int x=0;
    float avg=0,t=0;
    printf("\nHow many days : ");
    scanf("%d",&d);
    input(d);
    conv();
    for(x=0;x<d;x++)
    {
        t=t+temp[x];
    }
    avg=t/d;
    printf("Avarage is %f",avg);
    getch();
}
void input(int d)
{
    int x=0;
    for(x=0;x<d;x++)
    {
        printf("Input temperature in Celsius for #%d day",x+1);
        scanf("%d",&temp[x]);
    }
}
void conv()
{
    int x=0;
    for(x=0;x<d;x++)
    {
        temp[x]=1.8*temp[x]+32;
    }
}

1
你的编译器支持c99吗? - haccks
2
  1. #include<conio.h> 非标准头文件
  2. void main() main() 应该返回 int。
- wildplasser
如何检查我的编译器是否支持C99标准?我是C语言的初学者 :) - ViSTA
顺便提一下:temp[x]=1.8*temp[x]+32 执行的是向零舍入,偏向不精确结果朝0靠拢。建议使用‘(int) round(1.8*temp[x]+32)’。这样最终平均值会更好。 (通常的习惯用法+0.5仅在所有转换为正数时才有效。) - chux - Reinstate Monica
为什么PO不接受或者看起来没有赞同答案呢? - Mehdi Haghgoo
8个回答

28

在C语言中,数组和指针之间有着密切的关系。事实上,按照设计,数组只是一种访问已分配内存的指针的语法约定。*(更多细节请参见下面的注释)

因此,在C语言中,语句

 anyarray[n] 

等同于

 *(anyarray+n)

使用指针算术。

你不需要担心细节来使其“工作”,因为它被设计成相当直观。

只需创建一个指针,分配内存,然后像访问数组一样访问它。

这里有一些例子--

int *temp = null; // this will be our array


// allocate space for 10 items
temp = malloc(sizeof(int)*10);


// reference the first element of temp
temp[0] = 70;


// free the memory when done
free(temp);

记住——如果你访问超出分配区域的内存,会带来未知的后果。

  • 要明确的是,索引操作符 ([ ]) 被翻译为指针算术运算。这不是现代意义上的数组类型。无论指针是否指向动态分配的内存,都与此操作符的工作方式无关。在更现代化的语言中,你可以将数组视为抽象类型进行操作(例如查看其大小),但在 C 中无法做到这一点。

2
@waqaslam - 静态数组是不具有动态性的(根据定义)。是的,你需要释放内存。如果你不这样做,就会出现“内存泄漏”这个常见的错误。 - Hogan
1
这个答案有点误导性,至少让一个读者感到困惑,认为在分配后,“temp”将成为数组的标识符。但事实并非如此。声明为“int ”的对象始终只是“int ”,而不是数组。在大多数情况下,通过指针分配的空间可以数组一样使用,但这并不意味着它实际上是一个数组,并且有一些表达式可以检测到它们之间的区别,特别是一些涉及“sizeof”的表达式。 - John Bollinger
1
@Hogan,我知道这是一个旧答案。我发表评论是因为提出当前问题的用户(在我的原始评论中链接)误解了这个答案,就像我描述的那样(他们特别提到了这个答案)。我真的认为你可能会忽略这个评论,我认为这已经足够澄清了。尽管如此,我确实认为“数组只是访问指向分配内存的指针的语法约定”确实可能会误导任何不知道你意思的人。 - John Bollinger
@Hogan - 我们可以得到 temp 的大小吗? - Scott
1
@scott -- temp是一个指针,其大小由操作系统定义--例如32位操作系统为32位,64位操作系统为64位。 - Hogan
显示剩余6条评论

5

没有初始大小的数组基本上只是一个指针。为了动态设置数组的大小,需要使用malloc()calloc()函数。它们将分配指定数量的字节内存。

在您上面的代码中,将temp声明为一个整型指针

int *temp;

然后使用malloc()calloc()为其分配空间。这些函数接受的参数是要分配的内存字节数的数量。在本例中,您需要足够的空间来容纳d个整数。因此...

temp = malloc(d * sizeof(int));

malloc会返回一个指向刚分配的内存块中第一个字节的指针。普通数组仅仅是指向被分割成若干段的内存块的第一个字节的指针,而现在temp就是这样一个指针。因此,您可以将temp指针视为数组!示例代码如下:

temp[1] = 10;
int foo = temp[1];
printf("%d", foo);

输出

10

2

如果你的编译器支持c99,那么可以直接使用VLA(可变长度数组)。使用方式如下:

void input(int);

 int d;
 void main()
 {
    int x=0;
    float avg=0,t=0;
    printf("\nHow many days : ");
    scanf("%d",&d);
    int temp[d];
    input(d);
    conv();
    for(x=0;x<d;x++)
    {
       t=t+temp[x];
    }
    avg=t/d;
    printf("Avarage is %f",avg);
    getch();
  }

现在,在输入日期后,temp[]被定义在main()内部。

@user2534857,你在用哪个编译器? - haccks
@haccks 你得问他 :D - Hogan
@user2534857,请告诉我您使用的编译器/集成开发环境(如code::block、Dev-c++、Visual Basics等)。 - haccks
@Hogan;我非常确定他对指针一无所知! - haccks
@user2534857:要么更换这个旧的IDE(在此处阅读第一个答案http://stackoverflow.com/questions/1961828/why-not-turbo-c),要么使用指针! - haccks
显示剩余3条评论

2

您需要将temp声明为一个int指针(而不是int数组)。然后,您可以在第一个scanf之后的main中使用malloc

temp = malloc(d * sizeof(int));

我听不懂你在说什么。我尝试这样做: printf("\n需要多少天:"); scanf("%d",&d); int temp[d]; 但是它没有起作用 :( - ViSTA
你需要将代码中的int temp[10]改为int *temp。然后,不要使用int temp[d],而是使用我在答案中提供的代码。 - Drew McGowen
我不知道malloc。你能告诉我如何在我的程序中使用它吗? - ViSTA
malloc 基本上允许您为任何需要的目的保留一些内存,但当您事先不知道大小时。http://en.wikipedia.org/wiki/C_dynamic_memory_allocation 可能是一个好的起点。 - Drew McGowen

1

1-在文件顶部添加#include<stdlib.h>。然后按以下方式修改conv()代码:
2-将temp声明修改为以下内容(全局变量):

int *temp;

3- 将 input(int d) 函数修改为以下内容(在Visual Studio 2010上测试通过):

  void input(int d)
    {
        int x=0;
        temp=(int*)malloc(sizeof(int)*d);
        for(x=0;x<d;x++)
        {
            printf("Input temperature in Celsius for #%d day",x+1);
            scanf("%d",&temp[x]);
        }
    }

首先,在 main(...) 结束时不要忘记释放 temp。其次,我建议在 main(...) 函数中分配和释放 temp,而不是在 input(...) 中分配,在 main(...) 中释放。 - Jeff G

0

我没有改变任何其他东西,所以你可以清楚地看到它。

#include<stdio.h>
#include<conio.h>
#include <stdlib.h>   //here
void input(int);
int *temp=0;  //here
int d;
void main()
{
    int x=0;
    float avg=0,t=0;
    printf("\nHow many days : ");
    scanf("%d",&d);
    temp=malloc(d * sizeof(int));  //here
    input(d);
    conv();
    for(x=0;x<d;x++)
    {
        t=t+temp[x];
    }
    avg=t/d;
    printf("Avarage is %f",avg);
    getch();
}
void input(int d)
{
    int x=0;
    for(x=0;x<d;x++)
    {
        printf("Input temperature in Celsius for #%d day",x+1);
        scanf("%d",&temp[x]);
    }
}
void conv()
{
    int x=0;
    for(x=0;x<d;x++)
    {
        temp[x]=1.8*temp[x]+32;
    }
}

它出现了一些错误,"malloc应该有原型",应该如何修复它?请。 - ViSTA

0
也许回答有些晚了... 如果你在小型嵌入式系统中工作,可能没有malloc和free函数。 所以你需要为 366 * sizeof(你的类型) 牺牲一些内存,将其静态定义并作为圆形缓冲区使用。然后你可以根据需要计算平均值的天数来切割它。 当然这会带来自然限制。你可以自己定义它。

0
在读取大小后,动态地在堆上分配“数组”。

1
为什么不一开始就分配所需大小的数组呢? - Drew McGowen
@DrewMcGowen 你说得对,我没有读代码,也没有看到尺寸被读取。更新答案以反映这一点。 - Some programmer dude

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接