char ** s против char * s [], когда и как использовать каждый из них? - PullRequest
6 голосов
/ 22 июля 2011

Если я использую char *s[], я могу сделать следующее:

char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

В чем разница с **s?Как в этом случае использовать char **s вместо char *s[]?

Пример: int main (int argc, char **argv) вместо *argv[]

Ответы [ 9 ]

7 голосов
/ 22 июля 2011

Для параметров функции разницы нет.

В противном случае:

char *s[];

s - массив указателей на символ.И

char **s;

s - указатель на указатель на символ.

Вы используете первый, если вам нужен массив указателей на символ, и последний, если вам нужен указатель науказатель на символ.

4 голосов
/ 22 июля 2011

Как параметры функции, нет никакой разницы.Они эквивалентны.

void f(int** p);
void f(int* p[]);
void f(int* p[42]);

Эти три объявления эквивалентны.

Как объекты, они имеют разные типы;

char *s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};

s - это массив 6 указатель на char sizeof(s) == 6*sizeof(void*)

char **s;

s - указатель на указатель на char.sizeof(s) == sizeof(void*)

1 голос
/ 22 июля 2011

Не прямой ответ вашей очереди, но это может помочь вам понять немного больше:

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

int main() {

    char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

    printf("  s[0]: %s \n", s[0]);
    printf("    *s: %s \n", *s);
    printf("  *s+1: %s \n", *s+1);
    printf("*(s+1): %s \n", *(s+1));

return 0;
}

Выход:

$ gcc -o chararr chararr.c 
$ ./chararr 
  s[0]: foo   
    *s: foo 
  *s+1: oo 
*(s+1): bar 
1 голос
/ 22 июля 2011

Массивы и указатели это разные вещи. Указатель может быть использован для доступа к элементу в массиве. Чтобы иметь возможность инициализировать массив, вам нужно объявить массив, а не указатель.

Чтобы показать разницу, попробуйте:

int[] ia = {1, 2, 3, 4, 5, 6, 7, 8};
int* ip = ia;

printf("sizeof(ia): %zu, sizeof(ip): %zu", sizeof(ia), sizeof(ip));

Первый должен печатать размер массива, второй размер указателя int.

Странная вещь в C состоит в том, что когда массив передается в качестве параметра функции, он распадается на указатель. Подробнее см. В разделе 2.3 http://www.lysator.liu.se/c/c-faq/c-2.html. Причина, по которой main принимает argv** вместо argv*[], заключается в том, что argv*[] затухает в argv** при передаче в качестве параметра функции.

1 голос
/ 22 июля 2011

Они создают одинаковую структуру данных.Единственное отличие s в том, что char * s [] автоматически выделяет достаточно памяти для {"foo", "bar", "foobar", "whatever", "john, "doe"} при инициализации.char ** s будет выделять только один байт для указателя, тогда вы будете вручную распределять память для каждой строки в массиве.

0 голосов
/ 22 июля 2011

Это зависит от ваших требований. Если вашей программе не требуется изменять эти строки позже, вы можете использовать

char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

Они скомпилированы как строковые литералы в разделе только для чтения.

Сборочный выход:

        .file   "test.c"
        .section        .rodata
.LC0:
        .string "foo"
.LC1:
        .string "bar"
.LC2:
        .string "foobar"
.LC3:
        .string "whatever"
.LC4:
        .string "john"
.LC5:
        .string "doe"
        .text

Если вы попытаетесь изменить эти строки позже в программе, вы получите ошибку сегментации. В этом случае вы должны использовать char **s

0 голосов
/ 22 июля 2011

когда вы используете char *s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};, компилятор уже знает длину массива, т.е.: в этом случае он знает свой указатель на указатели из 6 символьных массивов.

char** не хватает информации о длине, и этов частности, почему main имеет 2 аргумента {length, pointer to pointer to char} == {argc, arv}

0 голосов
/ 22 июля 2011

Если вы определите

char **s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};

Я думаю, что это то же самое, что и определение трехмерных массивов (char s [10] [10] [10]), поскольку char * s [] определяет двумерный массив.

0 голосов
/ 22 июля 2011

Насколько мне известно, ** s - это адрес адреса s, где * s [] - адрес массива s, я думаю, вы бы хранили отдельные значения в s, но в s [] вы бы хранили массив и сам массив является указателем. Надеюсь, это поможет!

...