指针和访问内存c.小心

Dan*_*Dan 36 c pointers

还在学习更多C并且有点困惑.在我的引用中,我发现有关分配尚未初始化的指针的注意事项.他们继续举例说明.昨天从帮助我指点的人那里得到了很好的答案,这里:

优先级,括号,具有迭代数组函数的指针

在跟进时,我简要地询问了循环的最后一次迭代,并可能将指针指向一个不存在的位置(即因为我的引用警告它).所以我回去看了一下,发现了这个:

如果你有一个指针

int *pt;
Run Code Online (Sandbox Code Playgroud)

然后在不初始化的情况下使用它(即我认为这意味着没有声明*pt= &myVariable):

*pt = 606;
Run Code Online (Sandbox Code Playgroud)

你可能最终得到一个真正的糟糕的一天,取决于这个指针被分配给内存的位置.我遇到麻烦的部分是使用一串字符时这样的东西就可以了:

char *str = "Sometimes I feel like I'm going crazy.";
Run Code Online (Sandbox Code Playgroud)

引用所在的位置,"不要担心字符串在内存中的位置分配;它由编译器自动处理".所以没必要说初始化*str = &str[0];*str = str;.意思是,编译器是自动char str[n];在后台吗?

为什么处理方式不同?或者,我完全误解了吗?

dbu*_*ush 22

在这种情况下:

char *str = "Sometimes I feel like I'm going crazy.";
Run Code Online (Sandbox Code Playgroud)

您正在初始化str以包含给定字符串文字的地址.此时你实际上并没有解除引用任何东西.

这也没关系:

char *str;
str = "Sometimes I feel like I'm going crazy.";
Run Code Online (Sandbox Code Playgroud)

因为您正在分配str而不是实际解除引用它.

这是个问题:

int *pt;
*pt = 606;
Run Code Online (Sandbox Code Playgroud)

因为pt没有初始化然后它被解除引用.

您也不能出于同样的原因(加上类型不匹配):

*pt= &myVariable;
Run Code Online (Sandbox Code Playgroud)

但你可以这样做:

pt= &myVariable;
Run Code Online (Sandbox Code Playgroud)

之后你可以自由使用*pt.

  • 我把你所写的内容称为:`char*str ="有时我觉得我疯了.";`**不是=**`char*str;``*str ="有时候我觉得就像我疯了一样.";` (3认同)

Jos*_*ica 16

当你写作时sometype *p = something;,它相当于sometype *p; p = something;,而不是sometype *p; *p = something;.这意味着当你使用这样的字符串文字时,编译器会找出放置它的位置,然后将其地址放在那里.

该声明

char *str = "Sometimes I feel like I'm going crazy.";
Run Code Online (Sandbox Code Playgroud)

相当于

char *str;
str = "Sometimes I feel like I'm going crazy.";
Run Code Online (Sandbox Code Playgroud)


P__*_*J__ 11

简化字符串文字可以表示为:

const char literal[] = "Sometimes I feel like I'm going crazy.";
Run Code Online (Sandbox Code Playgroud)

所以表达

char *str = "Sometimes I feel like I'm going crazy.";
Run Code Online (Sandbox Code Playgroud)

在逻辑上等同于:

const char literal[] = "Sometimes I feel like I'm going crazy.";
const char *str = literal;
Run Code Online (Sandbox Code Playgroud)

当然文字没有名字.

但是你不能取消引用没有为实际对象分配内存的char指针.

/* Wrong */
char *c;
*c = 'a';
/* Wrong  - you assign the pointer with the integer value */ 
char *d = 'a';

/* Correct  */
char *d = malloc(1);
*d = 'a';

/* Correct */
char x
char *e = &x;
*e = 'b';
Run Code Online (Sandbox Code Playgroud)

最后一个例子:

/* Wrong - you assign the pointer with the integer value */
int *p = 666;

/* Wrong you dereference the pointer which references to the not allocated space */
int *r;
*r = 666;

/* Correct */
int *s = malloc(sizeof(*s));
*s = 666;

/* Correct */
int t;
int *u = &t;
*u = 666;
Run Code Online (Sandbox Code Playgroud)

最后一个 - 类似于字符串文字=复合文字:

/* Correct */
int *z = (int[]){666,567,234};
z[2] = 0;
*z = 5;

