我正在尝试比较char array (string)
中C
的不同声明。
我有两点主要比较这些组合(而不是一次又一次地写我命名):
char *a, *b;
a=b //we are doing this
char *a;
*a='x' //we are doing this
以下是具有不同组合的代码。我有大约10个疑点。我必须一起问他们,因为他们都有某种联系。
代码中解释了每个疑问。此外,还添加了错误消息。
因为你可能不知道每个问题的答案。所以,我在代码中标记了不同的部分。并且还给出了每个问题的编号 如果你知道任何问题的答案请用适当的索引回答。
在代码中,我也提出了自己的观察和结论,这可能是错误的。所以我用结论:标记标记了它们。如果您发现任何结论错误,请分享/回答。
代码:
#include <stdio.h>
int main() {
char *p = "Something";//I cant change the data
char q[] = "Wierd"; // I can change to what q points to
// I. ______________________ char*p ___________________________
printf("\nI. ______________________ char*p ___________________________ \n\n");
printf("%s %s\n",p, q);
//*p = 'a';// got segmentation fault as I cant change the Value
p = q;//This is possible because I change the Point
//Now the type p is a char pointer which can't change Value (because I declared it like this) but can change the Point
//and it is now pointing to a memory which is of type a char array.I can change its Value but cant change its Point
//This means there are two different things on both sides of the assignment but gcc doesnot give any error (i.e. it is acceptable)
//That is for Pointer assignment restriction rules of the type of left side var was used and for Value change
//rules of the type of right side var was used
// (1)Why?
*p = 'x';
printf("%s %s\n",p, q);
//Again try to make Something Wierd
p = "Something";
q[0] = 'W';
// II. ______________________ char q[] ___________________________
printf("\nII. ______________________ char q[] ___________________________ \n\n");
printf("%s %s\n",p, q);
//q = p;// This is not possible because for q I cant change Point.
// This is the error comes
//error: incompatible types when assigning to type ‘char[6]’ from type ‘char *’
*q = 'x';//This works fine as this is possible to change Value for q
printf("%s %s\n",p, q);
//Again try to make Something Wierd
p = "Something";
q[0] = 'W';
//____________________________________________________________________/
const char * r = "What";//I cant change the data to what a points to (basic def and const act on same)
char const * s = "Point";//I cant change the data to what a points to (basic def and const act on same)
char * const t = "Pointers";//I cant change the data to what a points to because of basic def and const make c a const that now c can only point to single entity.
const char u[] = "Are";//I cant change the data to what a points to because of const and I can't change to what d points because of basic def of [].
char const v[] = "Trying";//I cant change the data to what a points to because of const and I can't change to what d points because of basic def of [].
//char w const [] = "To make";//This is not possible
//___________________________________________________________________/
// III. ______________________ const char * r ___________________________
printf("\nIII. ______________________ const char * r ___________________________ \n\n");
printf("%s\n",r);
//*r = 'x'; // This is not possible
//Error comes is:
//error: assignment of read-only location ‘*r’
//now the behaviour of r is same as p but instead of getting segmentation fault I got an error at compile time.
//Also the restriction const put here is same as of restriction present with p except(error checking).
//Conclusion : This means writing const here makes no difference in terms of Value and Point. What it was before is the same now.
r = s;
printf("%s %s\n",r ,s);
//*r = 'x';
r = t;
printf("%s %s\n",r ,t);
//*r = 'x';
r = u;
printf("%s %s\n",r ,u);
//*r = 'x';
r=v;
printf("%s %s\n",r ,v);
//*r = 'x';
r=p;
printf("%s %s\n",r ,p);
//*r = 'x';
r=q;
printf("%s %s\n",r ,q);
//*r = 'x';
//For above four cases
//Everything works for Point assignment
//Nothing Works for Value change (Everytime assignment to read-only location error, no segmentation fault)
//Everything Works for Point assignment - This means everything works for the
//rules of the type of varible on the left side for Pointer assignment. (Even for r=u,r=v, r=q).
//(2) WHY this is happening.(Actualy answer related to WHY(1))
//Nothing Works for Value change
//Now this is absurd. On the first look it seems that as the things happen at the time of p=q, here
//for r=u, r=v, r=q same things should had happened. But on the closer inspection you can get that u,v
//have restrictions on Value change because of const.
//But (3)Why no Value change is happening for r=q ?
// (4) Why fot r=p, r=q getting error due to const. not due to segmentation fault.
//Resetting Wierdness
r = "What";
// IV. ______________________ char const * s ___________________________
printf("\nIV. ______________________ char const * s ___________________________ \n\n");
printf("%s\n",s);
//*s = 'x'; // This is not possible
//Error comes is
//error: assignment of read-only location ‘*s’
//Behavious of s is exactly same as r
//Conclusion: Writing const after or before char makes no difference.
s = r;
printf("%s %s\n",s ,s);
//*s = 'x';
s = t;
printf("%s %s\n",s ,t);
//*s = 'x';
s = u;
printf("%s %s\n",s ,u);
//*s = 'x';
s=v;
printf("%s %s\n",s ,v);
//*s = 'x';
s=p;
printf("%s %s\n",s ,p);
//*s = 'x';
s=q;
printf("%s %s\n",s ,q);
//*s = 'x';
//For above four cases
//Everything happens same as with r.
//Resetting Wierdness
s = "Point";
// V. ______________________ char * const t ___________________________
printf("\nV. ______________________ char * const t ___________________________ \n\n");
printf("%s\n",t);
//*t = 'x';//This is not possible
//Error is
//Segmentation-fault
//This means that on Value change the error comes not due to const. It comes for the same reason of p.
//t = r;
printf("%s %s\n",t ,r);
//*t = 'x';
//t = s;
printf("%s %s\n",t ,s);
//*t = 'x';
//t = u;
printf("%s %s\n",t ,u);
//*t = 'x';
//t=v;
printf("%s %s\n",t ,v);
//*t = 'x';
//t=p;
printf("%s %s\n",t ,p);
//*t = 'x';
//t=q;
printf("%s %s\n",t ,q);
//*t = 'x';
//For above four cases
//Nothing Works for Point Assignment
//Nothing works for value change (Everytime segmentation fault, assignment to read-only location error)
//Nothing Works for Point Assignment
//This is understandable
//Nothing works for value change
// (5) Why this is happening. Why left hand side is always given precedence. Why this isn't happening p=q,
//because for value change t=q and p=q are exctly same both pn left side and right side of the assignment.
//Resetting Wierdness
//t = "Pointers"; //No need
// VI. ______________________ const char u[] ___________________________
printf("\nVI. ______________________ const char u[] ___________________________ \n\n");
printf("%s\n",u);
//*u = 'x';//This is not possible
//Error Comes is
//error: assignment of read-only location ‘*(const char *)&u’
//This error comes because of const.
//Conclusion: [] gives the Point restriction and const gives the Value Restriction
//u = r;
printf("%s %s\n",u ,r);
//*u = 'x';
//u = s;
printf("%s %s\n",u ,s);
//*u = 'x';
//u = t;
printf("%s %s\n",u ,t);
//*u = 'x';
//u=v;
printf("%s %s\n",u ,v);
//*u = 'x';
//u=p;
printf("%s %s\n",u ,p);
//*u = 'x';
//u=q;
printf("%s %s\n",u ,q);
//*u = 'x';
//For above four cases
//Nothing Works for Point Assignment
//Nothing works for value change (Everytime assignment to read-only location error, no segmentation fault)
//Nothing Works for Point Assignment
//Error Comes for each is:
//warning: assignment of read-only location ‘u’ [enabled by default]
//error: incompatible types when assigning to type ‘const char[4]’ from type ‘const char *’
//Left side rules are given precedence. (6)Why? (If already not solved in above answers)
//Nothing works for value change
//Left side rules are given precedence. (7)Why? (If already not solved in above answers)
//Resetting Wierdness
//u = "Are";
// VII. ______________________ char const v[] ___________________________
printf("\nVII. ______________________ char const v[] ___________________________ \n\n");
printf("%s\n",v);
//*v = 'x';//This is not possible
//Error Comes is
//error: assignment of read-only location ‘*(const char *)&v’
//This error comes because of const.
//Conclusion: Writing const after or before char makes no difference.
//v = r;
printf("%s %s\n",v ,r);
//*v = 'x';
//v = s;
printf("%s %s\n",v ,s);
//*v = 'x';
//v = t;
printf("%s %s\n",v ,t);
//*v = 'x';
//v=u;
printf("%s %s\n",v ,u);
//*v = 'x';
//v=p;
printf("%s %s\n",v ,p);
//*v = 'x';
//v=q;
printf("%s %s\n",v ,q);
//*v = 'x';
//For above four cases
//Everything works as same with u.
//Resetting Wierdness
//v = "Trying";
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// (8) WHY `const char * a;` and `char const * a` works same?????
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//---------------Now doing more Possible combinations with p and q------------------
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// VIII. ~~~~~~~~~~~~~~~~~~~~~~~~~~~ char *p ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
printf("\nVIII. ~~~~~~~~~~~~~~~~~~~~~~~~~~~ char *p ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n\n");
//p = r;
printf("%s %s\n",p ,r);
//*p = 'x';
//p = s;
printf("%s %s\n",p ,s);
//*p = 'x';
//p = t;
printf("%s %s\n",p ,t);
//*p = 'x';
//p=u;
printf("%s %s\n",p ,u);
//*p = 'x';
//p=v;
printf("%s %s\n",p ,v);
//*p = 'x';
//For above four cases
//Point Assignment
//Warning for p=r, p=s is
//warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]
//Conclusion:Kind of understandable.
// NO Warning for p=t
//For left side type I can do Point assignment and for Right Side I can,t do.
// Left side rules are given precedence. (9)Why? (If already not solved in above answers)
//Warning for p=u, p=v is
//warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]
//For left side type I can do Point assignment and for Right Side I can,t do.
// Left side rules are given precedence. (10)Why? (If already not solved in above answers)
//Value Change
//Segmentation fault for everything .
//Conclusion: Understndable if assume left hand side are given precedence except for p = q (showed in I.)
//Resetting Wierdness
p = "Something";
// IX. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ char q[] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
printf("\nIX. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ char q[] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n\n");
//q = r;
printf("%s %s\n",q ,r);
*q = 'x';
//q = s;
printf("%s %s\n",q ,s);
*q = 'x';
//q = t;
printf("%s %s\n",q ,t);
*q = 'x';
//q=u;
printf("%s %s\n",q ,u);
*q = 'x';
//q=v;
printf("%s %s\n",q ,v);
*q = 'x';
//For above four cases
//Point Assignment
//Error for each is:
//error: incompatible types when assigning to type ‘char[6]’ from type ‘const char *’
//Conclusion: Understandable, if assume L.H.S. is given precedence except for p = q (showed in I.)
//Value Change
//Possible for each
//Conclusion: Understndable if assume left hand side are given precedence except for p = q (showed in I.)
//Resetting Wierdness
*q = 'W'; //No need
return 0;
}
Daniel的答案已经完成。但更简单的两个疑问是:
1)对于p
,case对象是一个字符串文字(一个不可修改),即它是右手边对象的属性,而对于RHS上的q我有相同的东西,但现在它表现不同。为什么这种不一致的设计。
2)对于p,如果我修改字符串文字,则行为未定义,即有时它被修改,有时不修改。为什么这样的设计。实际上,对于out of bound数组访问,这是可以理解的,因为你访问之前没有分配的内存,有时你没有权限访问那段内存所以,分段错误。但有时为什么我可以修改字符串文字。为什么这样。这背后的原因是什么。
答案 0 :(得分:5)
char *p = "Something";//I cant change the data
char q[] = "Wierd"; // I can change to what q points to
p
是char*
指向10个char
的数组的第一个元素(不要忘记0终结符),不允许修改(尝试修改字符串文字是未定义的行为;大多数实现将字符串文字存储在只读内存中,然后这样的尝试会导致段错误,但是修改字符串文字的尝试可能会修改数组而不是崩溃)。您可以自由更改p
,当它更改为指向可修改的对象时,您可以通过*p
修改该对象。
q
是一个包含六个char
s(再次为0-terminator)的数组。您无法为q
分配任何值,但您可以修改数组的内容。
p = q;
让p
指向数组q
的第一个元素。在该上下文中,q
被隐式转换为指向其第一个元素&q[0]
的指针,因此p = &q[0];
实际发生的是p
。现在*p = 'x';
指向可修改的对象,因此
char
允许并更改q
中的第一个p = "Something";
q[0] = 'W';
。
p
让char
再次指向您不允许修改的q
数组的第一个元素,并将p
的第一个元素更改回它之前的元素已经通过q
进行了修改,这一次是使用//q = p;// This is not possible because for q I cant change Point.
// This is the error comes
//error: incompatible types when assigning to type ‘char[6]’ from type ‘char *’
。
char hello[] = "Hello"; char world[] = "World";
错误消息有点误导,您无法分配数组。即使使用hello = world; produces the same error (since in that context,
,尽管两个数组都具有相同的类型,但您无法分配,*q = 'x';//This works fine as this is possible to change Value for q
world`将转换为指向其第一个元素的指针,但错误消息并没有错误。
*q
是的,q[0]
与const char * r = "What";//I cant change the data to what a points to (basic def and const act on same)
char const * s = "Point";//I cant change the data to what a points to (basic def and const act on same)
相同,因此在许多情况下你可以使用像指针这样的数组(反之亦然)。但总的来说,数组和指针是不同类型的东西。
const char *
char const *
和char
的意思完全相同,指向不可修改的char * const t = "Pointers";//I cant change the data to what a points to because of basic def and const make c a const that now c can only point to single entity.
(通常是数组中的第一个)。
t
t
是一个常量指针,您无法更改指向的位置,但根据类型,您可以修改它指向的对象。但是,在这种情况下,char
指向字符串文字的第一个t
,因此不允许您将对象t
更改为(但这不是const char u[] = "Are";//I cant change the data to what a points to because of const and I can't change to what d points because of basic def of [].
char const v[] = "Trying";//I cant change the data to what a points to because of const and I can't change to what d points because of basic def of [].
类型的后果。
u
同样,两者的含义相同,v
和const char
是//char w const [] = "To make";//This is not possible
的数组,由于它们的类型,不允许更改这些数组的内容。
//*r = 'x'; // This is not possible
//Error comes is:
//error: assignment of read-only location ‘*r’
是的,这是无效的语法,你不能在数组名和括号之间有一个类型限定符。
r
r
的类型禁止通过//now the behaviour of r is same as p but instead of getting segmentation fault I got an error at compile time.
//Also the restriction const put here is same as of restriction present with p except(error checking).
//Conclusion : This means writing const here makes no difference in terms of Value and Point. What it was before is the same now.
更改指向对象(但通过其他指针更改它可能是合法的。)
r
结论是错误的,如果您将q
更改为指向可修改的对象,例如r
,您仍然无法通过p
更改它,该类型禁止它。但您可以通过*r = 'x';
修改它。对于字符串文字的指针,通常不同之处在于*p = 'x';
是编译失败而p
是分段错误,但对于一般情况,通过p
进行修改是有效的(通常是& #34;工作&#34;如果const char arr[10]
指向r = s;
的元素,但这又是未定义的行为,它通常不会导致崩溃,与字符串文字的对比)。
r
好的,没问题。您可以更改指向的r
对象,即您更改r
,但不要更改指向的对象r = t;
。
t
也没问题。如果t
指向可修改的对象,则可以通过r
修改对象,但不能通过t
修改对象。但是当t
指向一个字符串文字时,你不能通过任何一个修改对象//Everything Works for Point assignment - This means everything works for the
//rules of the type of varible on the left side for Pointer assignment. (Even for r=u,r=v, r=q).
//(2) WHY this is happening.(Actualy answer related to WHY(1))
指向,但同样,一个是编译错误,另一个可能是段错误。
const
将const char *r;
读为&#34;只读&#34;。拥有char
意味着您有一个指向const
的指针,编译器将不允许您使用它来修改指向对象,您只能使用它来读取对象。它指向的对象是否被声明为const
并不重要,r
声明中的r
仅限制//Nothing Works for Value change
//Now this is absurd. On the first look it seems that as the things happen at the time of p=q, here
//for r=u, r=v, r=q same things should had happened. But on the closer inspection you can get that u,v
//have restrictions on Value change because of const.
//But (3)Why no Value change is happening for r=q ?
// (4) Why fot r=p, r=q getting error due to const. not due to segmentation fault.
可以使用的内容for,而不是通过其他指针对指向对象可以做什么。
*r = 'x';
我不确定我理解你的&#34;为什么(3)&#34;,但如果我理解正确,你希望r = q;
能够在r
后工作,从那以后const
指向可修改的对象。然后答案就是我上面写的,r
声明中的r
限定符限制了您可以通过const
执行的操作,它独立于r
指向对象的状态。这也回答了(4),*r = whatever;
的类型禁止作业//Conclusion: Writing const after or before char makes no difference.
。
const
然而,*
之前或之后const char *r;
是否出现,会有所不同。 char * const x = q;
声明一个不能用于修改指针的指针,const char * const y = q;
声明一个指向同一位置的指针;您可以使用它来修改指向对象(如果允许的话)。并且//*t = 'x';//This is not possible
//Error is
//Segmentation-fault
//This means that on Value change the error comes not due to const. It comes for the same reason of p.
声明了一个无法更改的只读指针。
*t = 'x';
您无法t
因为t
碰巧指向字符串文字。如果您初始化q
以指向//t = r;
,则可以允许这样做。
t
由于您宣布t
无法修改,因此无法更改,因此您无法更改指向的位置。
//(5)为什么会这样。为什么左手边始终优先。为什么这不会发生p = q, //因为对于值的改变,t = q和p = q在赋值的左侧和右侧都是非常相同的。
我不确定问题是什么。您声明const
为t
,这意味着您无法分配到const int i = 100;
。对于i = 120;
,它将是相同的,您将不被允许在您的程序中编写//*u = 'x';//This is not possible
//Error Comes is
//error: assignment of read-only location ‘*(const char *)&u’
//This error comes because of const.
//Conclusion: [] gives the Point restriction and const gives the Value Restriction
。
//For above four cases
//Point Assignment
//Warning for p=r, p=s is
//warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]
//Conclusion:Kind of understandable.
右。
const char*
不仅仅是&#34;有点&#34;。您正在为char*
分配char *p
。指向的对象可能是不可修改的,但尝试通过p
修改它是正式有效的,如果指向的对象是可修改的,使用const
修改它甚至是合法的。但是,如果指向的对象不可修改,则使用p
限定符声明字符串文字,尝试通过const
修改它是未定义的行为。因此丢弃// NO Warning for p=t
//For left side type I can do Point assignment and for Right Side I can,t do.
// Left side rules are given precedence. (9)Why? (If already not solved in above answers)
限定符是一件危险的事情,编译器就会发出警告。然而,它可能是完全合法的,所以它只是一个警告,而不是一个错误。您可以通过使用显式强制转换告诉编译器您知道自己在做什么(无论您是否这样做)。
char * const
您正在为char*
分配t
,此处没有任何遗失。分配const
的值不会更改它,*
之后的t
仅表示您无法更改//Warning for p=u, p=v is
//warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]
//For left side type I can do Point assignment and for Right Side I can,t do.
// Left side rules are given precedence. (10)Why? (If already not solved in above answers)
指向的地址。
p = r;
与//Value Change
//Segmentation fault for everything .
//Conclusion: Understndable if assume left hand side are given precedence except for p = q (showed in I.)
相同。
char[]
分段错误只是因为你让指针指向字符串文字。如果您指向*ptr = 'x';
,则分配const char
将工作或不编译,具体取决于指针是声明指向char
还是仅指向const char
。如果你引入了几个const char*
数组,那么赋值当然也不会为char*
编译,但它会为const
编译(带有关于丢弃char *p = "Something";
的警告运行程序调用未定义的行为(它可能不会崩溃并修改数组内容,但任何事情都可能发生)。
关于其他问题:
1)对于p case对象是一个字符串文字(一个可以修改),即它是右手边对象的属性,而对于RHS上的q,我有相同的东西,但现在它表现不同。为什么这种不一致的设计。
我不确定你的想法有什么不同。在char *p = q;
和p
中,指向对象的属性确定char[N]
的用途是有效的。两者中的任何一个都不能通过其类型进行修改(对于某些N
都是char *p;
),但字符串文字是不可修改的,作为标准定义的特殊情况。
声明p
(此处未进行初始化,但有一个不存在或不重要)将char q[] = "Wierd";
声明为可用于修改指向的指针。但是,这种修改指向对象的尝试是否有效,取决于指向对象的属性。
q
将字符串文字的内容复制到数组q
(包括0终结符),因此p
初始化为字符串文字的可修改副本。让char
指向数组q
中的某些p
会使p
指向可修改的对象,并且此类修改有效。
让const
指向const char c = 'C'; p = &c;
限定对象,p
比较危险,因为*p = 'x';
的类型不会阻止p
从编译 - 毕竟,编译器一般不知道在那一点const
是指向const char*
限定对象,还是可修改对象(赋值可能来自{{} 1}}被指向一个可修改的对象),或根本没有有效的位置。
因此赋值p = &c;
会导致编译器发出警告(至少编译器的警告级别足够高,但在gcc和clang中,例如,默认情况下启用),甚至中止带错误的编译(如果传递-pedantic-errors
标志,则执行gcc和clang)。语言标准禁止该分配而不明确地将const char *
&c
强制转换为char*
,但只需要诊断,因此编译器可以自由地将其作为警告或错误。
如果你只使用指针来指向一个不可修改的对象时从指向对象读取,这是一个合法的用途,所以这个任务不会被无条件禁止(与演员,它&& #39;标准允许并且甚至不会引起警告,因为演员告诉编译器&#34;我知道我在做什么&#34;)。
因此*p = 'x';
是否有效,只能由指向对象的属性决定。如果指向的对象是不可修改的(或者如果p
根本没有指向有效对象),则行为是未定义的。未定义的行为如何表现为未定义,但在这种情况下,通常要么是分段错误(如果对象驻留在写保护的内存区域中),要么修改指向对象,就像它被允许一样(如果只有该类型使对象不可修改,并且实现没有采取额外措施来识别这种无效写入)。在字符串文字的情况下,由于历史原因,键入char[N]
,通常它们存储在程序的.rodata
(只读数据)部分,并尝试写入由操作系统检测到并导致段错误。
2)对于p,如果我修改字符串文字,则行为未定义,即有时它被修改,有时不修改。为什么这样的设计。实际上,对于越界数组访问,这是可以理解的,因为您访问之前尚未分配的内存,有时您无权访问该内存,因此,分段错误。但有时为什么我可以修改字符串文字。为什么这样。这背后的原因是什么。
语用学
定义语言的委员会并不想将实施者与实施者联系起来。手中。程序员有义务避免未定义的行为,如果他没有,则无论发生什么事情都会发生。
从历史上看,据我所知,有些实现将字符串文字存储在只读存储器中,而实现的则不存在。当语言标准化(创建后近20年,行为多样化)时,主要是对现有常见做法的记录。由于编译器,库或硬件的差异,行为差异很大,因此未定义或实现定义,以允许尽可能多的平台上的符合实现。因此,一些实现允许修改字符串文字,其他实现没有,委员会决定通过使行为未定义来给程序员带来负担。