我是 C 新手,无法理解指针。我感到困惑的部分是关于char *and int *。
比如我们可以直接给char赋值一个指针,比如
char *c = "c";它不会出错。
但是,如果我像刚才那样为 int 分配一个指针,例如int * a = 10;,
它会出错。我需要在内存中腾出一个额外的空间来为 int 分配一个指针,
像int *b = malloc(sizeof(int)); *b = 20; free(b);...
谁能告诉我为什么?
我认为您误解了指针是什么以及它的含义。在这种情况下:
int* a = 10;
您说的是“创建一个指针(指向 an int)并将其指向文字内存位置0x0000000A(10)。
这和这个不一样:
int n = 10;
int* a = &n;
这是“创建一个指针(指向一个int)并将其指向n.
如果你想动态分配这个:
int* a = malloc(sizeof(int));
*a = 10;
翻译为“创建一个指针(指向一个int)并将其瞄准刚刚分配的内存块,然后将value分配给该位置10。
通常你永远不会分配一个int,你会为一个数组分配一堆,在这种情况下你会把它称为a[0]througha[n-1]一个 size 的数组n。在 C*(x + y)中,通常与 或 相同,x[y]换句话说*(x + 0),就是*x或x[0]。
在您的示例中,您不发送c到 char 'c'。您使用"c"的是字符串文字。对于字符串文字,它的工作原理如https://stackoverflow.com/a/12795948/5280183中所述。
像这样的字符串文字"c"实际上是一个数组表达式(的类型"c"是“2 元素数组” char)。
除非它是sizeofor&运算符的操作数,或者是用于在声明中初始化字符数组的字符串字面量,否则“array of T”类型的表达式将被转换,或“衰减”为“pointer to T”类型的表达式它的值将是数组第一个元素的地址。
所以当你写
char *c = "c";
大致相当于写
char string[] = "c";
char *c = &string[0];
您正在将指针分配给指针,因此编译器不会抱怨。
然而,当你写
int *a = 10;
您正在为指针分配int值并且类型不兼容,因此编译器会抱怨。指针不是整数;它们可能有一个整数表示,但这不能保证,它的大小不会与int.
在初始化过程中,右侧 (RHS) 表达式必须属于或可转换为声明的变量的类型。
如果你这样做
char *cp = ...
int *ip = ...
那么 in...必须可以转换为指向 achar的指针或指向 a 的指针int。还要记住 achar是单个字符。
现在,"abc"是 C 中的特殊语法 - 字符串文字,用于创建(许多)不可变字符的数组。它的类型是文字中的字符数加上终止空字符的字符数char [size]。类型size也是如此。它不是。C 中的数组被隐式转换为指向第一个元素的指针,然后具有“指向元素类型的指针”类型。in类型的ie被隐式转换为 type ,它指向两个字符中的第一个并且在两个字符数组中。它也是方便的类型,现在我们有了"c"char [2]char"c"char [2]char *cp = "c";char *c\0char *char *cp = (something that has type char * after conversions);.
至于int *,您正在尝试将整数值传递给指针。它没有任何意义。
一个指针保存一个地址。如果你要问福尔摩斯的地址,答案是贝克街 221 号。现在,您所做的是“福尔摩斯的地址是我今天早上为他拍的这张照片”。
编写的相同错误代码char *将是
char *cp = 'c'; // or more precisely `char *p = (char)'c';
它会给你完全相同的错误来证明这一点char *cp并且int *cp工作相同。
不幸的是,C 没有int字符串文字,也没有整数数组的文字,尽管从 C99 开始,您可以编写:
int *ip = (int[]){ 5 };
或者
const int *ip = (const int[]){ 5 };
同样,您始终可以将 achar *或指向该类型int *的单个对象:
字符 a = 'c'; 字符 *pa = &a; 诠释 b = 42; int *pb = &b;
现在我们可以说a和*pa指定同一个 char对象a,同样b和*pb指定同一个 int对象b。如果你改变了*pa,你就会改变a,反之亦然;同样对于b和*pb。
c中的int指针和char指针有区别吗?
在过去的几十年中,C 中的所有指针都是一样的。一段时间以来,在某些平台(如 Windows)中,由于一种称为内存模型的东西,存在不同大小的指针。
今天,编译器根据平台将代码设置为使用 32 位或 64 位或任何大小的指针,但一旦设置,所有指针都是相等的。
不相等的是指针指向的东西,是你困惑的东西。
void*指针。malloc()在 C 中分配内存。它总是返回一个void*指针,然后你将它转换为你需要的任何东西sizeof(void*)是一样的sizeof(int*)。sizeof(GiantStruct*)And与 64 位编译器中的 and相同是 8 字节或 64 位"c"。是char[2]。它是一个字符串文字。系统将在内存中的某处分配至少 2 个字节的区域,将 a'c'和零放在那里,因为字符串文字以NULL终止C,因此将该地址放入分配给您的指针的地址中c。int* a = 10?a?a 是int*指向a 的指针int。什么是*a?一个int。在哪个地址?10. 好吧,事实是,系统不会因为您设置了指向该地址的指针而让您访问该地址。在 80 年代你可以。今天对此有非常严格的规定:您只能访问分配给您的进程的内存。仅有的。因此,一旦您尝试访问,系统就会中止您的程序。如果你写
int* a = malloc(300);
系统将分配一个 300 字节的区域,取区域地址并在分配给 a 的地址处为您写入。当您写入时*a=3456,系统会将这个值写入该sizeof(int)地址的第一个字节。
您可以肯定地写入所有 300 个,但您必须稍微操纵指针以指向该区域内。只在那个区域内。事实上,C 语言就是为此而设计的。
让我们将“c”写入分配给 a 的 300 字节区域的末尾:
#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语言是一种严格类型的语言。在生成机器代码之前,编译器会检查一些可能的错误。类型不同,这就是编译器想要知道的全部。
但是从位字节的角度来看,对于C语言来说,与上述两个指针没有区别。
使用在线编译器查看您的代码
void main(){
int * a = 10; /* <= this presumably gives you an error. */
}
我所做的是复制粘贴您的代码,这会给您带来错误。并且在线编译器发出了警告,而不是错误。甚至不止于此。C将标准更改c17,您仍然只会收到警告。
关于将字符串文字分配给指针的注释已在 SO 上进行了广泛讨论。它值得一个不同的话题。
把它们加起来。对于C语言而言,上述两个指针没有有意义的区别。用户负责了解他/她的程序中的内存布局。总而言之,该语言被设计为一种在线性内存上运行的高级工具。