简体   繁体   English

C中的指针和数组,需要更多的理解

[英]Pointers and Arrays in C, Need for more Understanding

I was doing some pointers and arrays practice in C and I noticed all my four methods returned the same answer.My question is are there disadvantages of using any one of my below methods? 我在C中做了一些指针和数组练习,我注意到我的四个方法都返回了相同的答案。我的问题是使用以下任何一种方法都有缺点吗? I am stunned at how all these four give me the same output. 我惊讶于这四个人如何给我相同的输出。 I just noticed you can use a pointer as if it was an array and you can also use an array as if it was a pointer? 我只是注意到你可以使用一个指针,就像它是一个数组,你也可以使用一个数组,就好像它是一个指针?

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));
}

Results: 结果:

Madonah
Madonah
Madonah
Madonah

It is true that pointers and arrays are equivalent in some context, "equivalent" means neither that they are identical nor even interchangeable . 确实,指针和数组在某些上下文中是等价的“等效”意味着它们既不相同也不可互换 Arrays are not pointers . 数组不是指针
It is pointer arithmetic and array indexing that are equivalent, pointers and arrays are different . 指针算术和数组索引是等价的,指针和数组是不同的

which one is preferable and the advantages/Disadvantages? 哪一个更好,优点/缺点?

It depends how you want to use them. 这取决于您想要如何使用它们。 If you do not wanna modify string then you can use 如果你不想修改字符串,那么你可以使用

char *name = "Madonah";  

It is basically equivalent to 它基本上相当于

char const *name = "Madonah";  

*(name + i) and name[i] both are same. *(name + i)name[i]都是相同的。 I prefer name[i] over *(name + i) as it is neat and used most frequently by C and C++ programmers. 我更喜欢name[i]不是*(name + i)因为它很整洁并且最常用于C和C ++程序员。

If you like to modify the string then you can go with 如果你想修改字符串,那么你可以去

char name1[] = "Madonah";

In C, a[b] , b[a] , *(a+b) are equivalent and there's no difference between these 3. So you only have 2 cases: 在C中, a[b]b[a]*(a+b)是等价的,这三者之间没有区别。所以你只有2个案例:

char *name = "Madonah"; /* case 1 */

and

char name3 [7] = "Madonah"; /* case 2 */

The former is a pointer which points to a string literal. 前者是一个指向字符串文字的指针。 The latter is an array of 7 characters. 后者是一个7个字符的数组。

which one is preferred depends on your usage of name3 . 哪一个首选取决于你对name3的使用。

If you don't intend to modify then the string then you can use (1) and I would also make it const char* to make it clear and ensure the string literal is not modified accidentally. 如果你打算修改那么字符串然后你可以使用(1),我也会使它成为const char*以使其清楚并确保字符串文字不会被意外修改。 Modifying string literal is undefined behaviour in C 修改字符串文字是C中未定义的行为

If you do need to modify it then (2) should be used as it's an array of characters that you can modify. 如果你确实需要修改它,那么应该使用(2),因为它是你可以修改的字符数组。 One thing to note is that in case (2), you have explicitly specified the size of the array as 7 . 需要注意的一点是,在情况(2)中,您已明确指定数组的大小为7 That means the character array name3 doesn't have a null terminator ( \\0 ) at the end. 这意味着字符数组name3在末尾没有空终止符( \\0 )。 So it can't be used as a string . 所以它不能用作字符串 I would rather not specify the size of the array and let the compiler calculate it: 我宁愿不指定数组的大小,让编译器计算它:

char name3 [] = "Madonah"; /* case 2 */
/* an array of 8 characters */

Just in addition to what others said, I will add an image for better illustration. 除了别人说的话,我还会添加一张图片以便更好地说明。 If you have 如果你有

char a[] = "hello";
char *p = "world";

What happens in first case enough memory is allocated for a (6 characters) on the stack usually, and the string "hello" is copied to memory which starts at a . 在第一种情况下会发生什么,通常会为堆栈中a (6个字符)分配足够的内存,并将字符串“hello”复制到以a开头的内存中。 Hence, you can modify this memory region. 因此,您可以修改此内存区域。

In the second case "world" is allocated somewhere else(usually in read only region), and a pointer to that memory is returned which is simply stored in p . 在第二种情况下,“world”被分配到其他地方(通常在只读区域中),并返回指向该存储器的指针,该指针简单地存储在p You can't modify the string literal in this case via p . 在这种情况下,您无法通过p修改字符串文字。

Here is how it looks: 以下是它的外观:

在此输入图像描述

But for your question stick to notation which is easier, I prefer [] . 但是对于你的问题坚持更容易的符号,我更喜欢[] More info on relationship between arrays and pointers is here . 有关数组和指针之间关系的更多信息,请点击此处

In all cases, in C pointer + index is the same as pointer[index] . 在所有情况下,在C pointer + indexpointer[index]相同。 Also, in C an array name used in an expression is treated as a pointer to the first element of the array. 此外,在C中,表达式中使用的数组名称被视为指向数组的第一个元素的指针。 Things get a little more mystifying when you consider that addition is commutative, which makes index + pointer and index[pointer] legal also. 当你认为加法是可交换的时,事情变得更加神秘,这使得index + pointerindex[pointer]也合法。 Compilers will usually generate similar code no matter how you write it. 无论您如何编写代码,编译器通常都会生成类似的代码。

This allows cool things like "hello"[2] == 'l' and 2["hello"] == 'l' . 这允许很酷的事情,如"hello"[2] == 'l'2["hello"] == 'l'

