C 我的Int*数组是否全部初始化为NULL?

C 我的Int*数组是否全部初始化为NULL?,c,arrays,pointers,initialization,C,Arrays,Pointers,Initialization,我是一个努力理解C指针和数组的Java程序员。充分披露:我也是一名CS学生,是的,这个问题帮助我完成一项编程作业 我试图创建一个int*指针数组,然后确保每个指针都为NULL。稍后,当我需要在数组中查找数据时,这将发挥作用;给定的点中是否有有效的int或NULL将非常重要 因此为数组分配空间很容易,但是如何将所有这些指针设置为NULL呢?以下是我的一次不太成功的尝试: #include<stdio.h> #include<stdlib.h> #define TABLES

我是一个努力理解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;
}
所以我会坦率地说。。。我不知道上面告诉我什么。我猜我已经创建了一个1D数组,数组中的所有值都是有效的整数,都是0

但在我的程序中,这是有问题的。当我的代码需要将数据插入表[x]时,代码必须能够查看数组,并知道以前是否在同一位置插入了另一个有效的int。如果它看到表[x]=0,它是否认为索引x中插入了0,或者spot可用

我喜欢使用指向int的指针数组的想法,因为这样可以很好地解决这个问题。如果我的代码看到:

table[x] --> NULL // This spot is empty and available
table[x] --> 0 // This spot is occupied, can't insert here
表[x]->NULL//此点为空且可用 表[x]->0//此位置已被占用,无法在此插入 但我不认为我在编码我想要的

非常感谢您的任何想法/建议/评论/批评

谢谢! -皮特

不创建指针数组,而是创建单个int指针,指向大小为TABLESIZE*sizeofint的已分配内存块的开头

得到错误的原因是int*就是这个;指向int的指针

*运算符称为“取消引用”运算符。当它放在一个变量之前时,它的作用是说“转到这个指针指向的任何地方”。因此,该行

*(table+i) = NULL; 
意思是“转到表指向的任何地方,沿着i*sizeofint移动,然后将特定int设置为NULL。这显然没有意义-不能将int设置为NULL,因为这是指针值。这就是你的错误

顺便说一句,由于指针也可以像C中的数组一样处理,所以上面这一行也是

如果希望初始malloc是指针数组,则需要为int*分配空间,而不是为int*分配空间,这样就可以了

int** table = malloc(TABLESIZE * sizeof(int*));
然后有一个int**双指针,也就是指向引用TABLESIZE int*块的指针的指针

完成此操作后,该行下面的代码将正确地将指针设置为NULL。然后,为了实现问题中所述的表,在将int放入每个单元格之前,需要对每个单元格执行进一步的malloc。例如,将“3”放入单元格2中

if(*(table + 2) == NULL) {
   *(table + 2) = malloc(sizeof(int));
}
**(table + 2) = 3;
注意最后一行的双重区别:“转到表指向的任何地方,沿着2*sizeofint*移动,然后转到指针指向的任何地方。”同样,这也可以通过数组语法实现

if(table[2] == NULL) {
    table[2] = malloc(sizeof(int));
}
*table[2] = 3;
注意不要在同一个单元上调用malloc两次;如果你这样做,你将有一个内存泄漏

我是一个努力理解C指针和数组的Java程序员

是的,代码中的挣扎部分是显而易见的

C数组只是指定类型元素的有序集合,在内存中连续排列。这类似于Java数组,但Java不提供任何方法让您查看或探测内存中元素的排列,而且它的数组具有与元素相关的附加数据,特别是它们知道自己的长度

C指针是一个表示其他对象地址的值,其中对象表示任何类型的存储值,包括内置Java:基元类型、聚合类型、结构和数组、指针类型,甚至没有特定类型。这在某些方面与Java引用类似,这反映在一个事实上,即如果Java试图取消对空引用的引用,它会引发NullPointerException

非常重要的是要理解,尽管数组和指针之间有着密切的关系,但它们根本不是一回事。从上面的描述中可以清楚地看到这一点,但我经常会遇到相反的无厘头的说法

理解指针值可能无效也很重要-不指向任何对象。您可以很容易地拥有一个指针值,它可能存储在变量或数组中,其值是垃圾。这是需要管理的,不必害怕

此外,理解指针值不一定必须通过内存分配函数获得是很重要的。它们也可以通过操作符的地址获得&或者通过对涉及数组的表达式求值获得,或者在声明指针但未初始化指针时,垃圾指针值可以自然出现

我试图创建一个int*指针数组

