【问题标题】:Are there differences between int pointer and char pointer in c?c中的int指针和char指针有区别吗?
【发布时间】:2020-10-07 22:07:07
【问题描述】:

我是 C 新手,无法理解指针。我感到困惑的部分是关于char *int *

比如我们可以直接给char赋值一个指针,比如

char *c = "c"; 不会出错。

但是,如果我像刚才那样为 int 分配一个指针,例如int * a = 10;

它会出错。我需要在内存中腾出一个额外的空间来为 int 分配一个指针,

点赞int *b = malloc(sizeof(int)); *b = 20; free(b);...

谁能告诉我为什么?

【问题讨论】:

  • "this is not a char",因此与尝试将 int 分配给 int* 相比是不可比的;与char* ch = 'c' 相比,这应该说明为什么它通常没有多大意义(并且是类型错误),需要更大的锤子来用力。
  • 这能回答你的问题吗? String literals: pointer vs. char array
  • 顺便说一句,避免pointer = malloc(sizeof(pointee_type));,因为它很容易出错。首选不重复类型的pointer = malloc(sizeof *pointer);

标签: c pointers


【解决方案1】:

我认为您误解了指针是什么以及它的含义。在这种情况下:

int* a = 10;

您是说“创建一个指针(指向 int)并将其指向文字内存位置 0x0000000A (10)。

这和这个不一样:

int n = 10;
int* a = &n;

这是“创建一个指针(指向int)并将其指向n的内存位置。

如果你想动态分配这个:

int* a = malloc(sizeof(int));
*a = 10;

这意味着“创建一个指针(指向int)并将其指向刚刚分配的内存块,然后将值10 分配给该位置

通常你永远不会分配一个int,你会为一个数组分配一堆,在这种情况下,你会将它称为a[0]a[n-1] 用于大小为@ 的数组987654333@。在 C 中,*(x + y) 通常与 x[y] 相同,或者换句话说,*(x + 0) 要么只是 *x 要么 x[0]

