我是一名努力理解C指针和数组的Java程序员。 (完全披露:我也是一名CS学生,是的,这个问题可以帮助我完成编程任务。)
我正在尝试创建一个int *指针数组,然后确保每个指针都为NULL。稍后,当我需要在数组中查找数据时,这将发挥作用;在给定的位置中是否存在有效的int或NULL将是重要的。
因此,为数组分配空间很简单,但是如何将所有指针设置为NULL?这是我不那么出色的尝试:
#include<stdio.h>
#include<stdlib.h>
#define TABLESIZE 10
int main(int argc, char *argv[]){
int* table = (int*) malloc(TABLESIZE * sizeof(int));
// Initialize all *int pointers to NULL
int i;
for(i=0; i<TABLESIZE; i++){
if((table+i)!=NULL){ // They may be NULL already? I don't know...
*(table+i) = NULL; // This generates a warning:
// "warning: assignment makes integer from pointer without a cast [-Wint-conversion]"
}
}
// Sanity check : are all int* are NULL ?
for(i=0; i<TABLESIZE; i++){
printf("%d: %p %d ", i, (table+i), *(table+i));
if((table+i) == NULL)
printf("(NULL)");
printf("\n");
}
free(table);
return 1;
}
输出是:
$ ./a.exe
0: 0x6000103c0 0
1: 0x6000103c4 0
2: 0x6000103c8 0
3: 0x6000103cc 0
4: 0x6000103d0 0
5: 0x6000103d4 0
6: 0x6000103d8 0
7: 0x6000103dc 0
8: 0x6000103e0 0
9: 0x6000103e4 0
$
所以我会坦白说实话......我不知道上面告诉我的是什么。我猜我已经创建了一个一维数组,其中数组中的所有值都是有效的整数,全部为0。
但这对我后来的计划来说有问题。当我的代码将数据插入表[x]时,代码必须能够查看数组并知道先前是否在同一位置插入了另一个有效的int。如果它看到table [x] = 0,它是否会在索引x中插入0,或者该点是否可用?
我喜欢使用指向int的指针数组的想法,因为这样可以巧妙地解决这个问题。如果我的代码看到了:
但我不认为我正在编码我想要的东西。
非常感谢任何想法/建议/评论/批评。
谢谢! -Pete
答案 0 :(得分:5)
int* table = malloc(TABLESIZE * sizeof(int));
不创建指针数组,而是创建一个int
指针,指向大小为(TABLESIZE * sizeof(int))
的已分配内存块的开头
您收到错误的原因是int*
就是这样;指向int
的指针。
*
运算符称为&#39; dereference&#39;运营商。将放在变量之前的工作就是说“转到指针指向的地方”。因此,行
*(table+i) = NULL;
表示&#39;转到表所指向的位置,沿着i * sizeof(int)
移动,然后将该特定int
设置为NULL。这显然没有意义 - 你不能将int
设置为NULL,因为它是一个指针值。因此你的错误。
顺便说一下,由于指针也可以像C中的数组一样处理,上面的行也完全等同于
table[i] = NULL;
如果您希望初始malloc是一个指针数组,则需要为int
而不是int*
分配空间,所以你可以这样做
int** table = malloc(TABLESIZE * sizeof(int*));
然后你有一个int**
(双指针 - 也就是一个指向指针的指针)引用一个TABLESIZE int*
完成此操作后,该行下方的代码将正确设置指向NULL
的指针。为了实现问题中描述的表格,在将int
放入其中之前,您需要为每个单元格执行另外的malloc。所以例如把'3&#39;进入细胞2
if(*(table + 2) == NULL) {
*(table + 2) = malloc(sizeof(int));
}
**(table + 2) = 3;
请注意最后一行的双重参与:&#39;转到table
指向的任何地方,沿着2 * sizeof(int*)
移动,然后转到 指针指向的任何地方。&#39;同样,这也可以通过数组语法
if(table[2] == NULL) {
table[2] = malloc(sizeof(int));
}
*table[2] = 3;
小心不要在同一个小区上拨打malloc()
两次;如果你这样做会导致内存泄漏。
答案 1 :(得分:4)
我是一名努力理解C指针和数组的Java程序员。
是的,“挣扎”部分在您的代码中很明显。
C数组只是指定类型元素的有序集合,在内存中连续排列。这类似于Java数组,但是Java没有提供查看或探测内存中元素排列的方法,并且它的数组还有与之关联的附加数据(特别是,它们知道自己的长度)。
AC指针是一个表示某个其他对象的地址的值,其中“object”表示任何类型的存储值,包括内置(Java:“primitive”)类型,聚合类型(结构和数组),指针类型,甚至没有特定的类型。这在某些方面与Java“引用”类似,这反映在Java尝试取消引用空引用时引发“Null 指针异常”这一事实。
理解尽管数组和指针之间存在密切关系非常重要,但它们并不是完全相同的。从上面的描述中可以清楚地看出这一点,但我经常遇到相反的无能为力的说法。
理解指针值可能无效 - 也不指向任何对象也很重要。您可以轻松地获得指针值,可能存储在变量或数组中,其值为垃圾。这是管理的东西,不要害怕。
此外,重要的是要理解指针值不一定必须通过内存分配函数获得。它们也可以通过address-of运算符(&
)或通过评估涉及数组的表达式获得,或者当声明指针但未初始化时,垃圾指针值会自然弹出。
我正在尝试创建一个int *指针数组
我不确定你的意思是一个数组,其元素的类型为int *
(指向int的指针),一个数组的元素类型为int **
的数组(指向int的指针),或者可能是元素类型为int
的数组。我对你的措辞的猜测将是第一个,读取你的字面意思是第二个,你的实际代码就像第三个。
这将是int *
:
int *table[TABLESIZE];
未指定初始值设定项,在分配值之前,不能依赖元素的任何特定值。类似于你提出的代码可以用于那个(更少的NULL检查,由于初始值是不确定的,它具有未定义的行为,无论如何都没有提供任何优势),但我倾向于略微区别地写它:
for (int i = 0; i < TABLESIZE; i++) {
table[i] = NULL;
}
此时,表的元素都使用一个指针值初始化,您可以 某些 不指向任何对象。您可以检查这些指针值,但不能取消引用它们:
// Sanity check : are all int* are NULL ?
for(int i = 0; i < TABLESIZE; i++) {
printf("%d: %p ", i, (void *) table[i]);
if(table[i] == NULL)
printf("(NULL)");
printf("\n");
}
我喜欢使用指向int的指针数组的想法 会整齐地解决这个问题。如果我的代码看到了:
table[x] --> NULL // This spot is empty and available table[x] --> 0 // This spot is occupied, can't insert here
这没有意义,因为0
被解释为任何指针类型的值是空指针常量。但是,通过将表的所有元素分配为NULL开始,如果您打算在分配元素时将元素设置为有效指针,那么可以检查NULL
以查看是否存在spot是可用的,因为NULL
永远不是指向对象的指针。
请注意,如果您将table
声明为真正的数组,如上所述,那么您无需释放它。但是,您可能需要释放其元素指向的部分或全部对象,具体取决于这些对象是否是动态分配的,以及它们是否已经或将通过其他方式释放。
答案 2 :(得分:2)
在C和Java中,int
包含整数值。没有额外的,可区分的无效状态。通常,int
的每个可能的位模式都代表一个不同的整数值,因此实际上不可能存储这个额外的状态。
如果要实现“{null}”或int
范围内任何可能值的某些内容,则必须为每个数组条目使用额外的存储空间。 (例如,您可以维护一组并行的布尔标志,指示每个条目是否处于“活动”状态。
另一种解决方案是保留一个特定的整数值来表示该数组条目应被视为“空”。此技术称为 sentinel value 。
在Java中,您可以拥有一个Integer
数组,这是一个引用数组,可以是“null”或引用存储在别处的int
(该语言管理幕后分配) )。在C中模拟内存布局
代码是:
// Allocate array and initialize all entries to NULL
int * array[ARRAYSIZE] = { NULL };
// Insert at position (repeatable)
if ( array[2] == NULL )
array[2] = malloc( sizeof(int) );
*array[2] = 10;
// Use item
printf("%d\n", *array[2]);
// Remove from position
free( array[2] );
array[2] = NULL;
为了避免内存泄漏,您需要记住在array
超出范围之前循环并执行删除过程。检查malloc
失败并中止程序或采取其他行动也是一件好事。
请注意,此技术在C中会被视为异常,与其他可用选项相比,效率不高。