我不确定你指的是一个数组,它的元素 e type int*pointer to int,一个数组,其元素的类型为int**pointer to pointer to int,或者可能是一个数组,其元素的类型为int。我从您的措辞中猜测是第一个,从字面上看您会产生第二个,而您的实际代码呈现类似于第三个的内容

这将是int*数组的声明:

没有指定初始值设定项,在赋值之前,不能依赖元素的任何特定值。与您介绍的代码类似的代码可以用于减少空检查,空检查由于初始值不确定而具有未定义的行为,并且无论如何都不会提供任何优势,但我倾向于编写稍微不同的代码:

for (int i = 0; i < TABLESIZE; i++) {
    table[i] = NULL;
}
这没有意义,因为被解释为任何指针类型的值的0是空指针常量。但是,首先将表的所有元素分配为NULL,如果在分配元素时要将元素设置为有效指针,则可以检查NULL以查看点是否可用,因为NULL从来不是指向对象的指针

顺便说一句,请注意,如果您将表声明为真正的数组(如上所述),则不需要释放它。但是,您可能需要释放其元素所指向的部分或全部对象,这取决于这些对象是否被动态分配,以及它们是否已经或将通过其他方式被释放。

在C和Java中,int都包含一个整数值。没有其他可区分的空状态。通常,int的每一个可能的位模式都代表一个不同的整数值,因此物理上不可能存储这个额外的状态

如果要实现可以是“null”或int范围内的任何可能值的内容,则必须为每个数组项使用额外的存储。例如,您可以维护一组并行的布尔标志,指示每个条目是否处于活动状态

另一种解决方案是保留一个特定的整数值,以表示该数组项应视为空。这种技术称为哨兵值

在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;
为了避免内存泄漏,您需要记住在数组超出范围之前循环并执行删除过程。检查malloc故障并中止程序或采取其他措施也很好


请注意,这种技术在C语言中被认为是不寻常的,而且与其他可用选项相比不节省空间。

@merl:这是胡说八道!通常,NULL'是定义NULL void*0`。为了便于文档编制/可读性,建议使用宏。此外,空指针不需要具有全部零的位表示形式。表[x]不是指针,而是int。因此,将其赋值为null是没有意义的。@merl:在启用了现代编译器和警告的情况下,通过比较void*和int,您将得到一个类型missmatch警告。更不用说指针类型和整数之间的转换是由实现定义的,在许多系统上都会产生差异/问题。目前还不清楚OP真正需要什么@Olaf你是对的,我想说的是OP不能用0和NULL来区分整数。@KeithThompson sizeof*表对于不习惯这个的人来说似乎太模糊了。不要播放malloc和friends的返回,这被认为是有害的。它是C++所需要的,但在C@BenWainwright:指针显然存在,但未锁定对象并分配该地址。我的参考是C标准。总是一本好书。我也知道C语言。你混淆了对象和指向它的指针。顺便说一句,由于指针也可以像C中的数组一样对待,在这种通用形式下,它至少是误导性的。对指针引用的对象的访问可以通过将指针声明为数组来完成。这就是全部。数组和指针之间有着巨大的根本区别。不要混淆OP,@AminNegm Awad。int*table=NULL;不生成指向NULL的指针-它创建指针类型的变量,其值(而不是其referent)为NULL。例如,一个空指针。@BenWainwright谢谢Ben,这太好了。解释得很清楚啊。你回答的第二部分对OP想要做什么给出了一个非常合理的解释。我有足够的Java背景,有点不好意思我没有想到这一点。@M.M这太棒了,谢谢你花时间来阐述这一点。我已经把这个抄到我的笔记里了int*数组[ARRAYSIZE]={NULL};仅将第一个元素初始化为NULL所有其他元素都初始化为二进制0,这不一定需要导致数组的元素携带NULL。虽然C标准统计
表示char*p=0;和char p=NULL比较应相等,NULL不一定需要用二进制0表示。由此派生:如果数组[2]==NULL可能会失败。@alk no,它实际上会生成NULL指针。见C11 6.7.9/21和/10@M.M:我站着纠正。我不知怎的错过了6.7.9/21明确提到的*/10。谢谢你给我指这个。我似乎把这个和实际情况混淆了:memsetarray,0,sizeof array;谢谢你,约翰,这是有道理的。我有点挫伤地了解到C语法比我预想的要复杂得多。这对清理东西有很大帮助
int *table[TABLESIZE];
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");
}
table[x] --> NULL // This spot is empty and available
table[x] --> 0 // This spot is occupied, can't insert here
// 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;