Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
指针和数组——艰难地学习C语言_C_Arrays_Pointers - Fatal编程技术网

指针和数组——艰难地学习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"

这个问题来自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"
  };

  // 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()
    释放内存

  • 在所有for循环中使用指针算法

  • “使用指针而不是数组来重写代码”这一任务的表述不够清晰,没有意义。在C语言中,99.9%(只是一个非正式数字)的数组功能基于隐式数组到指针的转换,这意味着几乎每次使用数组时,都会使用指针。这是没有办法的

    换句话说,从形式上来说,真的没有必要重写任何东西

    如果您通过执行以下操作重写代码

    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)