Передача указателей на функции - PullRequest
1 голос
/ 19 июня 2009

У меня есть сомнения в моей программе

#include<stdio.h>

int myFunc(char **);
main()
{
    char *a[2]={"Do","While"};
    myFunc(a);
}

int myFunc(char **P)
{
    /* Here I want to print the strings passed but I'm unable to
       print the strings I just tried the below statement which
       printed just the first letter which is 'D'*/
       printf("%c",**P);
}

когда я пытался

printf("%s",**P);

Я получаю ошибку во время выполнения. так может кто-нибудь, пожалуйста, помогите мне?

Спасибо Мадху

Ответы [ 8 ]

11 голосов
/ 19 июня 2009

Установите размер в качестве параметра, чтобы функция могла знать, сколько строк у вас в массиве. Затем вы должны перебрать массив и напечатать каждый из них.

int myFunc( char** p, int size)
{
  for( int i = 0; i < size; ++i)
  {
     printf("%s", p[i]);
  }
}

Позднее редактировать (по запросу :-))

int main( int, char**)
{
   char *a[2]={"Do","While"};
   myFunc( a, 2); // Could be myFunc( a, sizeof(a)/sizeof(char*));
   // ...
   return 0; 
}
8 голосов
/ 19 июня 2009

Слишком много звезд - попробуйте

printf("%s",*P);

И вам нужен %s спецификатор формата - %c только для одного символа.

Если вы хотите напечатать все строки, вам нужно передать количество строк в массиве, а затем распечатать эти строки из цикла.

Проверьте код, предложенный Cătălin Pitiș. Чтобы передать количество строк, вы вызываете функцию следующим образом:

myFunc(a, sizeof(a)/sizeof(a[0]));
5 голосов
/ 19 июня 2009
for( int i = 0; i < 2; i++ ) {
    char* string = P[i];
    printf( "%s", string );
}

И вы должны использовать какой-либо способ передачи размера массива в функцию - либо передайте его как параметр int,

int myFunc(char **P, int size)
{
    for( int i = 0; i < size; i++ ) {
        //whatever here
    }
}

или всегда добавляйте нулевое значение к массиву и выполняйте цикл, пока не найдете это нулевое значение.

char* array[] = { "String1", "String2", 0 };    

В противном случае вам будет сложно поддерживать код.

4 голосов
/ 19 июня 2009

Мне нравятся массивы с нулем (0) в формате target-c:

void myFunc(char **P)
{
    while (*P)                   // loop to iterate over all strings until 0
       printf("%s\n",*P++);      // print and move to next element in array
}

int main()
{
    char *a[]={"Do","While",0};  // added 0 to null terminate array,
    myFunc(a);                   // kind of like string
}

Выход:

Do
While
1 голос
/ 19 июня 2009

, если вы не хотите сохранять и передавать размер массива ::

int myFunc(char **);
main()
{
    char *a[2]={"Do","While", NULL};
    myFunc(a);
}

int myFunc(char **P)
{
    if( !P )
        return 0;
    while(*P != NULL)
    {
        printf("%s",*P);
        P++;
    }
}
1 голос
/ 19 июня 2009

Проблема в вашем коде состоит в том, что вы хотите напечатать строку (char *), но вы даете ей символ. Помните, что P - это массив char *. Когда вы отмените ссылку на него один раз, вы получите символ *; когда вы делаете это второй раз, вы просто получаете символ в начале символа *.

Когда вы пытаетесь использовать значение char со спецификатором% s, оно обрабатывает значение как указатель и пытается разыменовать это значение. Следовательно, он будет пытаться напечатать «строку» в ячейке памяти X, где X - это значение символа (то есть значение от 0 до 255). Это дает вам нарушение прав доступа / ошибка сегментации (ошибка, которую вы видите во время выполнения).

Лучшие обходные пути для этого, как отмечают Cătălin Pitiș и RBerteig , следующие:

  • передать другой параметр, чтобы указать длину массива
  • добавить дополнительный ноль в конце массива.
1 голос
/ 19 июня 2009

Во-первых, хорошая новость: тип a эквивалентен char **, поэтому вы передаете действительный параметр myFunc().

Первая проблема заключается в том, что %c - это спецификатор формата, который означает печать одного символа. Поскольку **P является выражением, которое оценивается одним символом, ваша первая версия делает именно то, что вы сказали. Это не то, что вы хотите.

Вторая версия близка к синтаксически правильной. Он должен читать printf("%s", *P), где *P - это выражение, которое оценивает указатель на строку ASCII с нулевым символом в конце. В этом случае он оценивает «Do». Эта версия не будет печатать обе строки.

Хотя верно, что имя массива совпадает с указателем на его первый элемент, это своего рода «ложь студентам». Передача массива в функцию не передает и не может передать длину массива. Чтобы сделать это, вам нужен либо второй аргумент, содержащий длину, либо соглашение, например, nul-terminator в строке, чтобы указать конец массива. С этим изменением вы можете изменить myFunc(), чтобы использовать цикл над переданными элементами и печатать каждый из них.

0 голосов
/ 19 июня 2009

Неправильный ответ: Я думаю, что вам, возможно, придется разыменовывать P при печати, хотя я могу ошибаться.

РЕДАКТИРОВАТЬ: Я устал, уже 3 часа ночи, но я не хочу спать, поэтому я пытаюсь ответить на вопросы. Прочитав критику, я перечитал вопрос и заметил, что он разыменовывает P, но, как указано в другом ответе, он слишком разыменовывается. Когда кто-то хочет напечатать строку символов, он хочет передать указатель, поскольку строка символов действительно является массивом.

Еще одно ИЗМЕНЕНИЕ: я также хотел бы отметить, что человек, который задал вопрос, сделал правку после того, как я ответил, и что, когда я впервые ответил, он не читал «printf («% s », ** P); " это читало "printf ("% s ", P);" и последняя часть была жирной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...