char *和char **之间的区别(在C中)

时间:2011-08-15 13:07:30

标签: c string pointers

我写的这段代码很简单

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

void printLastLetter(char **str)
{
    printf("%c\n",*(*str + strlen(*str) - 1));
    printf("%c\n",**(str + strlen(*str) - 1));
}

int main()
{
    char *str = "1234556";
    printLastLetter(&str);
    return 1;
}

现在,如果我想打印字符串中的最后一个字符,我知道printLastLetter的第一行是正确的代码行。我不完全理解的是* str和** str之间的区别。第一个是字符数组,第二个是? 另外,char * str和str [10]之间的内存分配有什么不同? Thnks

8 个答案:

答案 0 :(得分:18)

char*是指向char的指针,char **是指向char的指针。

char *ptr;不为字符分配内存,它为指向char的指针分配内存。

char arr[10];分配10个字符,arr保存第一个字符的地址。 (虽然arr不是指针(不是char *)而是类型char[10]

为了演示:char *str = "1234556";就像:

char *str;         // allocate a space for char pointer on the stack
str = "1234556";   // assign the address of the string literal "1234556" to str

正如 @Oli Charlesworth 所评论的,如果您使用指向常量字符串的指针(例如上例中),则应将指针声明为const - const char *str = "1234556";因此,如果您尝试修改它(这是不允许的),您将收到编译时错误,而不是运行时访问冲突错误,例如分段错误。如果您对此不熟悉,请查看here

另见the explanation in the FAQ of newsgroup comp.lang.c

答案 1 :(得分:11)

char ** x是指向指针的指针,当你想要修改其范围之外的现有指针时(例如,在函数调用中),它很有用。

这很重要,因为C是通过副本传递的,所以要修改另一个函数中的指针,你必须传递指针的地址并使用一个指向指针的指针,如下所示:

void modify(char **s)
{
  free(*s); // free the old array
  *s = malloc(10); // allocate a new array of 10 chars
}

int main()
{
  char *s = malloc(5); // s points to an array of 5 chars
  modify(&s); // s now points to a new array of 10 chars
  free(s);
}

您还可以使用char **来存储字符串数组。但是,如果你动态分配所有内容,请记住跟踪字符串数组的长度,以便循环遍历每个元素并释放它。

关于你的上一个问题,char * str;简单地声明一个没有分配内存的指针,而char str [10];在本地堆栈上分配10个字符的数组。一旦它超出范围,本地数组将消失,这就是为什么如果你想从函数返回一个字符串,你想使用一个带有动态分配(malloc'd)内存的指针。

另外,char * str =“一些字符串常量”;也是一个指向字符串常量的指针。字符串常量存储在已编译程序的全局数据部分中,无法修改。您不必为它们分配内存,因为它们已编译/硬编码到您的程序中,因此它们已占用内存。

答案 2 :(得分:2)

  

第一个是字符数组,第二个是??

第二个是指向数组的指针。由于你传递了str的地址而不是指针(str)本身,你需要这个来解除反射。

printLastLetter( str ); 

printf("%c\n",*(str + strlen(str) - 1)); 
除非你需要改变str的值,否则

更有意义。

答案 3 :(得分:2)

你可能会关心你的程序的这个微小变化(函数printLastLetter()没有变化,除了它是静态的),并找出输出的原因:

3
X

输出是完全确定的 - 但只是因为我仔细设置了list变量,因此它是确定性的。

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

static void printLastLetter(char **str)
{
    printf("%c\n", *(*str + strlen(*str) - 1));
    printf("%c\n", **(str + strlen(*str) - 1));
}

int main(void)
{
    char *list[] = { "123", "abc", "XYZ" };
    printLastLetter(list);
    return 0;
}

答案 4 :(得分:0)

char **基本上是一串字符串 - 一个字符数组数组。如果你想传递多个字符数组参数,你可以使用它,假设它们被正确分配。

char ** x; * x将取消引用并为您提供在x中分配的第一个字符数组。 ** x将取消引用该字符数组,为您提供数组中的第一个字符。

答案 5 :(得分:0)

对于您的代码段,*str保存地址到char,**str保存地址到变量持有char的地址。换句话说,指向指针。

每当你有* str时,只分配足够的内存来保存指针类型变量(32位机器上的4个字节)。使用str[10],已为10 char分配内存。

答案 6 :(得分:0)

**str只是(*str)[0]*strstr[10]之间的差异(我在假设的声明中)我认为,前者只是一个指向可以存储在全局静态内存中的常量字符串文字的指针,而后者在存储文字的堆栈上分配10字节的内存。

答案 7 :(得分:0)

char *是指向内存位置的指针。 for char * str =“123456”;这是字符串的第一个字符。 “”只是输入字符值数组的便捷方式。 str [10]是一种在内存中保留10个字符而不说它们是什么的方法。(nb由于最后一个字符是NULL,实际上只能容纳9个字母。当函数采用*参数时,你可以使用[]参数但不是相反。

在将str用作参数之前,先将str的地址变为不必要的复杂化。在C中,您经常将对象的地址传递给函数,因为它比传递整个对象快得多。但是因为它已经是一个指针,所以你不能通过将指针传递给指针来使函数更好。假设您不想将指针更改为指向其他字符串。