2016-07-28 23 views
7

我写了下面的代码:结构查找表使用字符串指针问题

unsigned char *cPtr[] = 
{ 
    "First", 
    "Second", 
    "Third" 
}; 

typedef struct 
{ 
    int a; 
    char *lut; /* or char lut[20]*/ 
}Grp_t; 

const Grp_t Grp_st[]= 
{ 
    { 0, cPtr[0] }, 
    { 1, cPtr[1] }, 
    { 2, cPtr[2] } 
}; 

当我尝试编译这段代码,我得到了以下错误:

错误:初始元素不是常数

错误:(近初始化为 'Grp_st [0] .lut [0]')

但是当我更换*cPtr[]通过cPtr[][16]作为

unsigned char cPtr[][16] = 
{ 
    "First", 
    "Second", 
    "Third" 
}; 

我能够成功地编译代码。

请任何人解释我在这里失踪的概念。

+0

你不能在C中做这件事。当它用'cPtr [] [16]编译时'你应该得到警告,它不会做你认为它会做的事。 –

+0

@MichaelWalz,当你说它不能在C中做什么时,你的意思是什么?有时我得到同样的问题,并通过声明链解决它:'unsigned char c_ptr_0 [] =“First”; unsigned char c_ptr_1 [] =“Second”; unsigned char * c_ptr [] = {c_ptr_0,c_ptr_1};' - 那么在这里不能做什么? – imbearr

+0

@MichaelWalz,请您详细说明 – user1093152

回答

6

这是C.

的限制

6.7.8.4初始化

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

而且6.6.9常量表达式

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type. The array-subscript [] and member-access . and -> operators, the address & and indirection * unary operators, and pointer casts may be used in the creation of an address constant, but the value of an object shall not be accessed by use of these operators.

如果你可以改变代码使Grp_st不是它编译的静态存储持续时间:

#include <stdio.h> 
const char *cPtr[] = 
{ 
    "First", 
    "Second", 
    "Third" 
}; 

typedef struct 
{ 
    int a; 
    const char *lut; 
} Grp_t; 


int main(void) { 
    Grp_t Grp_st[]= { 
    { 0, cPtr[0] }, 
    { 1, cPtr[1] }, 
    { 2, cPtr[2] } 
    }; 
    return 0; 
} 

在第二种情况下你设法编译代码,因为你没有在给定的索引访问数组元素,但只有一个指针(在char cPtr[][16]情况下,cPtr[0]给出的16个字符的第一阵列的地址和cPtr[0]衰减到char *的表达式) - 因此您没有违反6.6.9规则。

+2

* cPtr []和cPtr [] [16]有什么区别? – user1093152

+1

在第二种情况下,您使用了一个指针,并且没有在给定的索引处访问过arrray值,因此您没有违反6.6.9规则 – 4pie0

+2

@ user1093152 ...并且它没有按照您的想法进行操作。 –

1

静态对象的初始化程序必须是常量。

由于您尝试初始化静态对象的成员,类型指针为char的成员需要地址常量。

cPtr[0]不是地址常量,因为在尝试创建此地址常量时访问对象cPtr的值。

另一方面,cStr[0]不访问任何值的对象cStr。表达式cStr[0]&cStr[0][0]相同,显然不会访问该值,而只能访问该值的地址。 ISO/IEC 9899:201X 6.7


(引自。9初始化4)
对于具有静态或线程存储持续时间 的对象,初始值设定项中的所有表达式应为常量表达式或字符串文字。

(:ISO/IEC 9899:引自201X 6.6常量表达式9)
地址常量是一个空指针,一个指向一个左值指定静态 存储持续时间的目的,或一个指针,指向一个函数指示符;应使用 运算符或一个整型常量强制转换为指针类型,或者通过使用 表示数组或函数类型明确创建。数组下标[]和成员访问。 和 - >运算符,地址&和间接*一元运算符,以及指针转换可能使用 创建地址常量,但通过使用这些运算符可以访问对象的值不得为 。

但是使用这些运算符访问的对象的值不应该是 。

0

这主要是对@where_is_ftp的答案进行补充以添加有关*cPtr[]cPtr[][16]之间差异的详细信息。前一种情况是指针数组。在那种情况下,地址cPtr[0],cPtr[1],cPtr[2]是不相关的并且是运行时间值,即被指向的字符串的地址。

后者是一个二维数组。在这种情况下,地址cPtr[0],cPtr[1]cPtr[2]是二维数组内的地址,具体地说是cPtr[1] == cPtr[0] + 16,并且原始字符串已经作为数组初始化被复制到二维数组中。这就是为什么他们现在是不变的价值。