关于C中指针和字符串的问题 [英] Question about pointers and strings in C

查看:25
本文介绍了关于C中指针和字符串的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<块引用>

可能的重复:
char s有什么区别[] 和 C 中的字符 *s?
char *str = ..." 和 char str[N] = ..."?

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

#include #include int main(int argc, char *argv[]){char* string1 = "这是一个测试";char string2[] = "这是一个测试";printf("%i, %i\n", sizeof(string1), sizeof(string2));系统(暂停");返回0;}

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

解决方案

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

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

<块引用>6.3.2.1 左值、数组和函数指示符
...
3 除非它是 sizeof 运算符或一元 & 运算符的操作数,或者是用于初始化数组的字符串文字,否则类型为array oftype" 被转换为类型为 "pointer to type" 的表达式,它指向数组对象的初始元素,而不是左值.如果数组对象有寄存器存储类,则行为未定义.

字符串文字this is a test"是一个包含 15 个元素的 char 数组.在声明中

<代码>char *string1 = "这是一个测试";


string1 被声明为一个指向 char 的指针.按照上面的语言,表达式this is a test"的类型从char [15]转换为char *,并且结果指针值分配给 string1.


在声明中

<代码>char string2[] = "这是一个测试";


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

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

在这种情况下,string2 被声明为一个 char 数组,它的大小是根据初始化器的长度计算的,内容 被复制到数组中.

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

<前>项目地址 0x00 0x01 0x02 0x03---- ------- ---- ---- ---- ---- ----无名字 0x08001230 't' 'h' 'i' 's'0x08001234'''''''''''0x08001238 'a' ' ' 't' 'e'0x0800123C 's' 't' 0...字符串 1 0x12340000 0x08 0x00 0x12 0x30string2 0x12340004 't' 'h' 'i' 's'0x12340008'''''''''''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 的表达式时,括号不是必需的(尽管它们没有伤害).

Possible Duplicate:
What is the difference between char s[] and char *s in C?
Difference between char *str = "…" and char str[N] = "…"?

I have some code that has had me puzzled.

#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;
}

When it outputs the size of string1, it prints 4, which is to be expected because the size of a pointer is 4 bytes. But when it prints string2, it outputs 15. I thought that an array was a pointer, so the size of string2 should be the same as string1 right? So why is it that it prints out two different sizes for the same type of data (pointer)?

解决方案

Arrays and pointers are completely different animals. In most contexts, an expression designating an array is treated as a pointer.

First, a little standard language (n1256):

6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

The string literal "this is a test" is a 15-element array of char. In the declaration


    char *string1 = "this is a test";


string1 is being declared as a pointer to char. Per the language above, the type of the expression "this is a test" is converted from char [15] to char *, and the resulting pointer value is assigned to string1.


In the declaration


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


something different happens. More standard language:

6.7.8 Initialization
...
14 An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
...
22 If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. At the end of its initializer list, the array no longer has incomplete type.

In this case, string2 is being declared as an array of char, its size is computed from the length of the initializer, and the contents of the string literal are copied to the array.

Here's a hypothetical memory map to illustrate what's happening:

Item          Address       0x00  0x01  0x02  0x03
----          -------       ----  ----  ----  ----
no name       0x08001230    't'   'h'   'i'   's'
              0x08001234    ' '   'i'   's'   ' '
              0x08001238    'a'   ' '   't'   'e'
              0x0800123C    's'   't'    0
              ...
string1       0x12340000    0x08  0x00  0x12  0x30
string2       0x12340004    't'   'h'   'i'   's'
              0x12340008    ' '   'i'   's'   ' '
              0x1234000C    'a'   ' '   't'   'e'
              0x1234000F    's'   't'    0

String literals have static extent; that is, the memory for them is set aside at program startup and held until the program terminates. Attempting to modify the contents of a string literal invokes undefined behavior; the underlying platform may or may not allow it, and the standard places no restrictions on the compiler. It's best to act as though literals are always unwritable.

In my memory map above, the address of the string literal is set off somewhat from the addresses of string1 and string2 to illustrate this.

Anyway, you can see that string1, having a pointer type, contains the address of the string literal. string2, being an array type, contains a copy of the contents of the string literal.

Since the size of string2 is known at compile time, sizeof returns the size (number of bytes) in the array.

The %i conversion specifier is not the right one to use for expressions of type size_t. If you're working in C99, use %zu. In C89, you would use %lu and cast the expression to unsigned long:


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

Note that sizeof is an operator, not a function call; when the operand is an expression that denotes an object, parentheses aren't necessary (although they don't hurt).

这篇关于关于C中指针和字符串的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