Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 指针和数组之间的详细差异_C_Arrays_Pointers - Fatal编程技术网

C 指针和数组之间的详细差异

C 指针和数组之间的详细差异,c,arrays,pointers,C,Arrays,Pointers,下面是C语言的代码: void test1(void); int main(){ test1(); return 0; } void test1(void){ char c, *p = &c, *sp1[3] = {"this 1","this 2", "this 3"}, //pointers array (*sp2)[5] = {"this 1","this 2", "this 3"},

下面是C语言的代码:

void test1(void);

int main(){
    test1();
    return 0;
}

void test1(void){
    char c,
        *p = &c,
        *sp1[3] = {"this 1","this 2", "this 3"},    //pointers array
        (*sp2)[5] = {"this 1","this 2", "this 3"},  
        //2 dimensions array declaration in method 1 
        sp3[][5] = {"this 1","this 2", "this 3"};   
        //2 dimensions array declaration in method 2

    p++;    //ok 
    sp1++;  //error 
    sp2++;  //ok
    sp3++;  //error     
}
我已经读到指针是一个变量,所以增量是可以的,但数组名不是变量,所以赋值是不可接受的

在上面的代码中,
p
是指针,因此增量是正确的
sp1
sp3
都是数组名,增量会导致错误,但是为什么
sp2
可以

在同一本书中,有如下功能:

//print lines 
void writelines(char *lineptr[],int nlines){
    while(--nlines >= 0){
        printf("%s\n",*lineptr++);
    }
}

在该函数中,
lineptr
是数组的名称,但会对其应用增量。为什么?这是因为参数在C中是通过值转换的,所以
lineptr
实际上是一个指针吗?

不清楚您编写代码的目的是什么,而不是简单地与指针和数组搏斗,试图了解它们的用法(这是对C学习时间的极好利用)

考虑到这一点,让我们看看您的声明,并尝试帮助理解它们。首先让我们看一下
c
p
(我为您初始化了“c”,以避免使用未初始化的值):

c
仅声明为
char
,自动存储在函数堆栈上创建的
1-char
p
声明为字符指针(或指向字符的指针),其值初始化为
c

(指针是一个简单的变量,它将其他对象的地址作为其值。普通变量,例如
c
持有一个立即值,在这种情况下,
'a'
p
简单地将
c
的地址作为其值,例如
p
指向
c

接下来,您将声明一个指针数组,这些指针被初始化为保存初始值设定项中提供的字符串文本的地址,例如

注意:如果提供每个指针的初始化,则无需指定
3

在这里,您可以有效地向char*声明一个
3指针数组。其中
sp1[0]
指向
“此1”
sp1[1]
指向
“此2”
,等等

接下来,您将声明一个指向数组5个字符的指针(或指向数组5个字符的指针)注意:正如在我的评论中一样,这不足2个字符,因此在下面将其声明为指向数组7个字符的指针。现在你需要注意了。因为您声明了一个指向数组的指针,所以它本身没有为7个字符分配任何存储空间(它只是指向已经包含7个字符的对象的指针)。你有几个选择

由于
sp3
属于
char[][7]
类型,因此可以在
sp3
之后声明
sp2
,并为其分配兼容数组的地址,例如

    *sp1[] = {"this 1","this 2", "this 3"},
    sp3[][7] = {"this 1","this 2", "this 3"},
    (*sp2)[7] = sp3,  
要使
sp2
指向
sp3
的开头,或者可以使用C99复合文字为
sp2
声明后的文字创建存储,例如

最后,您可以动态地为
sp2
分配存储空间(我们将在下一次讨论)。现在,由于您正在与这里的指针搏斗,您看到您不能简单地递增
sp3
它是一个数组,但是。。。作为练习的一部分,您可以声明指向其开头的指针并增加该指针,例如

        sp3[][7] = {"this 1","this 2", "this 3"},
        *p3 = *sp3; /* pointer to first element in sp3 */
现在,将拼图的所有部分放在一起,并练习每个指针的增量,您可以执行以下类似操作。(注意:在递增
p++
后,我不删除
p
的值,而是删除
p-1
,以便它仍然指向有效存储)

注意:如果您选择在
sp3
之后声明
sp2
,并让
sp2
指向
sp3
的开头,则输出相同:

    char c = 'a',
        *p = &c,
        *sp1[] = {"this 1","this 2", "this 3"},
        sp3[][7] = {"this 1","this 2", "this 3"},
        (*sp2)[7] = sp3,  
        *p3 = *sp3; /* pointer to first element in sp3 */

虽然我不确定这是否正是你的想法,但我认为这与你的锻炼目标很接近。如果没有,请告诉我。如果您还有任何问题,请仔细查看并告诉我。

这可能会帮助您更清楚地理解指针。
*sp1[3]
是指向char的指针数组,
(*sp2)[5]
是指向char类型的数组5的指针,
sp3[][5]
是一个二维数组(数组char[5])。注意:,在最后两种情况中,当您无法为提供足够的存储时,您都会调用未定义的行为,例如,
“this 2”
(对于nul终止字符,这是6-chars+1-char)。您的
5
至少需要是
7
char c
声明
c
为未初始化字符
*p=&c
创建
p
作为指向char的指针(只有一个char的存储空间),
p++
导致
p
指向分配给
c
的存储之外,任何试图取消引用
p
的行为都会调用未定义的行为。“在此函数中,lineptr是数组的名称”--是和否。
lineptr
可能是指向一行
nline
开头的指针数组,但是,当作为参数传递给函数时,数组将转换为指针,因此函数中实际包含的是指向char或
char**
的指针,可以轻松地递增。(如果是2D数组,参数应该是
char(*lineptr)[WIDTH],int-nlines…
)非常感谢。这是我第一次问“stackoverflow”,我对你的热情和专业的回答感到惊讶,我学到了很多东西,包括许多我以前没有意识到的细节。衷心感谢。很高兴能提供帮助。C语言可能是你能学的最优雅、最灵活的语言之一。它提供了对内存的位级控制,但它要求您度量和说明所使用的内存。无论您选择哪种语言,C都将使您成为一名更好的程序员,因为您将
        *sp1[] = {"this 1","this 2", "this 3"},
        /* using a compound literal to create storage */
        (*sp2)[7] = (char [][7]){"this 1","this 2", "this 3"},  
        sp3[][7] = {"this 1","this 2", "this 3"},
        sp3[][7] = {"this 1","this 2", "this 3"},
        *p3 = *sp3; /* pointer to first element in sp3 */
#include <stdio.h>

void test1 (void);

int main (void) {
    test1();
    return 0;
}

void test1 (void) {
    char c = 'a',
        *p = &c,
        *sp1[] = {"this 1","this 2", "this 3"},
        /* using a compound literal to create storage */
        (*sp2)[7] = (char [][7]){"this 1","this 2", "this 3"},  
        sp3[][7] = {"this 1","this 2", "this 3"},
        *p3 = *sp3; /* pointer to first element in sp3 */

    p++;        /* advance p to one-char-past-c     */
    (*sp1)++;   /* advance pointer to sp1[0] by one */
    sp2++;      /* advance pointer to next char[7]  */
    p3++;       /* advance pointer to sp3[0] by one */

    printf ("(p - 1): %c\n*sp1: %s\n*sp2: %s\np3  : %s\n",
            *(p - 1), *sp1, *sp2, p3);
}
$ ./bin/arrayptrinc
(p - 1): a
*sp1: his 1
*sp2: this 2
p3  : his 1
    char c = 'a',
        *p = &c,
        *sp1[] = {"this 1","this 2", "this 3"},
        sp3[][7] = {"this 1","this 2", "this 3"},
        (*sp2)[7] = sp3,  
        *p3 = *sp3; /* pointer to first element in sp3 */