char **然后取消引用char *

时间:2012-09-17 06:11:52

标签: c pointers casting

为了比较字符串使用库函数,我学会了编写一个比较函数来比较两个字符串,但我不清楚为什么他们这样做。

int StrCmp(const void *a, const void *b){
    char *s1 = *(char**) a;
    char *s2 = *(char**) b;
    return strcmp(s1,s2);
}

为什么他们必须先把它投给char **? 为什么不直接将它们转换为char *? 喜欢

return strcmp((char*)a, (char*)b);

将(指针)转换为(指向指针的指针)的含义 如果我有

char *x = "string";

如果我为x

进行投射
(char**)x; // what is this? Is this character 's'?

我对此非常困惑,谢谢你的澄清 还有一个问题是关于const 如果它是一个常量,我还可以施展它们吗?(我知道我可以这样做)

3 个答案:

答案 0 :(得分:4)

该函数的调用者很可能正在使用指针数组,例如:

const char* arr_of_ptr[] =
{
  "hello",
  "world"
};

在这种情况下,数组的第一个元素是指向char的指针,它本身不是char。因此,StrCmp函数充当指向普通C字符串的指针数组之间的转换器。

但是,它们也会丢弃const关键字,这是不好的做法。该函数应该写成:

int StrCmp(const void *a, const void *b){
    const char *s1 = *(const char**) a;
    const char *s2 = *(const char**) b;
    return strcmp(s1,s2);
}

Good reading on the topic

答案 1 :(得分:4)

“为什么他们必须先将它转换为(字符指针指针)? 为什么不直接将它们转换为(char指针)?“


他们必须把它变成现实。假设价值 你有记忆位置10,000点 像这样的东西:

  (char **) 

  a                 address a
                    "points to"
                    *a                **a   
  mem 1000          mem 10000         mem 20000
  to mem 1007       to mem 10007
  _____________     _____________     _______________ 
  pointer var  --> char pointer   ->  char
  10000             20000             'a'
  _____________     _____________     _______________

如果将它转换为(char *),则告诉编译器 a(在这种情况下为10,000)引用的地址是char。 哪个不对。

  (char *)          address a points 
  a                 to
  mem 1000          mem 10000         mem 20000
  to mem 1007
  _____________     ______            ________________
  pointer var  -->  "char"            unreachable char
  10000             ?                 'a'
  _____________     ______            ________________

“什么是(指针)指向(指针指针)的意思如果我有

char * x =“string”; 如果我为x做演员

(字符**)X; // 这是什么?这个角色是'?'


此示例中存在的内容类似于:

x            *x or x[0] x[1]       x[2]      x[3]      x[4]      x[5]      x[6]
mem 15000    mem 30000  mem 30001  mem 30002 mem 30003 mem 30004 mem 30005 mem 30006
to 15007
char *       char       char       char      char      char      char      char
_________    _________  _________  _________ _________ _________ _________ _________

30000    -->    's'       't'         'r'      'i'      'n'       'g'       '\0'
________     _________  _________  _________ _________ _________ _________ _________

如果你告诉编译器x是char **那么它会认为这个 是模式:

x              *x or x[0]         **x
               char *
mem 15000      mem 30000          "char" 
to 15007       to 30007
__________     _________          _________

30000      --> "string\0?"
               converted to
               pointer value  ->   ??
__________     _________          _________

它错误地最终转到任何“地址”,从30000开始的前8个字节解析为并获得“字符”。但是因为30000是 开始一个以null结尾的字符数组,最好它会进入内存的某个部分并获得一些随机字节,认为它是一个有效的字符。在最坏的情况下,它将获得一个对该程序无效的地址,在尝试访问它时会导致致命错误。


我也可以这样做

 return strcmp((char *)a, (char *)b);

不,因为a和b不是char指针。要得到char指针,你无法避免:

return strcmp( *(char**)a, *(char**)b);

使用林登的例子,你会这样打电话:

#include <stdio.h>
#include <string.h>

int StrCmp(const void *a, const void *b){
    char *s1 = *(char**) a;
    char *s2 = *(char**) b;
    printf("s1:%s\n",s1);
    printf("s2:%s\n",s2);
    return strcmp(s1,s2);
}

const char* arr_of_ptr[] =
{
  "hello",
  "world"
};

const char **p_arr_of_ptr = arr_of_ptr;

int main(void)
{
   const char *cstring1 = "LaDonna";
   const char *cstring2 = "McPherson";
   const char **pcstring1 = &cstring1;
   const char **pcstring2 = &cstring2;
   StrCmp(&arr_of_ptr[0],&arr_of_ptr[1]);
   StrCmp(pcstring1,pcstring2);
   StrCmp(p_arr_of_ptr,p_arr_of_ptr + 1);
}

答案 2 :(得分:1)

这实际上是将一个void指针(即:void*)转换为指向char的指针(即:char**)。

请记住,间接/反引用运算符(一元*运算符)和类型转换运算符(例如:(char**))具有相同的优先级,但也具有从右到左的关联性。 / p>

所以,请考虑以下事项:

void myFunction(void* a) {
  char* s1;  // Pointer to a character, or the beginning of a character array or string
             // Note that the effective difference between a character array and a string is that
             // a string is a character array that is terminated with the '\0' character
  s1 = *(char**) a;
             /* The above statement can be decomposed as follows:
              * (  *( (char**) a ) )
              * 1) Cast the pointer-to-void-type, (ie: void*)'a', 
              *    to a pointer-to-pointer-to-char (ie: char**)
              * 2) Deference the value, so it becomes a pointer-to-char
              * 3) Assign this char* value to s1
              */
}

这在C中非常常见,你必须做一些漂亮的指针魔术,因为该语言不支持像后继C ++这样的模板。请注意,如果您可以使用高级指针逻辑,那么您可能无需使用C ++代替C语言。

祝你好运!