我目前正在学习C http://c.learncodethehardway.org/book/,我们应该自己想出一些奇怪的事情。
首先,我发现这个webpage已经帮助我理解了有关函数和函数定义以及指针及其用法的一些内容。 现在问题出现在我看到一些“字符串”定义时。
如果我要做的这些假设是错误的,请纠正我:
char name[] = "John"; // creates an array of characters with these four letters + '\0'
“string”只是以'\0'
结尾的字符数组。
我还读到标识符之前的*
通常意味着它是一个指针。例如:
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?
如果这些假设是正确的,我不明白这里发生了什么:
char *name = "John";
这是一个指向字符串的指针吗?或者它是另一种定义字符串的方法?如果是的话,是
char *name[] = "John";
指向“字符串”的实际指针? (这只是一个字符数组?)。
修改
阅读你所有的答案和评论我必须要问另一件事。 “type char *
”是指向char的指针,对吗?
答案 0 :(得分:4)
本声明
char name[] = "John";
表示name
是一个包含以下序列的字符数组
{ 'J', 'o', 'h', 'n', '\0' }
实际上你可以写
char name[] = { 'J', 'o', 'h', 'n', '\0' };
这些记录是等效的。
至于这句话
char *name = "John";
然后编译器会执行以下操作。它创建一个类型为char[5]
的数组来存储字符串文字,然后将该数组的第一个字符的地址分配给指针name
。所以name
将包含字符串文字的第一个字符的地址。虽然C中的字符串文字具有非const数组的类型,但您可能无法更改它们。所以写
const char *name = "John";
对于本声明
char *name[] = "John";
编译器应该发出错误,因为初始化一个数组(字符数组除外)必须使用一个brace-init列表。有效记录将显示为
char *name[] = { "John" };
在这种情况下,数组只有一个char *
类型的元素指向字符串文字的第一个字符。字符串文字本身将由编译器作为类型char[5]
的数组放在内存中。
至于记录之间的区别
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?
和
char *name = "John";
然后在第一个记录中有一个标量对象myNum
,您必须应用operator &
来获取其地址。
在第二个记录中,字符串文字是一个数组。在这样的表达式中,编译器将其调整为指向数组的第一个元素的指针。因此,您没有对字符串文字应用operator &
。右侧的表达式已经键入char *
。
答案 1 :(得分:2)
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?
myNum
的类型为int
,其中包含整数。
myNum_pointer
的类型是int *
,其中包含整数变量的地址。
-----------------------------------------------------
variables: | myNum | myNum_pointer |
-----------------------------------------------------
address : | 0x12341234 | 0x12341238 |
-----------------------------------------------------
&
运算符获取操作数的地址。因此,&myNum
等于0x12341234
所以变量初始化如下:
variables: | myNum | myNum_pointer |
---------------------------------------------
address : | 0x12341234 | 0x12341238 |
---------------------------------------------
value : | 18 | 0x12341234 |
---------------------------------------------
现在
char *name = "John";
将name定义为指向字符串中第一个字符的指针。赋值意味着一旦程序加载,指针就会被设置为保存字符串存储的地址。它将字符串文字放在只读部分。 指针只保存一个地址,它们不能保存字符数组中的所有字符。这意味着当我们使用char *来跟踪字符串时,包含该字符串的字符数组必须已经存在。
EX>
char name[] = "John";
char *name2;
name2=name;
name @2000
----------------------
| j | o | h | n | \0 |
----------------------
name2 @3000
--------
| 2000 |
--------
另外
对于指向字符串数组的指针,您可以将其定义为
char * mystr[10];
之后你可以通过
来初始化它mystr[i]="john";
或者在定义时也可以初始化,如
const char *digitnames[] = {"zero", "one", "two", "three",
"four", "five", "six", "seven", "eight", "nine"};
答案 2 :(得分:1)
char *name = "John";
定义一个匿名的,静态分配的包含{'J', 'o', 'h', 'n', 0}
的五个字节的数组,并声明一个指针name
,它最初指向上述数组的第一个元素。这就是C中的规则:数组“衰减”成指向其第一个元素的指针。
char *name[] = "John";
无效。它像以前一样定义了一个char
数组,但后来尝试将它分配给char
指针数组,这没有任何意义。 char *[]
的用例是存储(指向第一个char
)多个字符串:
char *names[] = {"John", "Mary"};
读作:names
是一个数组([]
),其中每个元素都是char*
;我们使用元素"John"
和"Mary"
初始化此数组,并且由于我们正在初始化指针,因此这些char
数组会衰减为指向其第一个元素的指针。
答案 3 :(得分:1)
让我们来看看这一行:
int myNum = 18;
在该行中,您定义了一个具有多个属性的变量:
myNum
int
0xa1
的值,但它可以是任何类型的值。18
要获取变量的地址,请使用&
运算符。在这种情况下,行:
int *myNum_pointer = &myNum;
在右侧,&myNum
返回myNum
的地址,在我们的情况下,该地址的评估结果为0xa1
。我们将它存储在一个名为myNum_pointer
的变量中,该变量的类型为指向int ,这意味着它存储了一个int变量的地址。由于myNum_pointer
是其自身的变量,因此它也拥有自己的属性:
myNum_pointer
int*
(指向int的指针)0xa2
。0xa1
(myNum
的地址)。所以,是的,你确实需要&
运算符。
关于字符串的部分:不要以这种方式在C中定义字符串。
char name[] = "John"; // Good
char *name = "John"; // Bad
这是因为尽管数组和指针是相关的,they are not the same thing。有些编译器会警告您第二个语句在C中已弃用。
最后,
char *name[] = "John";
不正确。因为在这里你说的是一个指向字符的指针数组,当它只是一个字符数组时。
"John"
实际上是一个字符串文字,它是{'J', 'o', 'h', 'n', 0}
的数组,其中0
是空终止字符,表示C中字符串的结尾。事实上,没有最后0
,{'J', 'o', 'h', 'n'}
只是一个字符数组,而不是一个正确的字符串,这是另一个重要的区别。
答案 4 :(得分:0)
我想这是其他数百个问题的重复,但无论如何我都会回答它。
首先,'&'是变量地址的一元运算符。因此,例如,& foo可能是像0xffff这样的地址。所以你肯定需要'&',否则,如果foo == 1,你的指针将在地址0x0001上,如果你想改变它,你会得到一个段错误(我猜它甚至不会编译)。
第二
char* name="John";
做两件事。它在内存中分配一个不可变的部分,并将“John \ 0”写入其中。你有一个指向那个内存的指针,但你不能改变它,比如写“john \ 0”。
第三
char* name[]
是指向字符数组的指针。它也可以这样写:
char** name
或者这个:
char name[][]
它实际上是一个字符串数组。
有趣的事实:指针前面的'*'返回poiner所指向的对象的值。 E.g:
int i=0;
int* pi;
pi=&i;
i==*pi //this is true
答案 5 :(得分:0)
回答你的问题:
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?
是的,你需要& (这是Address-of运算符)。这会将指针myNum_pointer指定为myNum的地址。如果你取出&,你将myNum中的数字直接分配给指针,这是一件坏事,而不是预期的。稍后使用myNum_pointer时会出现问题,它指向内存地址18而不是myNum变量的内存地址(如果编译器甚至接受它)。这可能会在运行时导致分段错误,这可能很难调试。