【讨论】:

    【解决方案2】:

    在您的示例中,您没有将c 发送到字符'c'。您使用了"c",这是一个字符串文字。 对于字符串文字,它的工作原理如 https://stackoverflow.com/a/12795948/5280183 中所述。

    【讨论】:

      【解决方案3】:

      "c" 这样的字符串文字实际上是一个数组表达式("c" 的类型是“char 的二元数组”。

      除非它是sizeof& 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则将转换类型为“T”的表达式,或者“衰减”为“指向T”类型的表达式,其值将是数组第一个元素的地址。

      所以当你写的时候

      char *c = "c"; 
      

      大致相当于写

      char string[] = "c";
      char *c = &string[0];
      

      你将一个指针分配给一个指针,所以编译器不会抱怨。

      但是,当你写的时候

      int *a = 10;
      

      您将 int 值分配给指针并且类型不兼容,因此编译器会抱怨。指针不是整数;它们可能有一个整数表示,但这不能保证,它的大小与int不同。

      【讨论】:

        【解决方案4】:

        初始化中,右侧 (RHS) 表达式必须属于或可转换为声明的变量的类型。

        如果你这样做

        char *cp = ...
        int *ip = ...
        

        那么... 中的内容必须可转换为指向char 的指针或指向int 的指针。另请记住,char 是单个字符。

        现在,"abc" 是 C 中的特殊语法 - 字符串文字,用于创建 (许多)不可变字符的数组。它的类型为char [size],其中size 是文字中的字符数加上终止空字符的1。所以"c" 的类型为char [2]。不是char。 C 中的数组隐式转换指向第一个元素的指针,然后具有“指向元素类型的指针”类型。 IE。 char *cp = "c";char [2] 类型的"c" 隐式转换为char * 类型,它指向两个 字符c 和@987654337 中的第一个 @ 在两个字符数组中。它也是char * 类型,现在我们有了char *cp = (something that has type char * after conversions);

        至于int *,您正在尝试将整数值传递给指针。这没有意义。

        一个指针保存一个地址。如果你要问福尔摩斯的地址,答案是贝克街 221 号。现在你所做的是“福尔摩斯的地址是我今天早上给他拍的这张照片”。

        char * 编写的相同错误代码将是

        char *cp = 'c'; // or more precisely `char *p = (char)'c';
        

        它会给出完全相同的错误,证明 char *cpint *cp 工作相同。


        不幸的是,C 没有 int 字符串字面量 也没有 整数数组的字面量,尽管从 C99 开始您可以编写:

        int *ip = (int[]){ 5 };
        

        const int *ip = (const int[]){ 5 };
        

        同样,您始终可以将char *int * 指向该类型的单个 对象:

        字符 a = 'c'; 字符 *pa = &a; 诠释 b = 42; int *pb = &b;

        现在我们可以说a*pa 指定相同 char 对象a,同样b*pb 指定相同 em>int 对象b。如果您更改*pa,您将更改a,反之亦然; b*pb 也是如此。

        【讨论】:

          【解决方案5】:

          c中的int指针和char指针有区别吗?

          简短回答:否

          在过去的几十年里,C 中的所有指针都是一样的。一段时间以来,在某些平台(如 Windows)中,由于一种称为内存模型的东西,存在不同大小的指针。

          今天编译器将代码设置为使用 32 位或 64 位或任何大小的指针,具体取决于平台,但一旦设置,所有指针都相等。

          不相等的是指针指向的东西,是你困惑的东西。

          • 考虑一个void* 指针。 malloc() 在 C 中分配内存。它总是返回一个 void* 指针,然后你将它转换为你需要的任何东西
          • sizeof(void*)sizeof(int*) 相同。与sizeof(GiantStruct*) 相同,在 64 位编译器中为 8 字节或 64 位

          char* c = "c" 呢?

          • 您必须问自己"c" 是什么。是char[2]。它是一个字符串文字。系统将在内存中的某处分配至少 2 个字节的区域,将一个 'c' 和一个零放在那里,因为字符串文字以 NULL 终止于 C,将该地址放入分配给您的指针的地址中c

          int* a = 10 呢?

          • 是一回事。等操作系统进来就好了。a是什么? a 是 int* 指向 int 的指针。 *a 是什么?一个int。在哪个地址? 10。好吧,事实是,系统不会因为您设置了指向该地址的指针而让您访问该地址。在 80 年代你可以。今天对此有非常严格的规定:您只能访问分配给您的进程的内存。仅有的。因此,只要您尝试访问,系统就会中止您的程序。

          一个例子

          如果你写

              int* a = malloc(300);
          

          系统将分配一个 300 字节的区域,取区域地址并在分配给 a 的地址处为您写入。当您写入*a=3456 时,系统会将此值写入该地址的第一个sizeof(int) 字节。

          您可以肯定地写入所有 300 个,但您必须稍微操纵指针以指向该区域内。只在那个区域内。 事实上,C 语言就是为此而设计的。

          让我们在分配给 a 的 300 字节区域的末尾写上“c”:

          #include <stdio.h>
          #include <stdlib.h>
          int main(void)
          {
              char* c = "c";
              int* a = (int*)malloc(300);
              *a = 3456;
              printf("Area content is %d\n", *a);
              char* pToEnd = (char*)a + 298;
              *(pToEnd) = 'c';
              *(pToEnd + 1) = 0;
              printf("At the end of the 300-byte area? [Should be 'c'] '%s'\n", pToEnd);
              printf("The pointer c points to '%s'\n", c);
              //*c = 'x'; // error: cancel program
              c = pToEnd;
              printf("The pointer c now points do the end of the 300-byte area:'%s'\n", c);
              free(a);
              return 0;
          };
          
          

          看看

          Area content is 3456
          At the end of the 300-byte area? [Should be 'c'] 'c'
          The pointer c points to 'c'
          The pointer c now points do the end of the 300-byte area:'c'
          

          还请注意,一旦您尝试改写c,即示例中的char 指针,您的程序也将取消。它是一个只读区域 --- 请参见第 14 行的注释。但是您可以在示例中的区域内指向 c 并使用它,因为指针本身不是常量。

          当您在上面的示例中编写c = pToEnd 时,对字符串文字的访问将永远丢失。在某种意义上是内存泄漏,但它是一个静态分配的区域。 泄漏不是区域而是地址。

          还要注意最后是free(a),即使是a int* 将释放所有 300 个字节

          【讨论】:

          • "在过去的几十年里,C 中的所有指针都是一样的。" 2020年各个平台仍然有不同大小的对象和函数指针。
          • “因为字符串文字在 C 中以 NULL 结尾”更好,因为 null 字符 终止。在空指针常量而不是空字符的上下文中使用 NULL 很好。
          • @chux-ReinstateMonica 您是否阅读了所有文本?不同的平台,不是同一时间。
          • 在给定的实现和平台(同时相同)中,函数指针和对象指针的大小可能不同,即使在 2020 年也是如此。如果您有疑问,请将其作为问题发布。
          【解决方案6】:

          您的问题的直接答案是,C 语言是一种严格类型的语言。在生成机器代码之前,编译器会检查一些可能的错误。类型不同,这就是编译器想要知道的全部内容。

          但是从位字节的角度来看,没有区别,对于C语言,上面两个指针。

          看看your code with online compiler

          void main(){
           int * a = 10; /* <= this presumably gives you an error. */
          }
          

          我所做的是复制粘贴您的代码,这会给您带来错误。 并且在线编译器发出了警告,而不是错误。甚至更多。将C 标准更改为c17,您仍然只会收到警告。

          关于将字符串文字分配给指针的注释已在 SO 上进行了广泛讨论。它值得一个不同的主题。

          总结一下。对于C 语言,上述两个指针没有任何意义的区别。用户负责了解他/她的程序中的内存布局。总而言之,该语言被设计为一种在线性内存上运行的高级工具。

          【讨论】:

          • 您需要在此处在您的回答中发布minimal reproducible example,并在任何第三方网站上发布not a link
          • @Rob 提问者需要提供一个例子,而不是我。您错过了 SO 站点的要点。顺便说一句,您发布的链接与 mu 答案以及原始问题无关。坦率地说,我没有得到你的评论。
          猜你喜欢
          • 1970-01-01
          • 2017-06-19
          • 2012-03-02
          • 1970-01-01
          • 1970-01-01
          • 2016-12-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多