我想创建一个整数指针 p,为 10 个元素的数组分配内存,然后用值 5 填充每个元素。这是我的代码:
//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );
//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %dn", sizeof(array));
while (i < sizeof(array)){
*p = 5;
printf("Current value of array: %pn", *p);
*p += sizeof(int);
i += sizeof(int);
}
我在此代码周围添加了一些 print 语句,但我不确定它是否真的用值 5 填充每个元素。
那么,我的代码是否正常工作?谢谢你的时间。
首先:
*p += sizeof(int);
这将获取p
指向的内容,并向其中添加整数的大小。这没有多大意义。您可能想要的只是:
p++;
这使p
指向下一个对象。
但问题是p
包含指向第一个对象的指针的唯一副本。因此,如果您更改其值,您将无法再访问内存,因为您将没有指向它的指针。(因此,您应该保存从某处返回的原始值的副本malloc
。如果没有别的,你最终需要它传递给free
。
while (i < sizeof(array)){
这说不通。您不希望循环的次数等于数组占用的字节数。
最后,您不需要数组进行任何操作。只需将其删除并使用:
int *p = malloc(10 * sizeof(int));
对于 C,不要强制转换 malloc
的返回值。它不是必需的,并且可以掩盖其他问题,例如无法包含正确的标头。对于while
循环,只需跟踪单独变量中的元素数量。
这是一种更惯用的做事方式:
/* Just allocate the array into your pointer */
int arraySize = 10;
int *p = malloc(sizeof(int) * arraySize);
printf("Size of array: %dn", arraySize);
/* Use a for loop to iterate over the array */
int i;
for (i = 0; i < arraySize; ++i)
{
p[i] = 5;
printf("Value of index %d in the array: %dn", i, p[i]);
}
请注意,您需要单独跟踪数组大小,无论是在变量(如我所做的(还是宏(#define
语句(中,还是仅使用整数文字。但是,使用整数文本容易出错,因为如果以后需要更改数组大小,则需要更改更多代码行。
数组的sizeof
返回数组占用的字节数(以字节为单位(。
int *p = (int *)malloc( sizeof(array) );
如果您调用 malloc,则必须#include <stdlib.h>
.此外,强制转换是不必要的,并且可能会引入危险的错误,尤其是与缺少的malloc
定义配对时。
如果将指针
递增 1,则会到达指针类型的下一个元素。因此,您应该将底部写为:
for (int i = 0;i < sizeof(array) / sizeof(array[0]);i++){
*p = 5;
p++;
}
*p += sizeof(int);
应该是
p += 1;
由于指针的类型为 int *
此外,数组大小应按如下方式计算:
sizeof (array) / sizeof (array[0]);
事实上,您的代码不需要该数组。
不,不是。但是,以下代码将。您应该阅读指针算术。p + 1 是下一个整数(这是指针具有类型的原因之一(。还要记住,如果你改变p的值,它将不再指向你记忆的开始。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define LEN 10
int main(void)
{
/* Allocate memory for a 10-element integer array. */
int array[LEN];
int i;
int *p;
int *tmp;
p = malloc(sizeof(array));
assert(p != NULL);
/* Fill each element with the value of 5. */
printf("Size of array: %d bytesn", (int)sizeof(array));
for(i = 0, tmp = p; i < LEN; tmp++, i++) *tmp = 5;
for(i = 0, tmp = p; i < LEN; i++) printf("%dn", tmp[i]);
free(p);
return EXIT_SUCCESS;
}
//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );
此时,您已经分配了两倍的内存 - 堆栈上分配的数组中的十个整数的空间,堆上分配的十个整数的空间。在一个需要为十个整数分配空间的"真实"程序中,堆栈分配不是正确的做法,分配将像这样完成:
int *p = malloc(10 * sizeof(int));
请注意,无需从 malloc(3)
强制转换返回值。我希望您忘记包含 <stdlib>
标头,这将正确制作函数原型,并为您提供正确的输出。(如果没有原型在标头中,C 编译器假定该函数将返回一个 int
,并且强制转换使其将其视为指针。二十年来不需要演员阵容。
此外,要警惕学习习惯sizeof(array)
。这将适用于数组与 sizeof()
关键字分配在同一块中的代码,但当像这样使用时它会失败:
int foo(char bar[]) {
int length = sizeof(bar); /* BUG */
}
它看起来是正确的,但实际上sizeof()
会看到一个char *
而不是完整的数组。C 的新可变长度数组支持非常强烈,但不要与许多其他语言中可用的知道其大小的数组混淆。
//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %dn", sizeof(array));
while (i < sizeof(array)){
*p = 5;
*p += sizeof(int);
啊哈!其他人在 C 指针上遇到了和我一样的麻烦!我想你以前主要编写汇编代码,不得不自己增加指针?:)编译器知道p
指向的对象类型(int *p
(,因此如果您只是编写p++
,它将正确地将指针移动正确的字节数。如果您将代码交换为使用 long
或 long long
或 float
或 double
或 long double
或 struct very_long_integers
,编译器将始终对p++
做正确的事情。
i += sizeof(int);
}
虽然这没有错,但稍微重写一下最后一个循环肯定会更习惯:
for (i=0; i<array_length; i++)
p[i] = 5;
当然,您必须将数组长度存储到变量中或#define
它,但这样做比依赖有时对数组长度的挑剔计算更容易。
更新
在阅读了其他(优秀的(答案后,我意识到我忘了提到p
是你对数组的唯一引用,所以最好不要更新p
而不在某处存储其值的副本。我的小"惯用语"重写回避了这个问题,但没有指出为什么使用订阅比增加指针更惯用——这就是首选订阅的原因之一。我也更喜欢订阅,因为在数组基数不变的情况下,对代码进行推理通常要容易得多。(视情况而定。
//allocate an array of 10 elements on the stack
int array[10];
//allocate an array of 10 elements on the heap. p points at them
int *p = (int *)malloc( sizeof(array) );
// i equals 0
int i = 0;
//while i is less than 40
while (i < sizeof(array)){
//the first element of the dynamic array is five
*p = 5;
// the first element of the dynamic array is nine!
*p += sizeof(int);
// incrememnt i by 4
i += sizeof(int);
}
这会将数组的第一个元素设置为 9 次、10 次。 看起来你想要更像的东西:
//when you get something from malloc,
// make sure it's type is "____ * const" so
// you don't accidentally lose it
int * const p = (int *)malloc( 10*sizeof(int) );
for (int i=0; i<10; ++i)
p[i] = 5;
___ * const
可防止您更改p
,以便它始终指向已分配的数据。 这意味着free(p);
将始终有效。 如果更改 p,则无法释放内存,并且会出现内存泄漏。