C 指针和数组之间的详细差异
下面是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"},
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 */