it is convenient to use array syntax for random access 使用数组语法进行随机访问很方便

int getvalue(int *a, size_t x){return a[x];}

and pointer arithmetic syntax for sequential access 和用于顺序访问的指针算术语法

void copy_string(char *dest, const char *src){while((*dest++=*src++));}

Many compilers can optimize sequential accesses to pointers better than using array indices. 许多编译器可以优化对指针的顺序访问,而不是使用数组索引。

For practicing pointer and array idioms in C, those are all valid code blocks and illustrative of the different ways of expressing the same thing. 对于在C中练习指针和数组习语,这些都是有效的代码块,并说明了表达同一事物的不同方式。

For production code, you wouldn't use any of those; 对于生产代码,您不会使用其中任何一个; you would use something both easier for humans to read and more likely to be optimized by the compiler. 你会使用更易于人类阅读的东西,更有可能被编译器优化。 You'd dispense with the loop entirely and just say: 你完全放弃了循环而只是说:

printf("%s", name);

(Note that this requires name include the \\0 character at the end of the string, upon which printf relies. Your name1 and name3 definitions, as written, do not allocate the necessary 8 bytes.) (请注意,这需要name包含字符串末尾的\\0字符, printf依赖于该字符。您所写的name1name3定义不会分配必要的8个字节。)

If you were trying to do something tricky in your code that required one of the more verbose methods you posted, which method you chose would depend on exactly what tricky thing you were trying to do (which you would of course explain in code comments -- otherwise, you would look at your own code six months later and ask yourself, "What the heck was I doing here??"). 如果你试图在你的代码中做一些棘手的事情,需要你发布的一个更冗长的方法,你选择哪种方法将取决于你想要做什么棘手的事情(你当然会在代码注释中解释 - 否则,你会在六个月后查看自己的代码并问自己,“我在这做什么?”)。 In general, for plucking characters out of a string, name[i] is a more common idiom than *(name+i) . 通常,对于从字符串中提取字符, name[i]是比*(name+i)更常见的习语。

  1. char name[] = "Madonah";
  2. char* name = "Madonah";

When declared inside a function, the first option yields additional operations every time the function is called. 在函数内部声明时,第一个选项在每次调用函数时都会产生额外的操作。 This is because the contents of the string are copied from the RO data section into the stack every time the function is called. 这是因为每次调用函数时,字符串的内容都会从RO数据部分复制到堆栈中。

In the second option, the compiler simply sets the variable to point to the address of that string in memory, which is constant throughout the execution of the program. 在第二个选项中,编译器只是将变量设置为指向内存中该字符串的地址,该字符串在程序执行期间保持不变。

So unless you're planning to change the contents of the local array (not the original string - that one is read-only), you may opt for the second option. 因此,除非您计划更改本地数组的内容(不是原始字符串 - 该字符串是只读的),否则您可以选择第二个选项。

Please note that all the details above are compiler-implementation dependent, and not dictated by the C-language standard. 请注意,上面的所有细节都依赖于编译器实现,而不是C语言标准。

can I know which one is easy to use [...] 我能知道哪一个易于使用[...]

Try sticking to use the indexing operator [] . 尝试坚持使用索引操作符[]

One time your code gets more complex and you then notice that things are "more easy" to code using pointer arithmetical expressions. 有一次你的代码变得更复杂,然后你会注意到使用指针算术表达式编写代码“更容易”。

This typically will be the case when you also start to use the address-of operator: & . 当你也开始使用address-of运算符时,通常会出现这种情况: &

If for example you see your self in the need to code: 例如,如果您看到自己需要编码:

char s[] = "Modonah";
char * p = &s[2]; /* This gives you the address of the 'd'. */

you will soon notice that it's "easier" to write: 你会很快注意到写起来“更容易”:

char * p = s + 2; /* This is the same as char * p = &s[2];. */

An array is just a variable that contains several values, each value has an index, you probably know that already. 数组只是一个包含多个值的变量,每个值都有一个索引,您可能已经知道了。
Pointers are one of those things you dont need to know about until you realize you need to use them. 指针是你不需要知道的事情之一,直到你意识到你需要使用它们。 Pointers are not variables themselves they are literally pointers to variables. 指针本身不是变量,它们实际上是指向变量的指针。
An example of how and why you might want to use a pointer. 您可能想要使用指针的方式和原因的示例。
You create a variable in one function which you want to use in another function. 您可以在一个函数中创建一个要在另一个函数中使用的变量。
You could pass your variable to the new function in the function header. 您可以将变量传递给函数头中的新函数。 This effectively COPIES the values from the original variable to a new variable local to the new function. 这有效地将原始变量的值复制到新函数的本地新变量。 Changes made to it in the new function only change the new variable in the new function. 在新函数中对其进行的更改仅更改新函数中的新变量。
But what if you wanted changes made in the new function to change the original variable where it is in the first function ? 但是,如果您希望在新函数中进行更改以更改第一个函数中的原始变量,该怎么办?
You use a pointer. 你使用指针。
Instead of passing the actual variable to the new function, you pass a pointer to the variable. 您可以将指针传递给变量,而不是将实际变量传递给新函数。 Now changes made to the variable in the new function are reflected in the original variable in the first function. 现在,对新函数中的变量所做的更改将反映在第一个函数中的原始变量中。
This is why in your own example using the pointer to the array and using the actual array while in the same function has identical results. 这就是为什么在您自己的示例中使用指向数组的指针并使用实际数组而在同一函数中具有相同的结果。 Both of them are saying "change this array". 他们两个都在说“改变这个数组”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM