gpt4 book ai didi

c - 指针和数组—艰苦学习C

转载 作者:行者123 更新时间:2023-12-04 09:33:54 25 4
gpt4 key购买 nike

这个问题来自Zed Shaw的《 Learn C the Hard Way》。它是关于指针和数组的。这里给出一些代码:

#include <stdio.h>

int main(int argc, char *argv[])
{
// create two arrays we care about
int ages[] = {23, 43, 12, 89, 2};
char *names[] = {
"Alan", "Frank",
"Mary", "John", "Lisa"
};

// safely get the size of ages
int count = sizeof(ages) / sizeof(int);
int i = 0;

// first way using indexing
for(i = 0; i < count; i++) {
printf("%s has %d years alive.\n",
names[i], ages[i]);
}

printf("---\n");

// setup the pointers to the start of the arrays
int *cur_age = ages;
char **cur_name = names;

// second way using pointers
for(i = 0; i < count; i++) {
printf("%s is %d years old.\n",
*(cur_name+i), *(cur_age+i));
}

printf("---\n");

// third way, pointers are just arrays
for(i = 0; i < count; i++) {
printf("%s is %d years old again.\n",
cur_name[i], cur_age[i]);
}

printf("---\n");

// fourth way with pointers in a stupid complex way
for(cur_name = names, cur_age = ages;
(cur_age - ages) < count;
cur_name++, cur_age++)
{
printf("%s lived %d years so far.\n",
*cur_name, *cur_age);
}

return 0;
}


该指令指向“ rewrite all the array usage in this program so that it's pointers.”,这是否意味着要执行类似的操作?

int *ptr;
ptr = &ages[0]

最佳答案

首先让我说些不合时宜的话题:


我认为这不是一本好书。我认为这使某些主题变得混乱,使它们看起来比实际困难。对于一本更好的高级C书,我建议Deep C Secrets by Peter van der Linden,对于一本初学者的书,我建议原始的K & R


无论如何,您似乎正在查看this chapter中的额外功劳练习。


撇开其他地方-我认为这不是一个特别明智的学习练习(另一个答案指出,这个问题的形成没有道理),因此此讨论将变得有些复杂。相反,我会推荐K & R第5章中的练习。


首先,我们需要了解pointers are not the same as arrays。我在另一个答案here中对此进行了扩展,并且我将从C FAQ中借用相同的图表。当我们声明一个数组或一个指针时,这就是内存中发生的事情:

 char a[] = "hello";  // array

+---+---+---+---+---+---+
a: | h | e | l | l | o |\0 |
+---+---+---+---+---+---+

char *p = "world"; // pointer

+-----+ +---+---+---+---+---+---+
p: | *======> | w | o | r | l | d |\0 |
+-----+ +---+---+---+---+---+---+


因此,在本书的代码中,当我们说:

int ages[] = {23, 43, 12, 89, 2};


我们得到:

      +----+----+----+----+---+
ages: | 23 | 43 | 12 | 89 | 2 |
+----+----+----+----+---+


我将使用非法声明来进行解释-如果可以说的话:

int *ages = {23, 43, 12, 89, 2}; // The C grammar prohibits initialised array
// declarations being assigned to pointers,
// but I'll get to that


它将导致:

      +---+     +----+----+----+----+---+
ages: | *=====> | 23 | 43 | 12 | 89 | 2 |
+---+ +----+----+----+----+---+


稍后都可以以相同的方式访问这两个对象- ages[0]可以访问第一个元素“ 23”,而不管它是数组还是指针。到目前为止,一切都很好。

但是,当我们想要获得计数时,就会遇到问题。 C不知道数组有多大,它只知道它知道的变量有多大(以字节为单位)。这意味着,使用数组,您可以说出大小:

int count = sizeof(ages) / sizeof(int);


或者,更安全地:

int count = sizeof(ages) / sizeof(ages[0]);


在数组的情况下,这表示:

int count = the number of bytes in (an array of 6 integers) / 
the number of bytes in (an integer)


正确给出数组的长度。但是,对于指针情况,它将显示为:

int count = the number of bytes in (**a pointer**) /
the number of bytes in (an integer)


这几乎可以肯定与数组的长度不同。在使用指向数组的指针的地方,我们需要使用另一种方法来计算数组的长度。在C语言中,以下任一情况都是正常的:


记住有多少个元素:

int *ages = {23, 43, 12, 89, 2}; // Remember you can't actually
// assign like this, see below
int ages_length = 5;
for (i = 0 ; i < ages_length; i++) {

或者,保留哨兵值(永远不会在数组中作为实际值出现)以指示数组的结尾:

int *ages = {23, 43, 12, 89, 2, -1}; // Remember you can't actually
// assign like this, see below
for (i = 0; ages[i] != -1; i++) {


(这是字符串的工作方式,使用特殊的NUL值'\ 0'指示字符串的结尾)




现在,请记住我说过您实际上不能写:

    int *ages = {23, 43, 12, 89, 2, -1}; // Illegal


这是因为编译器不允许您将隐式数组分配给指针。如果您确实想要,可以写:

    int *ages = (int *) (int []) {23, 43, 12, 89, 2, -1}; // Horrible style 


但是请不要这样做,因为阅读起来非常不愉快。出于本练习的目的,我可能会写:

    int ages_array[] = {23, 43, 12, 89, 2, -1};
int *ages_pointer = ages_array;


请注意,编译器正在将数组名称“衰减”为指向该数组中第一个元素的指针-就像您已经编写了:

    int ages_array[] = {23, 43, 12, 89, 2, -1};
int *ages_pointer = &(ages_array[0]);


但是,您也可以动态分配数组。对于此示例代码,它将变得非常冗长,但是我们可以将其作为学习练习来做到。而不是写:

int ages[] = {23, 43, 12, 89, 2};


我们可以使用malloc分配内存:

int *ages = malloc(sizeof(int) * 5); // create enough space for 5 integers
if (ages == NULL) {
/* we're out of memory, print an error and exit */
}
ages[0] = 23;
ages[1] = 43;
ages[2] = 12;
ages[3] = 89;
ages[4] = 2;


请注意,当我们完成内存操作后,我们需要释放 ages

free(ages); 


还要注意,有几种写malloc调用的方法:

 int *ages = malloc(sizeof(int) * 5);


对于初学者来说,这更容易阅读,但通常被认为是较差的样式,因为如果更改 ages的类型,则需要在两个地方进行更改。相反,您可以编写以下任何一种:

 int *ages = malloc(sizeof(ages[0]) * 5);
int *ages = malloc(sizeof(*ages) * 5);


这些陈述是等效的-您选择的是个人风格的问题。我喜欢第一个。



最后一件事-如果我们将代码更改为使用数组,则可以考虑更改此内容:

int main(int argc, char *argv[]) {


但是,您不需要。之所以有点微妙。首先,此声明:

char *argv[]


说:“有一个指向argv的指针数组”。但是,编译器将函数参数中的数组视为指向数组第一个元素的指针,因此如果您编写:

int main(int argc, char *argv[]) {


编译器实际上会看到:

int main(int argc, char **argv)


这也是您可以忽略用作函数参数的多维数组的第一维长度的原因-编译器看不到它。

关于c - 指针和数组—艰苦学习C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17226278/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com