本周我一直在努力学习C语言。我一直在阅读C Primer Plus (5th Edition) ,但我对变量和指针仍然有点麻烦。
这是我用来测试的脚本:
int main (int argc, char **argv) {
char *myvariable=NULL;
myvariable = strdup("apples");
myvariable = strdup("value updated");
printf("========== \n\n");
printf("this is the thing : %p \n", myvariable);
printf("this is the thingval: %s \n", myvariable);
setvariable(&myvariable);
printf("after function - this is the thing : %p \n", myvariable);
printf("after function - this is the thingval: %s \n", myvariable);
return 0;
}
int setvariable(char **myvariable) {
*myvariable = strdup("value from function");
return 1;
}
运行它的输出给了我:
this is the thing : 0x7fee9b4039c0
this is the thingval: value updated
after function - this is the thing : 0x7fee9b4039d0
after function - this is the thingval: value from function
char *myvariable=NULL;
是否意味着myvariable
是指针或变量? This answer说表单char *ptr = "string";
只是向后兼容const char *ptr = "string";
使用函数setvariable(char **myvariable)
- **myvariable
是“指向指针的指针”吗?
或者myvariable
实际上只是一个字符串(nul终止的字符数组)?
这是我发现的一些代码(没有文档)所以我对它有很多疑问。下一个问题是为什么myvariable
以这种方式定义 - 并且将它设置为以下方式之一并不是更好:
char myvariable[] = "apples";
char myvariable[6] = "apples";
我也不明白为什么当setvariable
被调用时,似乎是在&
传递myvariable的地址时 - 传递指针不是更好吗?
在询问之前我曾尝试对此进行研究 - 但是经过两天的进展很慢,我想要一些建议。
要求澄清
我问的原因是因为形式我读过它看起来像是*
后面有char *myvariable
,如char
那么它应该是一个指针。
但是,我在创建不是指针的myvariable
时遇到问题,并指定{{1}}指针指向它。
答案 0 :(得分:2)
char * myvariable = NULL;是指myvariable是指针还是函数?
myvariable
是指针(即变量,因为指针是变量)。
1)这是真的吗?
我认为它不是真正的向后兼容性。但是,"string"
之类的字符串行为表示为常量字符串。
2)我是否创造了一个恒定的角色?
尝试修改字符串"string"
的字符是未定义的行为。没有const
,因为匿名字符串的类型是char[]
。但程序员经常建议将其声明为const
,以防止错误。
3)那些应该是不可变的吗?如果是这样,为什么我可以更新值?
您不能修改*myvariable
(只要它被分配给字符串litteral ),但您可以修改指针myvariable
。
使用函数setvariable(char ** myvariable) - ** myvariable是“指向指针的指针”吗?
是的,是的。
或者myvariable实际上只是一个字符串(nul终止的字符数组)?
*myvariable
是一个字符串和指向char
的指针。
顺便说一句,我想你应该阅读this answer。
答案 1 :(得分:1)
char * myvariable = NULL;是指myvariable是指针还是变量?
myvariable
是“指向char
的指针”类型的变量。它将用于存储“char”类型的对象的地址。
这个答案说形式char * ptr =“string”;只是const char * ptr =“string”;
的向后兼容性
的向后兼容性?
字符串文字表达式"string"
具有“{元素数组char
”(6个字符加0个终结符)。在C中,类型为“{-1}}的N元素数组”的表达式将被转换为“指向T
的指针”的表达式,它的值将是地址当数组表达式是T
或一元sizeof
运算符的操作数时,数组中第一个元素除之外,或者是用于初始化另一个数组的字符串文字在声明中。
所以当你写
&
表达式char *ptr = "string";
不是"string"
或一元sizeof
运算符的操作数,也不是用于在声明中初始化数组,因此其类型转换为“ 7个元素的&
“到”指向char
的指针“,指针值(数组的第一个元素的地址)被复制到char
。
C的一个问题是尝试修改字符串文字的内容会调用未定义的行为。有些平台将字符串文字放在只读内存中,有些则没有;如果代码中存在多个实例,则有些实例会创建文字的多个实例,有些只在文字上创建一个实例。因此,尝试修改文字可能会在某些平台上起作用,导致对其他平台的访问冲突,导致其他人无法预测的行为等.C语言标准明确地将行为保留为未定义,以便实现可以任意方式自由处理这种情况觉得合适。
作为安全措施,大多数人明确声明指针为ptr
:
const char *
这样您就无法通过const char *ptr = "string";
修改字符串内容。请注意,C ++在字符串文字类型为“ptr
数组”方面有所不同,因此无论如何这些表达式都将转换为const char
。
我问的原因是因为我读过它的形式看起来好像有什么东西在它之后,就像char * myvariable那样它应该是一个指针。
在C(和C ++)中,声明基于表达式的类型;声明中表达式的形式与代码中表达式的形式相匹配。
例如,如果我们有一个名为const char *
的指针变量指向p
,并且我们想要访问该整数值,我们取消引用指针一元int
运算符:
*
表达式 x = *p;
的类型为*p
,因此变量 int
的声明为
p
变量int *p;
的类型是“指向p
的指针”。 int
的{{1}} - ness由类型说明符int
给出; p
的指针由声明符 int
给出。请注意,p
绑定到标识符,而不是类型说明符;即使您可以将声明写为
*p
它被解释为
*
答案 2 :(得分:0)
通过撰写char *myvariable
,int foo
,double blah
或void (*funcptr)(void)
,您声明某种类型的变量。变量的类型指定存储在该变量中的内容:指针,数字或结构。
因此,char *myvariable
是包含指针值的变量(一些保留的内存量)。
答案 3 :(得分:0)
char* myvariable
- char*
正在设置一个指向内存位置的指针,该内存位置包含char
类型的对象
myvariable
是用于引用该位置的变量。
要使用&myvariable
我在10年前做过C ++,而不是C,但我认为这相当准确。
答案 4 :(得分:0)
char c; // allocates a variable with space to hold one character
char *p; // allocates a pointer that may point to a character
p = &c; // sets variable p to point to the storage allocated for c
c = 'a'; // stores character 'a' in the storage allocated for c
*p = 'a'; // has exact same result as previous
char const *mesg = "abcd";
// allocates 5 characters ('a', 'b', 'c', 'd', '\0')
// also allocates a pointer that may point to a character
// also makes the pointer point to the literal string "abc"
char buf5[] = "abcd";
// Allocates 5 characters ('a', 'b', 'c', 'd', '\0')...
// the compiler figures out how many values need to go in the array.
// Variable buf5 is a reference to this array
char x5[] = { 'a', 'b', 'c', 'd', '\0' };
// has exact same result as previous
sizeof(buf5) // evaluates to the value 5
int i5[5];
sizeof(i5) // evaluates to: sizeof(int) * 5
sizeof(buf5) // evaluates to: sizeof(char) * 5
// but sizeof(char) is always 1 (by definition!)
sizeof(p) // evaluates to size of a pointer (probably 4 or 8)
// size of pointer does not change no matter which string it points to
buf5[0] = 'A'; // now s3 holds: "Abcd"
*buf5 = 'A'; // has exact same result as previous
buf5[1] = 'B'; // now s3 holds: "ABcd"
*(buf5 + 1) = 'B'; // has exact same result as previous
您可以轻松覆盖char数组buf5
中的字符,但不能增加为其分配的存储空间大小;您只能重复使用现有存储。
当您声明一个数组时,您“拥有”该存储; C为你设置它。当你使用文字字符串时,你可能会或者可能无法写入它,并且最好不要尝试。文字可能放在特殊的地方(比如嵌入式系统中的ROM),甚至可能无法写入它,因此任何依赖于写入文字的程序都是不必要的不可移植的。
至于表示法......
当你使用指针时,如果你在它前面放了一个*
,那么取消引用指针。这使您可以检查指针指向或修改它的内容。
当您声明指针时,在C中使用相同的语法声明它,这有点棘手。但这里有一些例子:
char c; // c has the type char
char *p; // when you dereference the pointer p, you get type char
// Assume p contains garbage right now; we have no idea where it might point
c = 'a'; // legal: assigning a char value to a char type
*p = 'a'; // legal just as above
p = &c; // p now points to the storage for variable c
char **pp; // pp is a pointer to a pointer to char
// If you dereference pp twice you get a char
// If you dereference pp once you get a char *, a pointer to char
// Assume pp contains garbage right now; we have no idea where it might point
pp = &p; // pp now points to the storage of p (which is a pointer pointing to c)
*p = 'a'; // dereference p to find the char to assign (variable c)
*(*pp) = 'a'; // dereference pp to find p, dereference p in turn to find char to assign
**pp = 'a'; // parentheses not required, same as previous line
在C中,函数总是按值调用:复制函数的参数。因此,要从函数内部修改某些内容,您需要传递一个指针;指针被复制,但指针的值用于查找要修改的变量。
令人困惑的是,您的示例函数想要修改指针。因此,您声明它需要char **
,并在调用函数时获取指针的地址。