c - 为什么我们将字符串存储在字符指针中,例如 fopen(); 中?

标签 c

我试图更深入地研究以下行:

char* filename="file.txt";    

当我们使用 fopen() 时我会这样做;

我的问题是:

  1. filename应该保存一个字符的地址(在 core2Duo 中为 36 位)。为什么我们要在其中放入“字符串”?

  2. 为什么编译器不会生成错误,因为您可能存储了一个永远不存在的地址?

最佳答案

filename is supposed to hold an address of a character (36 bits in core2Duo), why we are putting a 'string' in it ?

表达式char* filename="file.txt";是一个有效的表达式。原因是 C 中字符串文字的类型是 char[N]很容易衰变成 char* ,和char[N]char*是兼容的。因此,您可以将字符串地址分配给 char*指针变量就像您在此表达式中所做的那样。

Why the compiler would not generate an error since you might be storing an address which can never exist?

请阅读以下三点:

  • 它是一个有效的地址:

否,在表达式 char* filename="file.txt"; 中, filename被分配了一个有效的地址。从概念上讲,它类似于(假设地址以 21 开头):

filename   21  22   23  24  25  26  27  28  29
+---+     +------------------------------------+
|21 |---> |'f'|'i'|'l'|'e'|'.'|'t'|'x'|'t'|'\0'|
+---+     +------------------------------------+

filename pointing to string, a valid address.

并且它不会给出任何错误或警告:尝试下面的代码示例:

示例 1:

#include<stdio.h>
int main(int argc, char **argv){
    char* filename = "filename.txt";
    printf("%s", filename);
    return 0;
}

编译:

:~$ gcc y.c  -Wall -pedantic 
~$ ./a.out 
filename.txt

没有错误和警告,编译和执行完美。

关于您对我的回答的评论:

C 中的字符串数据结构有点复杂,然后是简单的值变量,例如 int , char , float .

对于基本数据类型:

int i = 5;  You are assigning value 5, to variable i
char c = 'A'; You are assigning value 'A' to char variable c. 
float f = 5.5f; You are assigning value 5.5f to float variable f.

但是对于字符串,当你这样做时:

  char* filename = "filename.txt"; 

那么你实际上是在分配字符串"filename.txt"的地址到 char* 指针变量 filename

如果你这样做:

  char filename[] = "filename.txt"; 
      //        ^ notice [] in declaration 

然后您将分配字符串“filename.txt”;到一个字符数组 filename[] ,这里filename类型是char[]

要了解两个声明中的更多尊重,请阅读:What does sizeof(&arr) return?

字符串文字可能会在您使用它的上下文中为您提供值或地址依赖性。例如尝试:printf(" address: %p, value: %s", "Hello", "Hello");

  • 编译器不验证地址,而是检查语法。

编译器不负责验证地址是否合法。编译器移植代码并检查语法错误(例如不可编译的类型不匹配)。假设如果您将假地址分配给指针,它不会给您警告(如果您正确键入强制转换地址)。考虑下面的例子:

示例 2:

#include<stdio.h>
int main(int argc, char **argv){
    char* filename = "filename.txt";
    char* ptr = (char*)0x020202;
    printf("%s %s\n", filename, ptr);
    return 0;
}

编译:

$ gcc y.c  -Wall -pedantic 

并且它不会产生任何错误或警告。因为从语法上来说,一切都很好并且有效。
(而 ptr 分配了一个可能不存在的虚假地址)。

  • 无效地址会导致运行时出现未定义的行为

好吧,编译 example-2 代码即可,其中 ptr被分配了一个假地址,即使使用坚持检查标志选项,编译器也不会生成任何错误/警告:-Wall -pedantic

但是执行这段代码是错误的。它尝试访问分配给 ptr 的内存地址在 printf 语句中,程序将表现异常(在不同的执行实例中)。在 C -语言标准称为:Undefined behavior

当您执行此代码时,操作系统(而不是编译器)检测到进程对内存权限的侵犯 - 对有效内存的无效访问给出:SIGSEGV 对无效地址的访问给出:SIGBUS。这可能会导致进程终止/崩溃并出现一些段错误和 coredump

要了解并了解访问非法内存时会发生什么,请阅读:strcat() implementation works but causes a core dump at the end .

关于c - 为什么我们将字符串存储在字符指针中,例如 fopen(); 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17627394/

相关文章:

c - 函数总是返回无意义的值

c - 这段代码不会造成内存泄漏吗?

c - MIPS:将 C 代码转换为 MIPS 函数调用和返回中的问题

c - 为什么 gcc 使用 -I 选项找不到包含路径?

使用 MPI_Type_create_subarray 发送时可以转置数组吗?

c++ - #define 中定义的最大值无法正常工作

c - 对 fork 系统调用行为的一些解释?

c - C如何执行括号?

c - 在C中输出两个二进制字符串及其十进制值相加的结果

c - 添加mysql客户端库出现段错误