我在C中做了一些指针和数组练习,我注意到我的四个方法都返回了相同的答案。我的问题是使用以下任何一种方法都有缺点吗?我惊讶于这四个人如何给我相同的输出。我只是注意到你可以使用一个指针,就像它是一个数组一样,你也可以使用一个数组就好像它是一个指针一样?
char *name = "Madonah";
int i= 0;
for (i=0;i<7; i++){
printf("%c", *(name+i));
}
char name1 [7] = "Madonah";
printf("\n");
int j= 0;
for (j=0;j<7; j++){
printf("%c", name1[j]);
}
char *name2 = "Madonah";
printf("\n");
int k= 0;
for (k=0;k<7; k++){
printf("%c", name2[k]);
}
char name3 [7] = "Madonah";
printf("\n");
int m= 0;
for (m=0;m<7; m++){
printf("%c", *(name+m));
}
结果:
Madonah
Madonah
Madonah
Madonah
答案 0 :(得分:23)
在某些情况下,指针和数组确实是equivalent,&#34;等效&#34;并不意味着它们是相同的,甚至不可互换的。 数组不是指针。
指针算术和数组索引是等效的,指针和数组是不同的 。
哪一个更好,优点/缺点?
这取决于您想要如何使用它们。如果你不想修改字符串,那么你可以使用
char *name = "Madonah";
它基本上等同于
char const *name = "Madonah";
*(name + i)
和name[i]
都是相同的。我更喜欢name[i]
而不是*(name + i)
因为它很整洁并且最常用于C和C ++程序员。
如果您想修改字符串,则可以使用
char name1[] = "Madonah";
答案 1 :(得分:11)
在C中,a[b]
,b[a]
,*(a+b)
是等效的,这三者之间没有区别。所以你只有2个案例:
char *name = "Madonah"; /* case 1 */
和
char name3 [7] = "Madonah"; /* case 2 */
前者是一个指向字符串文字的指针。后者是一个包含7个字符的数组。
哪一个首选取决于您对name3
的使用情况。
如果不打算修改字符串,那么你可以使用(1),我也会使它const char*
使其清楚并确保字符串文字不是意外修改。修改字符串文字是C
如果你做需要修改它,那么应该使用(2),因为它是你可以修改的字符数组。需要注意的一点是,在情况(2)中,您已明确指定数组的大小为7
。这意味着字符数组name3
在末尾没有空终止符(\0
)。所以它不能用作字符串。我宁愿不指定数组的大小,让编译器计算它:
char name3 [] = "Madonah"; /* case 2 */
/* an array of 8 characters */
答案 2 :(得分:6)
除了别人说的话,我还会添加一张图片以便更好地说明。如果你有
char a[] = "hello";
char *p = "world";
在第一种情况下会发生什么,通常会在堆栈上为a
(6个字符)分配足够的内存,字符串&#34; hello&#34;被复制到以a
开头的内存。因此,您可以修改此内存区域。
在第二种情况下&#34;世界&#34;在其他地方(通常在只读区域)分配,并返回指向该内存的指针,该指针只存储在p
中。在这种情况下,您无法通过p
修改字符串文字。
以下是它的外观:
但是对于你的问题坚持更容易的符号,我更喜欢[]
。
有关数组和指针之间关系的更多信息是here。
答案 3 :(得分:2)
在所有情况下,C pointer + index
与pointer[index]
相同。此外,在C中,表达式中使用的数组名称被视为指向数组的第一个元素的指针。当你认为加法是可交换的时,事情会变得更加神秘,这使得index + pointer
和index[pointer]
合法化。无论你如何编写代码,编译器通常都会生成相似的代码。
这允许像"hello"[2] == 'l'
和2["hello"] == 'l'
这样的酷事。
答案 4 :(得分:2)
使用数组语法进行随机访问很方便
_attributes->size = size + 1;
和顺序访问的指针算术语法
int getvalue(int *a, size_t x){return a[x];}
许多编译器可以优化对指针的顺序访问,而不是使用数组索引。
答案 5 :(得分:1)
对于在C中练习指针和数组习语,这些都是有效的代码块,并说明了表达同一事物的不同方式。
对于生产代码,您不会使用其中任何一种;你会使用更易于人类阅读的东西,更有可能被编译器优化。你完全放弃了循环而只是说:
printf("%s", name);
(请注意,这需要name
在字符串末尾包含\0
字符,printf
依赖该字符。您的name1
和name3
定义如所写的,不要分配必要的8个字节。)
如果你在你的代码中尝试做一些棘手的事情,需要你发布的一个更详细的方法,你选择哪种方法将取决于你想要做什么棘手的事情(你当然会在代码中解释)评论 - 否则,你会在六个月后查看自己的代码并问自己,“我在这做什么?”)。通常,对于从字符串中提取字符,name[i]
是比*(name+i)
更常见的习语。
答案 6 :(得分:1)
char name[] = "Madonah";
char* name = "Madonah";
在函数内部声明时,第一个选项在每次调用函数时都会产生额外的操作。这是因为每次调用函数时,字符串的内容都会从RO数据部分复制到堆栈中。
在第二个选项中,编译器只是将变量设置为指向内存中该字符串的地址,这在程序执行过程中是不变的。
因此,除非您计划更改本地数组的内容(不是原始字符串 - 该字符串是只读的),否则您可以选择第二个选项。
请注意,上面的所有细节都依赖于编译器实现,而不是C语言标准。
答案 7 :(得分:1)
我可以知道哪一个易于使用[...]
尝试坚持使用索引操作符[]
。
有一次你的代码变得更加复杂,然后你会注意到使用指针算术表达式“更容易”编写代码。
当您也开始使用address-of运算符时,通常会出现这种情况:&
。
例如,如果您认为自己需要编码:
char s[] = "Modonah";
char * p = &s[2]; /* This gives you the address of the 'd'. */
你很快就会注意到写作“更容易”:
char * p = s + 2; /* This is the same as char * p = &s[2];. */
答案 8 :(得分:0)
数组只是一个包含多个值的变量,每个值都有一个索引,您可能已经知道了 指针是你不需要知道的事情之一,直到你意识到你需要使用它们。指针本身不是变量,它们实际上是指向变量的指针 您可能希望如何以及为何使用指针的示例 您可以在一个函数中创建一个要在另一个函数中使用的变量 您可以将变量传递给函数头中的新函数。 这有效地将原始变量的值复制到新函数的本地新变量。在新函数中对其进行的更改仅更改新函数中的新变量 但是,如果您希望在新函数中进行更改以更改第一个函数中的原始变量,该怎么办? 你用指针 您可以将指针传递给变量,而不是将实际变量传递给新函数。现在,对新函数中的变量所做的更改将反映在第一个函数中的原始变量中 这就是为什么在您自己的示例中使用指向数组的指针并使用实际数组而在同一函数中具有相同的结果。他们俩都在说“改变这个数组”。