指针和数组——艰难地学习C语言
这个问题来自Zed Shaw的《艰难学习C》。它是关于指针和数组的。这里给出了一些代码:指针和数组——艰难地学习C语言,c,arrays,pointers,C,Arrays,Pointers,这个问题来自Zed Shaw的《艰难学习C》。它是关于指针和数组的。这里给出了一些代码: #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"
#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;
}
它的意思可能和你建议的一样,是的 但是请记住,
ages
已经是一个int指针(int*
)——在C语言中,数组只是一组在内存中彼此相邻的东西。表示该数组的变量只是指向该数组中第一个元素的指针,[]
运算符是一个解引用
你可以这样想:
程序运行时,某个地方有一块内存,其中包含|……| 23 | 43 | 12 | 89 | 2 |……|
其中每个框表示足够容纳一个
int
那么,程序中的变量
ages
就是一个指针,它保存该块中第一个元素的地址。它“指向”了23
,并且具有类型int*
。如果取消引用,您会发现*ages
的计算结果为23。类似地,如果您获取该地址并向前“跳过”一个int
-size,您将得到43
。在代码中,这看起来像*(年龄+1*sizeof(int))
您可以将
1
替换为要跳过的元素数量。因为这真的很难看而且令人困惑,所以C提供了一种很好的方法来做完全相同的事情:[]
操作符。总的来说
some_数组[n]=*(some_数组+n*sizeof(数组元素类型))
希望对大家有所帮助,祝学习C好运!确保花时间真正理解数组和指针的相等性;如果你不这样做的话,以后很多事情会变得更加困难。我猜这意味着
malloc()
为每个数组分配内存,并使用free()
释放内存int *ptr = &ages[0];
使用
ptr
代替ages
,您只需将代码中已经隐式存在的东西显式地表示出来。如果这就是那个任务的真正含义,那么你当然可以做到。但我认为这样的冗余练习没有多大意义。这里有一种方法可以将年龄和名称更改为指针,而不使用动态分配
// create two arrays we care about
const char *ages = "\x17\x2b\x0c\x59\x02";
const char (*names)[6] = (void *)
"Alan\0\0" "Frank\0" "Mary\0\0" "John\0\0" "Lisa\0\0";
// safely get the size of ages
int count = strlen(ages);
//...
// setup the pointers to the start of the arrays
const char *cur_age = ages;
const char (*cur_name)[6] = names;
名称
和cur_name
都是指针类型,尽管它们确实指向数组。让我先说一些离题的话:
- 我认为这不是一本很好的书。我认为它混淆了一些主题,使它们看起来比实际更难。对于更好的高级C语言书,我推荐,对于初学者书,我推荐原版
不管怎么说,看起来你是在看来自美国的额外学分练习
- 另一方面,我不认为这是一个特别明智的学习练习(另一个答案指出这个问题没有意义),所以这个讨论会变得有点复杂。相反,我会推荐第5章的练习
首先,我们需要了解这一点。我在另一个答案中对此进行了扩展,我将从。下面是当我们声明数组或指针时内存中发生的情况:
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 |
+---+ +----+----+----+----+---+
这两个元素以后可以以相同的方式访问-第一个元素“23”可以由ages[0]
访问,无论它是数组还是指针。到目前为止还不错
然而,当我们想要得到计数时,我们遇到了问题。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++) {
(这是字符串的工作方式,使用特殊的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;
请注意,在使用完内存后,我们需要释放age
:
free(ages);
还要注意,有几种方法可以编写malloc调用:
int *ages = malloc(sizeof(int) * 5);
这对于初学者来说更清楚,但一般认为是不好的风格,因为有两个地方
free(ages);
int *ages = malloc(sizeof(int) * 5);
int *ages = malloc(sizeof(ages[0]) * 5);
int *ages = malloc(sizeof(*ages) * 5);
int main(int argc, char *argv[]) {
char *argv[]
int main(int argc, char *argv[]) {
int main(int argc, char **argv)