LINUX.ORG.RU

проблема массивом указателей


0

0

Продолжаю штудировать указатели по книге Кернигана и Ричи. Пытаюсь заставить работать этот код:

#include <stdio.h>

static const char *lineptr[] = {"abc", "d", "ef", "jh", "xyz"};

int main(void)
{
while (*lineptr) {
printf("string '%s'\n", *lineptr++); /*XXX*/
}

return 0;
}

Компилятор ругается на строку XXX: invalid lvalue in increment
Но все исправно работает и компилится, если сделать :

#include <stdio.h>

static const char *lineptr[] = {"abc", "d", "ef", "jh", "xyz"};

int main(void)
{
const char **tmp = lineptr;
while (*tmp) {
printf("string '%s'\n", *tmp++);
}

return 0;
}

Пока еще до конца не осознал, что происходит :( надеюсь на подсказки.

anonymous

Между const char **tmp и const char *lineptr разницу осознаешь?

CFA
()

> printf("string '%s'\n", *lineptr++); /*XXX*/

С какой радости инкрементируем _массив_? Это тебе не указатель, хоть и неявно приводится к этому типу.

> const char **tmp = lineptr; > while (*tmp) { > printf("string '%s'\n", *tmp++); > }

Зачем объявлять лишний уровень указателя? Далее, почему в условии цикла стоит *tmp? С какой радости данные по указателю проверяются на логическую истину?

spy_
()

Имя массива - это константа, представляющая собой указатель на 0-ой элемент массива. Этот указатель отличается от обычных тем, что его нельзя изменить.

sergej ★★★★★
()

>while (*tmp) {

tmp спокойненько выйдет за пределы массива и вызовет segfault.

Davidov ★★★★
()
Ответ на: комментарий от spy_

>> printf("string '%s'\n", *lineptr++); /*XXX*/
> С какой радости инкрементируем _массив_? Это тебе не указатель, хоть и > неявно приводится к этому типу.


Рассуждаю так: lineptr это массив из указателей на char (строки), lineptr указывает на первый элемент этого массива (т.е. на первый указатель на строку "abc"), соответственно увеличивая этот указатель, можно двигаться по элементам массива.

Где ошибка в моих рассуждениях?

>> const char **tmp = lineptr; > while (*tmp) { > printf("string '%s'\n", *tmp++); > }


> Зачем объявлять лишний уровень указателя?


Что значит лишний уровень указателя?

> Далее, почему в условии цикла стоит *tmp? С какой радости данные по указателю проверяются на логическую истину?


а как тогда правильно сделать, приведи пример plz.

anonymous
()

> #include <stdio.h>
>
> static const char *lineptr[] = {"abc", "d", "ef", "jh", "xyz"};
> 
> int main(void)
> {
> while (*lineptr) {
> printf("string '%s'\n", *lineptr++); /*XXX*/
> }
>
> return 0;
> } 

#include <stdio.h>

static const char *lineptr[] = {"abc", "d", "ef", "jh", "xyz"};

int 
main()
{
    const char **ptr = lineptr + (sizeof(lineptr)/sizeof(lineptr[0]));
    while (--ptr >= lineptr) {
        printf("string '%s'\n", *ptr); /*XXX*/
    }

    return 0;
}

anonymous
()
Ответ на: комментарий от anonymous

имхо лучше lineptr нулевым указателем завершить

dilmah ★★★★★
()
Ответ на: комментарий от anonymous

>Рассуждаю так: lineptr это массив из указателей на char (строки), lineptr указывает на первый элемент этого массива (т.е. на первый указатель на строку "abc"), соответственно увеличивая этот указатель, можно двигаться по элементам массива.

Как ни странно, массив и указатель в C - это разные понятия. Они, действительно, обладают похожими свойствами, но массив - это не l-value (см. докумендацию/книжки/стандарты). Под указатель на первый элемент массива просто не выделяется память. Точно так же ты можешь пытаться сделать 2++.

>а как тогда правильно сделать, приведи пример plz.

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

Можно хранить длину массива, чтоб не выйти за его пределы. А можно сделать специальный элемент, который программа будет интерпретировать как "конец массива". В C-style строках используется второй.

Davidov ★★★★
()
Ответ на: комментарий от anonymous

>соответственно увеличивая этот указатель, можно двигаться по элементам массива.

>Где ошибка в моих рассуждениях?

ошибка в том, что нельзя увеличивать этот указатель. по определению!!!

> Зачем объявлять лишний уровень указателя?

а иначе никак...

>С какой радости данные по указателю проверяются на логическую истину?

вполне допустимо! только у него в исходном массиве нет завершающего NULL. а это, как уже сказали, segfault

xydo ★★
()
Ответ на: комментарий от xydo

вот наиболее приемлимый вариант

#include <stdio.h>

static const char *lineptr[] = {"abc", "d", "ef", "jh", "xyz", NULL};

int main(void)
{
  const char **tmp = lineptr;
  while (*tmp) {
    printf("string '%s'\n", *tmp++);
  }

  return 0;
} 

xydo ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.