1

我正在尝试比较char array (string)in 的不同声明C

我主要比较了这些组合有两点(而不是一次又一次地写我命名它们):

  1. 点更改或点分配:我们只是更改指针指向的内容。
    char *a, *b;
    a=b //we are doing this
  2. 值更改:我们正在更改指针指向的数据。
    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;
}

丹尼尔的答案是完整的。但是还有两个更简单的疑问:
1)对于pcase 对象是一个字符串文字(无法修改),即它是右侧对象的属性,而对于 RHS 上的 q 我有相同的东西,但现在它的行为不同. 为什么会有这种不一致的设计。
2) 对于 p 如果我修改字符串文字,行为是未定义的,即有时它被修改,有时不被修改。再说为什么这样的设计。实际上,对于越界数组访问,这是可以理解的,因为您访问了以前未分配的内存,有时您无权访问那块内存,因此,分段错误。但是为什么有时我可以修改字符串文字。为什么这样。这背后的原因是什么。

4

1 回答 1

5
char *p = "Something";//I cant change the data
char q[] = "Wierd"; // I can change to what q points to

pchar*指向不允许修改的十个数组的第一个元素char(不要忘记 0 终止符)(尝试修改字符串文字是未定义的行为;大多数实现以只读方式存储字符串文字内存,那么这种尝试会导致段错误,但尝试修改字符串文字可能会修改数组而不是崩溃)。您可以p自由更改,当更改为指向可修改对象时,您可以通过*p.

q是一个由六个 s 组成的数组char(同样是 0 终止符)。您不能为 分配任何值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,world` 被转换为指向其第一个元素的指针,但错误消息并没有错)。

*q = 'x';//This works fine as this is possible to change Value for q

对,*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's 类型的结果)。

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';分段错误,但对于一般情况,修改 through是有效的(如果指向 a 的元素,p通常甚至“有效” ,但这又是未定义的行为,它通常不会导致崩溃,与字符串文字相反)。pconst 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;方法意味着你有一个指针char,编译器不允许你用来修改指向的对象,你只能用它来读取对象。它指向的对象是否被声明为const无关紧要,constinr的声明只限制了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.

我不确定我是否理解您的“Why(3)”,但如果我理解正确,您希望*r = 'x';在 之后工作r = q;,因为r它指向一个可修改的对象。那么答案就是我上面写的, 's 声明const中的限定符r限制了你可以通过 做什么r,它const与指向对象的状态无关。这也回答了(4),r禁止分配的类型*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不可修改,您无法更改它指向的位置。

// (5) 为什么会这样。为什么总是优先考虑左侧。为什么这不会发生 p=q, //因为对于值更改 t=q 和 p=q 在赋值的 pn 左侧和右侧都完全相同。

我不确定问题是什么。您声明tconst,这意味着您不能分配给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.

不仅“有点”。您正在将 a 分配const char*给 a 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)

您将 a 分配char * const给 a 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限定符的警告),并且运行程序会调用未定义的行为(它可能不会崩溃并修改数组内容,但任何事情都可能发生)。


关于附加问题:

1)对于 p case object 是一个字符串文字(不能修改),即它是右侧 object 的属性,而对于 RHS 上的 q 我有同样的东西,但现在它的行为不同。为什么会有这种不一致的设计。

我不确定你认为有什么不同。在char *p = "Something";char *p = q;中,指向对象的属性决定了哪些使用p是有效的。两者都不是不可修改的类型(两者都是char[N]for some N),但作为标准定义的特殊情况,字符串文字是不可修改的。

声明char *p;(此处没有初始化,但存在与否无关紧要)声明p为一个指针,您可以使用它来修改它所指向的内容。但是这种修改指向对象的尝试是否有效,取决于指向对象的属性。

char q[] = "Wierd";

将字符串文字的内容复制到数组q(包括 0 终止符),因此使用字符串文字的可修改副本q进行初始化。让指向数组中的某个点指向一个可修改的对象,这样的修改是有效的。pcharqp

比如说,p指向一个const合格的对象const char c = 'C'; p = &c;是很危险的,因为 of 的类型p不会阻止*p = 'x';编译——毕竟,编译器通常不知道此时是p指向一个const合格的对象,还是一个可修改的对象 (分配可能来自const char*指向可修改对象的 a),或者根本没有有效位置。

因此,赋值p = &c;会导致编译器发出警告(至少编译器的警告级别足够高,但在 gcc 和 clang 中,它默认启用),甚至会因错误而中止编译(gcc 和 clang如果您通过-pedantic-errors标志,请执行此操作)。语言标准禁止在没有明确地将const char *that &cis 强制转换为 a的情况下进行分配char*,但只需要诊断,因此编译器可以自由地将其设为警告或错误。

如果您只使用指针从指向对象中读取,而它指向一个不可修改的对象,那是合法的使用,所以分配不是无条件禁止的(使用强制转换,它是允许的标准和甚至不会引起警告,因为演员表告诉编译器“我知道我在做什么”)。

所以是否*p = 'x';有效,只能由指向对象的属性来判断。如果指向的对象是不可修改的(或者p根本没有指向有效的对象),则行为是未定义的。未定义的行为如何表现自己是未定义的,但是在这种情况下,通常要么是分段错误(如果对象位于写保护的内存区域中),要么指向的对象将被修改,就好像它被允许一样(如果只有类型使对象不可修改,并且实现不采取额外措施来识别此类无效写入)。在字符串文字的情况下,由于历史原因 - type char[N],它们通常存储在.rodata程序的(只读数据)部分,并且尝试写入该部分会被操作系统检测到并导致段错误。

2) 对于 p 如果我修改字符串文字,行为是未定义的,即有时它被修改,有时不被修改。再说为什么这样的设计。实际上,对于越界数组访问,这是可以理解的,因为您访问了以前未分配的内存,有时您无权访问那块内存,因此,分段错误。但是为什么有时我可以修改字符串文字。为什么这样。这背后的原因是什么。

实用主义。

定义语言的委员会不喜欢束缚实现者的手脚。程序员有义务避免未定义的行为,如果他不这样做,无论发生什么。

据我所知,从历史上看,有些实现将字符串文字存储在只读内存中,有些则没有。当语言被标准化时(在它创建将近 20 年后,行为有很多多样性),它主要是对现有常见做法的记录。由于编译器、库或硬件的差异,行为差异很大,因此未定义或实现定义,以允许在尽可能多的平台上实现一致的实现。因此,一些实现允许修改字符串文字,而另一些则不允许,委员会决定通过使行为未定义来将负担放在程序员身上。

于 2012-10-04T22:29:49.653 回答