关于C中的指针和字符串的问题[重复]

Posted

技术标签:

【中文标题】关于C中的指针和字符串的问题[重复]【英文标题】:Question about pointers and strings in C [duplicate] 【发布时间】:2011-05-21 18:34:27 【问题描述】:

可能重复:What is the difference between char s[] and char *s in C?Difference between char *str = “…” and char str[N] = “…”?

我有一些代码让我感到困惑。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])

  char* string1 = "this is a test";
  char string2[] = "this is a test";
  printf("%i, %i\n", sizeof(string1), sizeof(string2));
  system("PAUSE"); 
  return 0;

当它输出 string1 的大小时,它会打印 4,这是意料之中的,因为指针的大小是 4 个字节。但是当它打印string2时,它输出了15。我认为一个数组是一个指针,所以string2的大小应该和string1一样吧?那么为什么它会为同一种类型的数据(指针)打印出两种不同的大小呢?

【问题讨论】:

另外,sizeof 返回一个 size_t,与 %i 预期的 int 不同,它是未签名的。 size_t 变量的正确格式是 %zu Array 不是 pinter!记住这一点! 【参考方案1】:

数组不是指针。数组名称 decay 在某些情况下指向指向数组第一个元素的指针:当您将其传递给函数时,当您将其分配给指针时,等等。但除此之外,数组就是数组 - 它们存在于堆栈,具有可以通过sizeof 确定的编译时大小,以及所有其他好东西。

【讨论】:

【参考方案2】:

数组和指针是完全不同的动物。在大多数情况下,指定数组的 表达式 被视为指针。

首先,一点标准语言 (n1256):

6.3.2.1 左值、数组和函数指示符 ... 3 除非它是 sizeof 运算符或一元 &amp; 运算符的操作数,或者是用于初始化数组的字符串文字,否则类型为“type 的数组”的表达式是转换为类型为“pointer to type”的表达式,该表达式指向数组对象的初始元素并且不是左值。如果数组对象有寄存器存储类,则行为未定义。

字符串文字“这是一个测试”是一个 15 元素数组 char。在声明中


    char *string1 = "this is a test";
string1 被声明为指向char 的指针。根据上述语言,表达式“这是一个测试”的类型从char [15] 转换为char *,并将生成的指针值分配给string1。 在声明中

    char string2[] = "this is a test";

发生了一些不同的事情。更标准的语言:

6.7.8 初始化 ... 14 字符类型的数组可以由字符串字面量初始化,可选 括在大括号中。字符串文字的连续字符(包括 如果有空间或数组大小未知,则终止空字符)初始化数组的元素。 ... 22 如果一个未知大小的数组被初始化,它的大小由具有显式初始化器的最大索引元素确定。在其初始值设定项列表的末尾,数组不再具有不完整类型。

在这种情况下,string2 被声明为 char 的数组,它的大小是根据初始化器的长度计算的,并且字符串文字的 内容 被复制到大批。

这是一个假设的内存映射来说明正在发生的事情:

项目地址 0x00 0x01 0x02 0x03 ---- -------- ---- ---- ---- ---- 没有名字 0x08001230 't' 'h' 'i' 's' 0x08001234 ' ' '我' 's' ' ' 0x08001238 'a' ' ' 't' 'e' 0x0800123C 's' 't' 0 ... 字符串1 0x12340000 0x08 0x00 0x12 0x30 string2 0x12340004 't' 'h' 'i' 's' 0x12340008 ' ' '我' 's' ' ' 0x1234000C 'a' ' ' 't' 'e' 0x1234000F 's' 't' 0

字符串字面量具有静态范围;也就是说,它们的内存在程序启动时被留出并一直保留到程序终止。尝试修改字符串文字的内容会调用未定义的行为;底层平台可能允许也可能不允许,标准对编译器没有限制。最好表现得好像文字总是不可写的。

在我上面的内存映射中,字符串文字的地址与string1string2 的地址有所不同,以说明这一点。

无论如何,您可以看到string1,具有指针类型,包含字符串文字的地址string2 是一个数组类型,包含字符串文字的 contents 的副本。

由于string2 的大小在编译时是已知的,sizeof 返回数组中的大小(字节数)。

%i 转换说明符不适用于size_t 类型的表达式。如果您使用 C99,请使用 %zu。在 C89 中,您将使用 %lu 并将表达式转换为 unsigned long


C89: printf("%lu, %lu\n", (unsigned long) sizeof string1, (unsigned long) sizeof string2);
C99: printf("%zu, %zu\n", sizeof string1, sizeof string2);

注意sizeof是一个操作符,而不是一个函数调用;当操作数是一个表示 object 的表达式时,括号不是必需的(尽管它们不会造成伤害)。

【讨论】:

哇!谢谢你的详细解答!这真的帮助了我。【参考方案3】:

string1 是一个指针,而string2 是一个数组。

第二行类似于int a[] = 1, 2, 3;,它将a 定义为长度为3 的数组(通过初始化程序)。

string2 的大小为 15,因为初始化程序是 nul 终止的(所以 15 是字符串的长度 + 1)。

【讨论】:

【参考方案4】:

一个未知大小的数组等价于一个用于 sizeof 目的的指针。 static 大小的数组算作它自己的类型,用于 sizeof 目的,sizeof 报告数组所需的存储大小。即使string2 的分配没有明确的大小,C 编译器也会神奇地对待它,因为带引号的字符串直接初始化并将其转换为具有静态大小的数组。 (因为内存没有以任何其他方式分配,毕竟它无能为力。)出于sizeof 行为的目的,静态大小数组与指针(或动态数组!)的类型不同,因为那只是C 怎么样。

This 似乎是 sizeof 行为的一个不错的参考。

【讨论】:

【参考方案5】:

编译器知道test2 是一个数组,所以它会打印出分配给它的字节数(14 个字母加上空终止符)。请记住,sizeof 是一个编译器函数,因此它可以知道堆栈变量的大小。

【讨论】:

【参考方案6】:

数组不是指针。指针是指向内存位置的变量,而数组是分配的顺序内存的起点

【讨论】:

【参考方案7】:

因为

    string1 保存指针,其中指针具有连续的字符及其 不可变的。 string2 是您的字符所在的位置。

基本上,C 编译器以不同的方式解释这两个。这里解释得很漂亮http://c-faq.com/aryptr/aryptr2.html

【讨论】:

以上是关于关于C中的指针和字符串的问题[重复]的主要内容,如果未能解决你的问题,请参考以下文章

C程序:使用双指针更改函数中的字符串

任何可用于 C 中无符号字符指针行为的文档? [复制]

关于变量的C ++问题:在字符串中添加一个整数[重复]

C语言中关于指针的学习

C语言中关于指针的学习

在C中为结构中的单个字符分配内存[重复]