/* Correct */
int *z = (const int[]){666,567,234}; 
Run Code Online (Sandbox Code Playgroud)

  • 说`char *str =literal` 是“逻辑上等价的”是错误的……字符串文字(`"foo"`)通常被放置在只读内存中。即`char * s = "foo"` **不能**被编辑。另一方面,`char s[] = "foo"` 初始化堆栈** 上的字符串数据,使其可编辑。两件非常不同的事情。 (2认同)

J-L*_*J-L 5

提出这个例子的好工作.它很好地显示了声明指针(如char *text;)和指定指针(如)之间的区别text = "Hello, World!";.

当你写:

char *text = "Hello!";
Run Code Online (Sandbox Code Playgroud)

它基本上与说:

char *text;        /* Note the '*' before text */
text = "Hello!";   /* Note that there's no '*' on this line */
Run Code Online (Sandbox Code Playgroud)

(你知道,第一行也可以写成char* text;.)

那么为什么*二线上没有?因为text是类型char*,并且"你好!" 也是类型char*.这里没有分歧.

此外,就编译器而言,以下三行是相同的:

char *text = "Hello!";
char* text = "Hello!";
char * text = "Hello!";
Run Code Online (Sandbox Code Playgroud)

在之前或之后放置空间*没有区别.第二行可以说是更易于阅读,因为它驱动点回家的text是一个char*.(但要小心!如果你在一行上声明多个变量,这种风格会烧掉你!)

至于:

int *pt;
*pt = 606;   /* Unsafe! */
Run Code Online (Sandbox Code Playgroud)

你可能会说*pt是一个int,所以是606的,但它更准确的说,pt(没有*)是一个指针内存应该包含一个INT.而*pt(带有a *)引用内存中的intpt(没有*)指向.

而且由于pt从未初始化,使用*pt(分配或去引用)是不安全的.

现在,有关线条的有趣部分:

int *pt;
*pt = 606;   /* Unsafe! */
Run Code Online (Sandbox Code Playgroud)

是他们会编译(尽管可能有警告).那是因为编译器看作*pt是一个int,也是606一样int,所以没有分歧.但是,如上所述,指针pt不指向任何有效的内存,因此分配*pt可能会导致崩溃,或损坏数据,或引发世界末日等.

认识到这一点很重要*pt不是一个变量(尽管它经常被用来像一个). *pt只是指内存中包含地址的值pt.因此,是否*pt安全使用取决于是否pt包含有效的内存地址.如果pt未设置为有效内存,则使用*pt不安全.

所以现在你可能想知道:宣布什么pt是一个int*而不仅仅是一个int

这取决于具体情况,但在很多情况下,没有任何意义.

在使用C和C++进行编程时,我使用了建议:如果您可以在不将其作为指针的情况下声明变量,那么您可能不应该将其声明为指针.

程序员经常在不需要时使用指针.当时,他们没有想到任何其他方式.根据我的经验,当它引起他们注意不使用指针时,他们会经常说不可能不使用指针.当我以其他方式证明它们时,它们通常会回溯并说它们的代码(使用指针)比不使用指针的代码更有效.

(但对于所有程序员来说都不是这样.有些人会认识到用非指针替换指针的吸引力和简单性,并乐意改变他们的代码.)

当然,我无法代表所有情况,但是现在C编译器通常足够聪明,可以编译指针代码和非指针代码,在效率方面几乎完全相同.不仅如此,根据具体情况,非指针代码通常比使用指针的代码更有效.

  • 一个挑剔:`int*pt;*pt = 606;`具有未定义的行为,因此允许编译器拒绝编译它. (2认同)

Ser*_*rge 5

您的示例中混合了4个概念:

  1. 声明一个指针. int *p;或者char *str;是指针的声明
  2. 在声明处初始化指针. char *str = "some string";声明指针初始化它.
  3. 为指针赋值. str = "other string";指针赋值.类似地,p = (int*)606;将606的值赋给指针.但是,在第一种情况下,该值是合法的,并指向字符串在静态内存中的位置.在第二种情况下,您可以为其分配任意地址p.它可能是也可能不是合法地址.所以,p = &myint;或者p = malloc(sizeof(int));是更好的选择.
  4. 为指针指向的值赋值. *p = 606;将值赋给'pointee'.现在它取决于指针'p'的值是否合法.如果你没有初始化指针,那就是非法的(除非你很幸运:-)).


归档时间:

查看次数:

1926 次

最近记录:

6 年,6 月 前