реклама на сайте
подробности

 
 
> Си
Буратино
сообщение Jan 24 2013, 19:24
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



ЗАДАЧА А
Есть функция (K&R), которая обращает порядок символов в строке. Вот она:


Код
#include <string.h>

void reverse (char s[]) {
   int c, i, j;
  
   for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
      c = s[i];
      s[i] = s[j];
      s[j] = c;
   }
}


Вопросы:
1. Какие слабые места у данной реализации.
2. Как можно оптимизировать код. И что конкретно это даст.
3. Какие есть варианты реализации функции.

Спасибо!


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
19 страниц V   1 2 3 > »   
Start new topic
Ответов (1 - 99)
telix
сообщение Jan 24 2013, 19:37
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 118
Регистрация: 9-12-12
Из: Курск
Пользователь №: 74 767




В коде ошибка поставьте j-- sm.gif

Сообщение отредактировал telix - Jan 24 2013, 19:42


--------------------
улыбаемся ...
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 24 2013, 20:15
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(telix @ Jan 24 2013, 22:37) *
В коде ошибка поставьте j-- sm.gif


да ,сори.

ЗАДАЧА Б
Есть реализация функции перевода "типа" bool в строку.

Код
char *b2s (char b) {
   static char *name[] = {"Out Of Range", "False", "True"};
   return (b < 0 || b > 1) ? name[0] : name [b+1];
}


Вопросы:
1. Какие слабые/ошибочные места у данной реализации.
2. Как можно оптимизировать код. И что конкретно это даст.
3. Какие есть варианты реализации функции.


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 24 2013, 20:31
Сообщение #4


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



В смысле AVR, может выглядеть так

CODE
#include <avr/io.h>
#include <string.h>
void reverse(char s[])
{
char *beg = (char *)&(s[0]);
char *end = (char *)&(s[strlen(s)]);
while(beg < end)
{
char c = *beg;
*beg++ = *(--end);
*end = c;
}
}

CODE

82: fc 01 movw r30, r24
84: 01 90 ld r0, Z+
86: 00 20 and r0, r0
88: e9 f7 brne .-6 ; 0x84 <reverse+0x2>
8a: 31 97 sbiw r30, 0x01 ; 1
8c: e8 1b sub r30, r24
8e: f9 0b sbc r31, r25
90: e8 0f add r30, r24
92: f9 1f adc r31, r25
94: dc 01 movw r26, r24
96: 04 c0 rjmp .+8 ; 0xa0 <reverse+0x1e>
98: 8c 91 ld r24, X
9a: 92 91 ld r25, -Z
9c: 9d 93 st X+, r25
9e: 80 83 st Z, r24
a0: ae 17 cp r26, r30
a2: bf 07 cpc r27, r31
a4: c8 f3 brcs .-14 ; 0x98 <reverse+0x16>
a6: 08 95 ret
Go to the top of the page
 
+Quote Post
редактор
сообщение Jan 25 2013, 05:16
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 356
Регистрация: 9-06-07
Пользователь №: 28 315



По задаче Б.
переменная типа bool принимает значение 0 и !0 (не 0). В зависимости от реализации компиляторе !0 может выглядеть любым целым числом, поэтому "Out Of Range" - некоррекное заявление.

Сообщение отредактировал редактор - Jan 25 2013, 05:16


--------------------
Хорошую систему делают из стандартных блоков нестандартно мыслящие инженеры.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 05:23
Сообщение #6


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(редактор @ Jan 25 2013, 08:16) *
По задаче Б.
переменная типа bool принимает значение 0 и !0 (не 0). В зависимости от реализации компиляторе !0 может выглядеть любым целым числом, поэтому "Out Of Range" - некоррекное заявление.

Неправда! Область значений, согласно stdbool.h -это true,false. Отсюда
Код
static const char strue[]="TRUE";
static const char sfalse[]="FALSE";
static const char sndef[]="OUT OF RANGE";
switch(boolean)
{
  case true:
   return &strue;
  case false:
   return &sfalse;
  default:
   return &sndef;
}
Go to the top of the page
 
+Quote Post
msalov
сообщение Jan 25 2013, 05:38
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(_Pasha @ Jan 25 2013, 08:23) *
Неправда! Область значений, согласно stdbool.h -это true,false.

Исходя из того, что в Си bool это всего лишь костыль для пришедших из других языков, и любое не 0-ое значение является истиной для условных операторов, то, ИМХО редактор прав.

Задачу А можно оптимизировать сильнее всего исходя из контекста.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 05:49
Сообщение #8


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(gotty @ Jan 25 2013, 08:38) *
и любое не 0-ое значение является истиной для условных операторов, то, ИМХО редактор прав.

biggrin.gif
if(0) - выражение в скобках сейчас == 0
if(!0) - выражение в скобках сейчас == 1
Ы?

Цитата(gotty @ Jan 25 2013, 08:38) *
Задачу А можно оптимизировать сильнее всего исходя из контекста.

Работа непосредственно с двумя указателями выигрывает на любых pic/avr/arm/x51
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Jan 25 2013, 05:59
Сообщение #9


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



В задаче А вижу только один недостаток - это нет проверки на пустую строку. Если длина будет 0, то произойдёт переполнение и запись за пределы строки. По производительности тоже проблем не наблюдаю - можно было бы сделать какой-нибудь ассемблерный SWAP или хотя бы промежуточную переменную поместить в регистр, но это от архитектуры зависит.
В задаче Б всякая жесть. Тип заявлен bool, а передаётся char. Сравнение почему-то с 0 и 1, хотя false и true может быть определена иначе. Нужно сравнивать с настоящими false и true, теми которые используются вашим компилятором.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 25 2013, 05:59
Сообщение #10


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



грубовато...
Код
const char* b2s (unsigned char b) {
   static const char* name[] = {"False", "True", "Out Of Range", "Out Of Range"};
   return name[b&3];
}


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 06:04
Сообщение #11


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(demiurg_spb @ Jan 25 2013, 08:59) *
return name[b&3];

Ага, щаз! А если b например... b=0x0C
Go to the top of the page
 
+Quote Post
msalov
сообщение Jan 25 2013, 06:08
Сообщение #12


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(_Pasha @ Jan 25 2013, 08:49) *
biggrin.gif
if(0) - выражение в скобках сейчас == 0
if(!0) - выражение в скобках сейчас == 1
Ы?
Я имел ввиду немного другое
Код
    if (42)
    {
        printf("True\n");
    }
    else
    {
        printf("False\n");
    }

Какая ветка условного оператора будет выполнена? Третьего "outofrange" не дано, увы.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 06:16
Сообщение #13


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(gotty @ Jan 25 2013, 09:08) *
Я имел ввиду немного другое

Дык это несовместимость типов. laughing.gif Почему к случаям явного приведения int к указателю всегда люди относятся настороженно, а к "притягиванию" bool к char - типа что это нормально?
Примеров привести не могу, у меня не очень богатый сишный опыт. Только анекдот
Цитата
#define true false // собаки, ковыряйтесь теперь сами


sm.gif
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 25 2013, 06:31
Сообщение #14


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(_Pasha @ Jan 25 2013, 10:04) *
Ага, щаз! А если b например... b=0x0C
Ну так я и сказал что грубоватоsm.gif
Код
const char* b2s (unsigned char b) {
   static const char* name[] = {"False", "True", "Out Of Range"};
   return name[(b>1)? 2:b];
}


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 06:33
Сообщение #15


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



В армоводческом смысле reverse() с указателями
CODE

0x0800024A B570 PUSH {r4-r6,lr}
0x0800024C 4605 MOV r5,r0
0x0800024E 462C MOV r4,r5
0x08000250 4628 MOV r0,r5
0x08000252 F000F84F BL.W strlen (0x080002F4)
0x08000256 1946 ADDS r6,r0,r5
0x08000258 E007 B 0x0800026A
0x0800025A 7820 LDRB r0,[r4,#0x00]
0x0800025C 1E71 SUBS r1,r6,#1
0x0800025E 460E MOV r6,r1
0x08000260 7809 LDRB r1,[r1,#0x00]
0x08000262 F8041B01 STRB r1,[r4],#0x01
0x08000266 7030 STRB r0,[r6,#0x00]
0x08000268 BF00 NOP
0x0800026A 42B4 CMP r4,r6
0x0800026C D3F5 BCC 0x0800025A
0x0800026E BD70 POP {r4-r6,pc}
Go to the top of the page
 
+Quote Post
msalov
сообщение Jan 25 2013, 06:33
Сообщение #16


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(_Pasha @ Jan 25 2013, 09:16) *
Дык это несовместимость типов. laughing.gif Почему к случаям явного приведения int к указателю всегда люди относятся настороженно, а к "притягиванию" bool к char - типа что это нормально?

Моё ИМХО: в нынешней реализации Си тип bool не имеет смысла, т.к. операнды операций равно/неравно не приводятся к одному типу (bool), а используются как есть. Вот и получается что 42 != true, а (bool)42 == true в зависимости от компилятора
Go to the top of the page
 
+Quote Post
Herz
сообщение Jan 25 2013, 06:39
Сообщение #17


Гуру
******

Группа: Модераторы
Сообщений: 10 983
Регистрация: 23-11-05
Пользователь №: 11 287



Цитата(Буратино @ Jan 24 2013, 22:15) *
Вопросы:
1. Какие слабые/ошибочные места у данной реализации.
2. Как можно оптимизировать код. И что конкретно это даст.
3. Какие есть варианты реализации функции.


Буратино, сообщите нам смысл Ваших вопросов. Что конкретно их породило?
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 25 2013, 07:29
Сообщение #18


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(gotty @ Jan 25 2013, 08:33) *
Моё ИМХО: в нынешней реализации Си тип bool не имеет смысла, т.к. операнды операций равно/неравно не приводятся к одному типу (bool), а используются как есть. Вот и получается что 42 != true, а (bool)42 == true в зависимости от компилятора
(Не понял, почему операнды в выражении (0.5 != 'A') должны приводиться к bool)

Это тоже не должно зависеть от компилятора. Т.е. если у конкретного компилятора «зависит», то он не соответствует стандарту.

В выражении, ну пусть уж (42 != true), операнды используются не «как есть», а приводятся к int.
Была бы она твёрдая — я бы её жевал Было бы 42UL, тогда бы true приводилось бы к unsigned long int :-)

Но зато вот (42 != true) имеет значение true и в
bool b = 5;
в переменную будет занесено 1 даже в C99 c <stdbool.h>, не говоря уже о C++.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 08:31
Сообщение #19


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(_Pasha @ Jan 24 2013, 23:31) *
В смысле AVR, может выглядеть так

CODE
#include <avr/io.h>
#include <string.h>
void reverse(char s[])
{
char *beg = (char *)&(s[0]);
char *end = (char *)&(s[strlen(s)]);
while(beg < end)
{
char c = *beg;
*beg++ = *(--end);
*end = c;
}

}


А зачем тут скобки?
Код
char *beg = (char *)&(s[0]);
char *end = (char *)&(s[strlen(s)]);
*(--end);


А почему вы пишите
Код
*(--end);

Это с терминатором строки связано?

А какой смысл объявлять и инициализировать "с" внутри операторного блока while?
Как Вы думаете, что передается в функцию: массив или строка? Мне кажется что не очень корректно формальный аргумент сотрица, ну как будет тот-же strlen с массивом то? Может правильнее описать аргумент так: char * s ?

demiurg_spb, мне не очень понравилось. читаемость отвалилась, а скилов не добавилось как по мне.


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
msalov
сообщение Jan 25 2013, 08:46
Сообщение #20


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(Буратино @ Jan 25 2013, 11:31) *
Выбираю текст для тату, а что?

Может тогда что из победителе The International Obfuscated C Code Contest выберете sm.gif
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jan 25 2013, 09:12
Сообщение #21


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Буратино @ Jan 25 2013, 12:31) *
А почему вы пишите
Код
*(--end);

Во-первых, пишете (изъявительное наклонение вместо повелительного)
А во-вторых, я однажды написал
* temp ++ ;
имея в виду инкремент значения по указателю, а потом долго не мог понять, почему это "бесполезная операция", с т.з. компилятора.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 09:28
Сообщение #22


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(MrYuran @ Jan 25 2013, 12:12) *
Во-первых, пишете (изъявительное наклонение вместо повелительного)

а как же жи ,ши через и? sm.gif

Цитата(MrYuran @ Jan 25 2013, 12:12) *
А во-вторых, я однажды написал
* temp ++ ;
имея в виду инкремент значения по указателю, а потом долго не мог понять, почему это "бесполезная операция", с т.з. компилятора.


* temp++ сначала плюсанется указатель, а затем получим значение по плюсанутому указателю ,постави(е)те скобки и все будет так как запланированио, но в нашем то случае именно что и не нужны они! Я так думаю


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
telix
сообщение Jan 25 2013, 09:29
Сообщение #23


Частый гость
**

Группа: Свой
Сообщений: 118
Регистрация: 9-12-12
Из: Курск
Пользователь №: 74 767



Я б пример А оптимизировал за счет второго буфера.
То есть не делал тройную пересылку a=>c b=>a c=>b
а однократную b[j--] => a[i++] но при этом a и b это разные массивы
"b" это исходная строка, "a" это пустой массив для записи строки в обратном порядке.
За счет использования второго буфера резко увеличивается скорость собственно операции.

Сообщение отредактировал telix - Jan 25 2013, 09:31


--------------------
улыбаемся ...
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 09:35
Сообщение #24


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(telix @ Jan 25 2013, 12:29) *
Я б пример А оптимизировал за счет второго буфера.
То есть не делал тройную пересылку a=>c b=>a c=>b
а однократную b[j--] => a[i++] но при этом a и b это разные массивы
"b" это исходная строка, "a" это пустой массив для записи строки в обратном порядке.
За счет использования второго буфера резко увеличивается скорость собственно операции.


по поводу тройной пересылки мы еще поговорим, а вот второй буфер не айс однозначно. во первых b[j--] => a[i++] в 2 раза больше нужно а во вторых место под буфер.


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 09:38
Сообщение #25


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Буратино @ Jan 25 2013, 11:31) *
А зачем тут скобки?

А почему вы пишите

А какой смысл объявлять и инициализировать "с" внутри операторного блока while?

Как Вы думаете, что передается в функцию: массив или строка? Мне кажется что не очень корректно формальный аргумент сотрица, ну как будет тот-же strlen с массивом то? Может правильнее описать аргумент так: char * s ?

1. Во-первых, без скобок оно не работало, во вторых, имею недостаток в виде "хронического плавания " в приоритетах, тк Си "не родной язык", по сему не брезгую лишними скобками, тем более, что в 80% случаев это правильный подход.
2. MrYuran ответил, именно после его сообщения, не помню когда и не скажу где sm.gif этот случай навечно впечатался в мозг. А делов-то всего пробел...
3. Как-раз смысл произошел из давних разговоров о свойствах GCC, что чем больше нагрузки на локальные переменные, тем будет правильнее. Листинг AVR это демострирует
4. Прототип функции кривоват, т.к. выпадает из общепринятой практики и заставляет задуматься о языке а не о том, что нужно.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 25 2013, 09:45
Сообщение #26


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Буратино @ Jan 25 2013, 12:28) *
* temp++ сначала плюсанется указатель, а затем получим значение по плюсанутому указателю ,постави(е)те скобки и все будет так как запланированио, но в нашем то случае именно что и не нужны они! Я так думаю

Я думаю не так.

Цитата(_Pasha @ Jan 25 2013, 12:38) *
... имею недостаток в виде "хронического плавания " в приоритетах, тк Си "не родной язык", по сему не брезгую лишними скобками, тем более, что в 80% случаев это правильный подход.

Я выписал на листок приоритеты операций, и держу его перед мор над монитором. А иногда еще в текстовые файлы - заметки по проекту - вставляю. И теперь безошибочно пишу что-то вроде a << 4 | b;
А Буратино может набить себе тату - таблицу с приоритетами. Лучшего вряд ли можно посоветовать! rolleyes.gif
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 09:48
Сообщение #27


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(_Pasha @ Jan 25 2013, 12:38) *
1. Во-первых, без скобок оно не работало, во вторых, имею недостаток в виде "хронического плавания " в приоритетах, тк Си "не родной язык", по сему не брезгую лишними скобками, тем более, что в 80% случаев это правильный подход.
2. MrYuran ответил, именно после его сообщения, не помню когда и не скажу где sm.gif этот случай навечно впечатался в мозг. А делов-то всего пробел...
3. Как-раз смысл произошел из давних разговоров о свойствах GCC, что чем больше нагрузки на локальные переменные, тем будет правильнее. Листинг AVR это демострирует
4. Прототип функции кривоват, т.к. выпадает из общепринятой практики и заставляет задуматься о языке а не о том, что нужно.


Хорошо ,мне нравится ваш вариант с указателями давайте его допилим и перейдем ко второй задачке!?
Итак: давайте формальный аргумент заменим на "char * s", это правильнее будет судя по всему. Раз так, то тогда зачем приводить &(s[0]); к (char *) да еще и скобки использовать!? Сначала индекс ,а только потом одноместные унарные!

Код
char *beg = (char *)&(s[0]);


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jan 25 2013, 09:48
Сообщение #28


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Буратино @ Jan 25 2013, 13:28) *
а как же жи ,ши через и? sm.gif

жи это жи, а ше это ше )
Насчет скобок - лучше явно указать.
И самому спокойнее, и читателю понятнее будет.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 09:52
Сообщение #29


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(ViKo @ Jan 25 2013, 12:45) *
Я выписал на листок приоритеты операций, и держу его перед мор над монитором. А иногда еще в текстовые файлы - заметки по проекту - вставляю. И теперь безошибочно пишу что-то вроде a << 4 | b;

Дык я это расцениваю(для себя) как write only style sm.gif Тем более, не встречал случаев, когда лишние скобки влияют не результат.
--
Закномерность: чем более пустяковый вопрос, тем оживленнее тема. Насчет замечания Herz. Только штука в том, что здесь из простейшего произрастают интересные вещи. Довольно часто.
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 09:53
Сообщение #30


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(MrYuran @ Jan 25 2013, 12:48) *
жи это жи, а ше это ше )
Насчет скобок - лучше явно указать.
И самому спокойнее, и читателю понятнее будет.


Нет, давайте так: в этих "задачках" сделаем все правильно ,а в жизни будем беспокоится о читателях. Ищу самую правильную и изящную реализацию, хочу вот именно так и не иначе.


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jan 25 2013, 09:59
Сообщение #31


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(Буратино @ Jan 25 2013, 12:31) *
demiurg_spb, мне не очень понравилось. читаемость отвалилась, а скилов не добавилось как по мне.

Профит есть 2 строчки кода с хорошей читаемостью вместо 6..9 строк кода в другой реализации.
Вы это поймёте, когда будете писать большие программы, в которых становится важна не только выразительность отдельно взятой процедуры, а модуля целиком... Всему своё время.

Цитата(_Pasha @ Jan 25 2013, 09:23) *
Код
static const char strue[]="TRUE";
static const char sfalse[]="FALSE";
static const char sndef[]="OUT OF RANGE";
switch(boolean)
{
  case true:
   return &strue;
  case false:
   return &sfalse;
  default:
   return &sndef;
}
Кстатиsm.gif В этом кусочке кода три ошибки (три лишних символа &).
А вы говорите хорошая читаемость... Чем лаконичнее, тем ИМХО профессиональнее.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 25 2013, 10:00
Сообщение #32


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Буратино @ Jan 25 2013, 12:53) *
Ищу самую правильную и изящную реализацию, хочу вот именно так и не иначе.

Если речь идет о первом вопросе, то логичнее не попадать в такую ситуацию. Строки не сами по себе появляются в программе. Вот в момент создания и заносить символы в нужном порядке.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 10:04
Сообщение #33


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Буратино @ Jan 25 2013, 12:48) *
давайте его допилим и

Чо там пилить?
CODE

void reverse(char *s)
{
if(s == NULL) return;
char *end = s;
while(*end) end++;
while(s < end)
{
char c = *s;
*s++ = *(--end);
*end = c;
}
}

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

Сообщение отредактировал _Pasha - Jan 25 2013, 10:06
Go to the top of the page
 
+Quote Post
telix
сообщение Jan 25 2013, 10:06
Сообщение #34


Частый гость
**

Группа: Свой
Сообщений: 118
Регистрация: 9-12-12
Из: Курск
Пользователь №: 74 767



Цитата(Буратино @ Jan 25 2013, 13:35) *
по поводу тройной пересылки мы еще поговорим, а вот второй буфер не айс однозначно. во первых b[j--] => a[i++] в 2 раза больше нужно а во вторых место под буфер.

Я бы поспорил насчет в два раза, и про место под буфер
Так что удачи...

Сообщение отредактировал telix - Jan 25 2013, 10:09


--------------------
улыбаемся ...
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 10:06
Сообщение #35


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Давайте в первом чтении вот такую версию ЗАДАЧИ А от _Pasha обсудим?
Код
#include <string.h>
void reverse ( char *s ) {

   char *beg = s;
   char *end = &s[strlen(s)];
   char c;

   while(beg < end) {
       c = *beg;
      *beg++ = *--end; // благодаря префиксному декременту end терминатор строки '\0' останется на своем месте
      *end = c;
   }
}




--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 10:17
Сообщение #36


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Для нелюбителей тройных пересылок есть одна бяка
Код
while(beg < end)
{
  *beg++ = *(--end);
  *end = *beg;
}

Строка "сползает", но ее можно искусственно расширить и передать указ. не на начало, а на s[1]
Бред, в общем случае, но.. если у нас не char а нечто более существенное, пересылки могут доставить
ЗЫ вот только для чего эти сферокони, не пойму sm.gif

Сообщение отредактировал _Pasha - Jan 25 2013, 10:21
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 25 2013, 10:20
Сообщение #37


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(_Pasha @ Jan 25 2013, 13:17) *
Для нелюбителей тройных пересылок есть одна бяка
...
Строка "сползает"

Так вы потеряете первый символ строки... и т.д.
++ инкрементирует указатель после использования.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 10:23
Сообщение #38


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(ViKo @ Jan 25 2013, 13:20) *
Так вы потеряете первый символ строки... и т.д.

А не надо его терять. Первый символ !=0 и всё, а сама строка начинается со второго. Ассемблерные заморочки sm.gif
Кстати, такая штуковина со "сползанием и перестановкой" может в графике пригодиться

Сообщение отредактировал _Pasha - Jan 25 2013, 10:25
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 25 2013, 10:29
Сообщение #39


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(_Pasha @ Jan 25 2013, 13:23) *
А не надо его терять. Первый символ !=0 и всё, а сама строка начинается со второго. Ассемблерные заморочки sm.gif
Кстати, такая штуковина со "сползанием и перестановкой" может в графике пригодиться

Т.е. начать переносить на 1 символ левее строки? Тогда в середине появится разрыв. laughing.gif
По-моему, без промежуточной переменной - никак!
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 10:53
Сообщение #40


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Вот немного "заоптимизировал". Теперь переменной "с" нет, но есть 3 дополнительные арифметич. действия. Какие есть мысли, соображения? Спасбио!
Код
#include <string.h>
void reverse ( char *s ) {

   char *beg = s;
   char *end = &s[strlen(s)-1];

      do {
         *end -= *beg;
         *beg += *end;
         *end = *beg - *end;
      } while (++beg < --end);
}


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 11:00
Сообщение #41


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(ViKo @ Jan 25 2013, 13:29) *
Т.е. начать переносить на 1 символ левее строки? Тогда в середине появится разрыв. laughing.gif
По-моему, без промежуточной переменной - никак!

Ага, ошибочка вышла. Да простит меня высокое собрание.

Цитата(Буратино @ Jan 25 2013, 13:53) *
Какие есть мысли, соображения? Спасбио!

На общеприменяемых архитектурах будет хуже. Потому что "лишний" char c есть регистровая переменная. А так - добавляются операции, такие же переменные неявно выделяются компилятором, но самое обидное будет если у нас не char, а long например.
В принципе, вместо + - как у Вас надо бы
Код
поменять местами A,B
A ^= B;
B ^= A;
A ^= B;


Сообщение отредактировал _Pasha - Jan 25 2013, 11:00
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 11:11
Сообщение #42


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(_Pasha @ Jan 25 2013, 14:00) *
Ага, ошибочка вышла. Да простит меня высокое собрание.


На общеприменяемых архитектурах будет хуже. Потому что "лишний" char c есть регистровая переменная. А так - добавляются операции, такие же переменные неявно выделяются компилятором, но самое обидное будет если у нас не char, а long например.
В принципе, вместо + - как у Вас надо бы
Код
поменять местами A,B
A ^= B;
B ^= A;
A ^= B;


с исключающим или мне не очень, хотя красиво конечно a ^= b ^= a ^= b;

Вот еще вариантец, только проверить нужно. Кстати как можно простенькие такие программки потестить? Например в самом ИАРе? Как в отладочное окно выводить результаты всяких printf? Спрашивал однажды и запамятовал к сож(
Код
#include <string.h>
void reverse ( char *s ) {

   char *beg = s;
   char *end = &s[strlen(s)-1];

    do
       *beg += *end - (*end = *beg);
    while (++beg < --end);
}


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 25 2013, 11:11
Сообщение #43


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Да, верно, с исключающим или можно обойтись без промежуточной переменной (знал, но забыл). Но это не будет эффективнее, чем использовать еще один регистр.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 11:35
Сообщение #44


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Буратино @ Jan 25 2013, 15:11) *
Вот еще вариантец, только проверить нужно. Кстати как можно простенькие такие программки потестить?

У меня три вивария, с чем работаю, симуляторы
1. C::B + Proteus для аврок - всё в два клика, но создать проект под АРМ - муки творчества, ибо визардов нормальных нету, поэтому
2. Кейл, там тоже элементарно, исключительно из-за stm32 и at91sam7s
3. Mplab
Сыр-бор весь только чтобы глянуть листинг.

Сообщение отредактировал _Pasha - Jan 25 2013, 11:36
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 25 2013, 11:55
Сообщение #45


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Буратино @ Jan 25 2013, 13:11) *
Кстати как можно простенькие такие программки потестить? Например в самом ИАРе? Как в отладочное окно выводить результаты всяких printf?

CODE
C:\user\My documents>echo "#include <stdio.h>\
int main()\
{\
      printf (\"Hello, world\");\
      return 0;\
}\
" > test.c

C:\user\My documents>gcc test.c -o test.exe
C:\user\My documents>test.exe
Hello, world
C:\user\My documents>


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 25 2013, 12:48
Сообщение #46


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Буратино @ Jan 25 2013, 13:11) *
с исключающим или мне не очень, хотя красиво конечно a ^= b ^= a ^= b;
UB на двух записях в a в переделах sequence point. Правильно так, как было написано сначала, в три строки. Можно записать в две, но это уже неинтересно.

Цитата(Буратино @ Jan 25 2013, 13:11) *
Код
       *beg += *end - (*end = *beg);
Вам так хочется UB-иться?
UB на произвольном порядке вычисления подвыражений (тут возможность записи в *end в скобках в правом аргументе операции вычитания до того, как будет прочитано *end в левом операнде).


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 25 2013, 12:54
Сообщение #47


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Что еще за UB? Мы ж так не UBьемся!
Последовательность операций в a ^= b ^= a ^= b; определена точно. Справа налево.
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 25 2013, 12:58
Сообщение #48


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



что такое UB? что такое в пределах sequence point?
a ^= b ^= a ^= b;
сначала выполнится a ^= b ,затем b ^= a и в конце a ^= b по идее все верно. Нужно проверить.


Код
*beg += *end - (*end = *beg);

тут мне кажется что однозначно от старого *end новое отнимется ,но снова вынужден признать- необходимо проветить


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 25 2013, 13:20
Сообщение #49


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Да вроде всегда была определена последовательность вычислений, но не последовательность записи результатов.
Так как значением выражения (a = B) является не «содержимое а после записи», а «значение b приведенное к неквалифицированному типу а».
А (a ^= B) это «то же, что и (a = a ^ B), за исключением того, что a оценивается один раз»
А порядок записи в пределах между точками следования неопределён.

Но что-то меня LWS поколебал...

http://liveworkspace.org/code/Ll7BX$13

gcc по 4.6.3 выдаёт
Цитата
source.cpp:7:20: warning: operation on 'a' may be undefined [-Wsequence-point]

в режимах и C, и C++, gcc 4.7.2 только в режиме C, но не в C++

clang 3.2 доволен всем.

Для меня это новость. Первое (и последнее -- больше так не баловался) предупреждение на a ^= b ^= a ^= b; я получил как бы не от BCC5 уже не помню как давно. Почитал стандарт. Вроде понял :-)

Что касается *beg += *end - (*end = *beg);, то все компиляторы единодушны -- UB (undefined behavior).


Цитата(Буратино @ Jan 25 2013, 14:58) *
что такое UB? что такое в пределах sequence point?
«тут мне кажется», что Вы рано за такие оптимизации взялись :-)

Sequence_point популярно для начала.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2013, 13:23
Сообщение #50


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Гнаться за мнимым весом строки - позор sm.gif
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 25 2013, 13:43
Сообщение #51


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Хех.
Цитата(С99)
6.5.16 Assignment operators
Syntax
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
assignment-operator: one of
= *= /= %= += -= <<= >>= &= ^= |=
...

Semantics
3 An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment, but is not an lvalue. The type of an assignment expression is the type of the left operand unless the left operand has qualified type, in which case it is the unqualified version of the type of the left operand. The side effect of updating the stored value of the left operand shall occur between the previous and the next sequence point.


Цитата(C++11)
5.17 Assignment and compound assignment operators
...
In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.
Это они сводят поведение assignment operators для POD к поведению перегруженных операторов для классов (которые есть функции и уж точно завершат запись до возврата значения)?

Свежий стандарт C (не С++) у кого-то есть? Недавно и C обновили, не только С++


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 25 2013, 14:07
Сообщение #52


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Наверное, цитата по ссылке
At the end of a full expression. This category includes expression statements (such as the assignment a=b;)
говорит, что любое ^= создает sequence point.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 25 2013, 16:10
Сообщение #53


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Не говорит. В "например" определяющей является точка с запятой, заканчивающая утверждение, а не присваивающий оператор, являющийся вместе со своими операндами выражением.
Цитата
6.8 Statements and blocks
Syntax
1
statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement

4 A full expression is an expression that is not part of another expression or of a declarator.
Each of the following is a full expression: an initializer; the expression in an expression
statement;
the controlling expression of a selection statement (if or switch); the
controlling expression of a while or do statement; each of the (optional) expressions of
a for statement; the (optional) expression in a return statement. The end of a full
expression is a sequence point.

6.8.3 Expression and null statements
Syntax
expression-statement:
expressionopt ;
Т.е. expression в данному случае превращается в full expression путём участия в expression statement при помощи завершения символом
;
т.е.:
a = b = c = d; Это один expression-statement, превращает в full-expression всё a = b = c = d
Cостоящее из нескольких subexpression.

Может, в С++, особенно в C++11, что-то и не так, я туда ещё так не вчитывался.
Какие-то моменты, undefined в C, стали unspecified в C++, с этими их тонкостями ещё пойди разберись.

Да, кстати, я не подчеркнул отдельно
Цитата( @ Jan 25 2013, 13:11) *
как можно простенькие такие программки потестить?

Вот ответ, разными компиляторами можно:

http://liveworkspace.org

Причём не только C/C++.
В ответ на кусок кода вся диагностическая выдача компилятора (в зависимости от ключей) и, при создании исполняемого файла, выдача на stdout


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 28 2013, 14:11
Сообщение #54


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Вот еще вариант. В основе смелая идея (уже ранее высказанная) о том чтоб испоьзовать буфер, но я немного переосмыслил это дело sm.gif

Код
#include <stdio.h>
#define MAX_LEN 100

char * reverse ( char *s ) {
   static char buf[MAX_LEN];
   char *buf_pointer = &buf[MAX_LEN-1];

   while ( (*buf_pointer-- = *s++) )  // компилятор попросил о 2х скобках, ну раз ему так легче, то пусть будут:)
;
   return buf_pointer+2;
}

int main() {
   char s[]= "Hello World!";
   printf("%s\n", reverse (s) );

}


Код
stdout:
!dlroW olleH


Итак, я считаю что с задачей А мы справились. Плавно переходим к задаче Б..

Задача Б
В этой реализации мне не нравится, что в случае дефолта сначала проверится один кейс, затем другой и только потом собственно выполнится подходящее действие! Что если нужно например месяца из чисел в названия переводить или там справочные данные какие?
Потом мне непонятно почему нужно static const char strue[]="бла-бла-бла"; делать!? Это в смысле что строки в памяти программ расположатся? Как с доступом к таким значениям? не будет страдать производительность?

Код
static const char strue[]="TRUE";
static const char sfalse[]="FALSE";
static const char sndef[]="OUT OF RANGE";
switch(boolean)
{
  case true:
   return &strue;
  case false:
   return &sfalse;
  default:
   return &sndef;
}


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
xemul
сообщение Jan 28 2013, 14:46
Сообщение #55



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(Буратино @ Jan 28 2013, 18:11) *
Итак, я считаю что с задачей А мы справились.

Для таких программ потом и пишут заплатки на тему переполнения какого-нить буфера.
Цитата
Потом мне непонятна почему нужно static const char strue[]="бла-бла-бла"; делать!?

static - чтобы можно было вернуть из функции указатель на что-то вменяемое, const - считайте просто правилом хорошего тона.
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 28 2013, 14:52
Сообщение #56


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(xemul @ Jan 28 2013, 18:46) *
Для таких программ потом и пишут заплатки на тему переполнения какого-нить буфера.

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


Для этой задачи оптимальным наверное будет сочетание двух подходов: в случае если длина строки не более чем MAX_LEN использовать один подход, если больше - второй, и менять данные прямо по месту. Я пока еще не придумал как красиво пофиксить переполнение буфера ибо нужно на каждой итерации проверять условие достижения конца буфера, а мне не оч. такой вариант.


Вот у меня тоже static, но при этом данные в массиве указателей описаны внутри функции, вроде так логичнее получается ,зачем выносить их наружу меняя область действия?
Код
char *b2s (char b) {
   static char *name[] = {"Out Of Range", "False", "True"};
   return (b < 0 || b > 1) ? name[0] : name [b+1];
}


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 28 2013, 15:04
Сообщение #57


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Буратино @ Jan 28 2013, 16:11) *
Итак, я считаю что с задачей А мы справились.
Поосторожнее… А то сейчас набегут спецы, которые сначала скажут, что возвращать указатель на внутренний статический буфер нельзя, потом скажут, что они имели ввиду, что оно-то можно, но глюкодром. А на вопрос, чем именно
Код
const char *foo()
{
    static char buf[10];
    ...
    return buf;
}
глюкодромее
Код
const char *moo()
{
    return "bla-bla-bla";
}
просто не будут отвечать по существу.
Недостаток у способа один:
Код
char str1[] = "String 1";
char str2[] = "String 2";
printf("%s %s\n", reverse(str1), reverse(str2));
Впрочем, для таких случаев мои функции подобного типа принимают второй аргумент (со значением по умолчанию в C++), которым программа, имеющая желание в одни заход получить несколько строк, обязан апередать буфер достаточного размера:
Код
const char *reverse(const char *src, char *tmpbuf = 0)
{
    static char inernal_buf[сикоку_не_жаль];
    if (!tmpbuf) tmpbuf = internal_buf;
    …
    return tmpbuf; // или что там надо по алгоритму
}
В итоге в большинстве случаев вызывается reverse(some_string); (второй аргумент по умолчанию подставляется 0), и только в отдельных случаях подставляется доп. буфер.

Однако задача в некотором смысле не решена и не может быть решена без уточнения условий и целей.
Например, если цель — скорость, а строки преимущественно «достаточно длинные», а процессор Cortex-M3 или другой, имеющий команду реверся байтов в 32-битном слове (i486+), то стоит подумать о зачитывании по 32 бита, реверсе порядка байтов соответствующей командой и т.п. Соответственно, с выделением места под буфер кратно 4 байтам + под концевой 0, спецобработкой хвоста из 1..3 символов и возвратом указателя на tmp_buf с нужным смещением.
«Если Вы не указали цель оптимизации, то Вам всё равно, как писать код» © Чеширсикй Кот – программист.

Цитата(Буратино @ Jan 28 2013, 16:11) *
Это в смысле что строки в памяти программ расположатся? Как с доступом к таким значениям? не будет страдать производительность?
По простому const объекты расположатся в памяти программ только у тех процессоров, у которых память программ и память данных находятся в одном и том же адресном пространстве.
(чтобы не повторяться)

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


Цитата(xemul @ Jan 28 2013, 16:46) *
Для таких программ потом и пишут заплатки на тему переполнения какого-нить буфера.
Я надеюсь, высказывание касается только того, что перед реверсом либо в процессе оного не проверияется длина строки. Само по себе наличие промежуточного буфера фиксированного размера к ошибкам переполнения буфера не приводит.



Цитата(Буратино @ Jan 28 2013, 16:52) *
Вот у меня тоже static, но при этом данные в массиве указателей описаны внутри функции, вроде так логичнее получается ,зачем выносить их наружу меняя область действия?
Код
char *b2s (char b) {
   static char *name[] = {"Out Of Range", "False", "True"};
   return (b < 0 || b > 1) ? name[0] : name [b+1];
}
Да, лучше внутри функции.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
xemul
сообщение Jan 28 2013, 16:10
Сообщение #58



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(ReAl @ Jan 28 2013, 19:04) *
Я надеюсь, высказывание касается только того, что перед реверсом либо в процессе оного не проверияется длина строки.

Безусловно.
Т.к. в условии задачи не сказано, что исходная строка должна сохраниться, я бы делал реверс на месте. Цена вопроса - один strlen(). (оно, конечно, не спасёт, если строка вдруг окажется без '\0')
Цитата
Само по себе наличие промежуточного буфера фиксированного размера к ошибкам переполнения буфера не приводит.

К переполнению, естественно, не приведёт. Но если память (опять же вдруг) закончится...

За жисть. У меня K&R был первого советского издания (в мягком переплёте, голубая обложка), не помню в нём таких упражнений. Хотя, может опять склероз буйствует.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jan 28 2013, 18:45
Сообщение #59


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(xemul @ Jan 28 2013, 18:10) *
Т.к. в условии задачи не сказано, что исходная строка должна сохраниться, я бы делал реверс на месте. Цена вопроса - один strlen(). (оно, конечно, не спасёт, если строка вдруг окажется без '\0')
Так в том-то и дело, что в условии задачи не сказано ничего (см. выше про Чеширского Кота – программиста). Как я говорил дочери, когда в школе на информатике пошёл паскаль, — программу можно оптимизировать на скорость написания, на простоту отладки, на скорость выполнения, на минимальный размер, на скорость понимания другим человеком, …
«Множество чего? Просто множество!» (что-то меня на Алису потянуло) «просто оптимизировать» невозможно.

Цитата(xemul @ Jan 28 2013, 18:10) *
За жисть. У меня K&R был первого советского издания (в мягком переплёте, голубая обложка), не помню в нём таких упражнений. Хотя, может опять склероз буйствует.
У меня был K&R, любовно кем-то подготовленный (фигурные скобки сделаны из круглых с надпечаткой поверх минусом, ключевые слова двойной печатью, …) и напечатанный на барабанном АЦПУ, переплетённый в переплётной мастерской (кажись, в один заказ с дипломной работй жены, тогда это 1987 год). Тоже таких упражнений не помню :-)


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jan 29 2013, 08:24
Сообщение #60


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(xemul @ Jan 28 2013, 19:10) *
У меня K&R был первого советского издания (в мягком переплёте, голубая обложка), не помню в нём таких упражнений. Хотя, может опять склероз буйствует.

Во втором издании (в мягком переплете, белая обложка, голубая буква С) есть упражнения по переворачиванию строки.
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 29 2013, 14:52
Сообщение #61


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Задача А. Работа над ошибками так сказать..
В этой версии маленькие строки (меньше LEN_BUF байт) копируются в обратном порядке в буфер и возвращается указатель на голову, а если строки большие, то перестановками решаем. Во втором варианте проверям чтоб строка не слишком большой была (меньше MAX_LEN_STR)
Код
#include <stdio.h>

#define  LEN_BUF        100
#define  MAX_LEN_STR    1000

#define  _LenStr        buf[LEN_BUF-1]    // для хранения длины строки
#define  _TmpChar       buf[LEN_BUF-2]    // для хранения временных значений


char * reverse ( char *s ) {

   static char buf[LEN_BUF];              // буфер данных
   char *buf_pointer = &buf[LEN_BUF-1];   // определяем указатель, инициализируем значением адреса

   char *beg = s;                         // определяем указатель, инициализируем адресом начала строки
   char *end;

   while ( (*buf_pointer-- = *s++) ) {    // копипастим
      
      if (buf_pointer <= &buf[0]) {       // если строка больше, чем буфер, то:
              
         while (*++s)
        ;    
                
         if (s - beg > MAX_LEN_STR)
            return "Error, overflow!";

         _LenStr = s - beg;               // Вычисляем длинну строки
         end = s-1;                       // Указатель на конец строки
        
         do {                             // Меняем местами данные:
            _TmpChar = *beg;
            *beg = *end;
            *end = _TmpChar;
         } while (++beg < --end);
        
         return s - _LenStr;
      }
   }  

   return buf_pointer+2;
}


int main() {
   char s[]= "http://www.youtube.com/watch?v=cZjx6ItATW4";
   printf("%s\n", reverse (s) );
}



Не ясно еще как все же быть с одновременным вызовом функций
Код
char str1[] = "String 1";
char str2[] = "String 2";
printf("%s %s\n", reverse(str1), reverse(str2));

Вариант который предлагает ReAl требует введения второго аргумента, что не очень айс


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 29 2013, 15:16
Сообщение #62


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



О майн Готт! Вы на листинг этого чуда хоть смотрели?
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 29 2013, 15:43
Сообщение #63


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Цитата(_Pasha @ Jan 29 2013, 18:16) *
О майн Готт! Вы на листинг этого чуда хоть смотрели?


неа, не смотрел. а что там такого страшного?
последний вариант лучше предыдущих тем. что небольшие строки перевернутся без вызова strlen ,ведь даже в вашем варианте нужно вызвать strlen, а потом до половины размера строки ворочать значения. При варианте с буфером я НЕ вызываю strlen и получаю строку в доп. буфере, однако при большой строке переворачиваю строку без буфера, но при этом strlen также не пользую.


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 29 2013, 15:55
Сообщение #64


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Буратино @ Jan 29 2013, 19:43) *
неа, не смотрел. а что там такого страшного?
последний вариант лучше предыдущих тем. что небольшие строки перевернутся без вызова strlen ,ведь даже в вашем варианте нужно вызвать strlen, а потом до половины размера строки ворочать значения. При варианте с буфером я НЕ вызываю strlen и получаю строку в доп. буфере, однако при большой строке переворачиваю строку без буфера, но при этом strlen также не пользую.

Ниасилил. Strlen() хоть вызывай, хоть делай сам - оно выглядит одинаково.
Чем, извините, это всё лучше, если оно жрет памяти вдвое больше, не заточено под ASCIIZ, в >3раза больше число итераций. О майн Готт! crying.gif
Go to the top of the page
 
+Quote Post
xemul
сообщение Jan 29 2013, 16:01
Сообщение #65



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



K&R всплакнули бы от умиления...
Есть такая прилада профайлер, которая позволяет оценить время выполнения кода. Сравните результаты Вашей программы и поминавшихся выше вариантов со strlen().
Про наглядность кода и разбазаривание памяти ... пусть будет Задачей №3.

И попробуйте
Код
int main() {
   char s[]= "http://www.youtube.com/watch?v=cZjx6ItATW4";
   char s1[]= "Пачиму-то не работает";
   printf("%s\n", reverse (s) );
   printf("%s\n", reverse (s1) );
}


UPD: сделайте s1 > LEN_BUF
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 29 2013, 16:25
Сообщение #66


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



_Pasha , функция работает в двух так сказать режимах:
а) когда входная строка меньше по длине чем LEN_BUF
б) когда входная строк больше, чем LEN_BUF

в варианте "а" strlen не вызывается, но при этом крутится вся строка
в варианте "б" strlen не вызывается, но выполняются действия аналогичные по смыслу. после этого строка перебирается и меняются местами данные, кол-во итераций длина строки/2. Вот как и у вас по сути.

последняя реализация лучше тем ,что если на входе функции будут разные данные ,то в общем итоге получается оптимальнее!
И обратите внимание - алгоритм "б" дополняет собой алгоритм "а" !

Цитата(xemul @ Jan 29 2013, 19:01) *
K&R всплакнули бы от умиления...
Есть такая прилада профайлер, которая позволяет оценить время выполнения кода. Сравните результаты Вашей программы и поминавшихся выше вариантов со strlen().
Про наглядность кода и разбазаривание памяти ... пусть будет Задачей №3.


Я согласен. Предлагаю обсудить условия проведения соревнования на скорость и денежные призы. Итак!?





Цитата(xemul @ Jan 29 2013, 19:01) *
И попробуйте
Код
int main() {
   char s[]= "http://www.youtube.com/watch?v=cZjx6ItATW4";
   char s1[]= "Пачиму-то не работает";
   printf("%s\n", reverse (s) );
   printf("%s\n", reverse (s1) );
}


ну не знаю ,кажись работает:

Код
  char s[]= "http://www.youtube.com/watch?v=cZjx6ItATW4";
   char s1[]= "http://www.ebay.com/sch/i.html?_from=R40&_sacat=0&_nkw=pl-660&_sop=15";
   printf("%s\n", reverse (s) );
   printf("%s\n", reverse (s1) );


Код
stdout:
4WTAtI6xjZc=v?hctaw/moc.ebutuoy.www//:ptth
51=pos_&066-lp=wkn_&0=tacas_&04R=morf_?lmth.i/hcs/moc.yabe.www//:ptth


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
xemul
сообщение Jan 29 2013, 16:33
Сообщение #67



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Код
int main() {
   char s[]= "http://www.youtube.com/watch?v=cZjx6ItATW4";
   char s1[]= "Пачиму-то не работает 1234567890 1234567890 1234567890 1234567890  1234567890 1234567890 1234567890 1234567890 1234567890 1234567890";
   printf("%s\n", reverse (s) );
   printf("%s\n", reverse (s1) );
}

D:\Work\Soft\Test>a
4WTAtI6xjZc=v?hctaw/moc.ebutuoy.www//:ptth
,=
Go to the top of the page
 
+Quote Post
Буратино
сообщение Jan 29 2013, 17:09
Сообщение #68


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215




Код
#define  LEN_BUF        10

stdout:
4WTAtI6xjZc=v?hctaw/moc.ebutuoy.www//:ptth
0987654321 0987654321 0987654321 0987654321 0987654321 0987654321 0987654321 0987654321 0987654321 1111111111111111111111


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
Буратино
сообщение Feb 27 2013, 20:10
Сообщение #69


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Есть указатель на указатель на char:
Код
char **argv;

Как и чем его можно инициализировать и как (для чего) можно потом использовать? Что будет если я буду инкрементировать такой указатель на указатель?
К сож. с языком знакомлюсь рывками и че та совершенно запуталсяsad.gif


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
igorle
сообщение Feb 27 2013, 21:03
Сообщение #70


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



обычно это имя переменной, которую получает main. Это массив указателей на строки - аргументы командной строки. В паре к ней идет argc - количество элементов в массиве.

Код
void foo1(int argc, char **argv)
{
    while (argc--)
        printf("\"%s\"\n", argv++);
}

void foo(void)
{
    char *my_argv[] = {"Hello", "World", "one", "two", "four"};

    foo1(5, my_argv);
Go to the top of the page
 
+Quote Post
toweroff
сообщение Feb 27 2013, 21:08
Сообщение #71


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Да поправят меня, если не прав sm.gif
Указатель передается обычно тогда, когда функция может менять какие-то данные за пределами себя
Указатель за пределами какой-то функции тоже можно менять, не так ли? вот и передается указатель на этот указатель
Go to the top of the page
 
+Quote Post
Lotor
сообщение Feb 28 2013, 04:17
Сообщение #72


Местный
***

Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866



Цитата(toweroff @ Feb 28 2013, 01:08) *
Да поправят меня, если не прав sm.gif
Указатель передается обычно тогда, когда функция может менять какие-то данные за пределами себя
Указатель за пределами какой-то функции тоже можно менять, не так ли? вот и передается указатель на этот указатель

Вы правы - при реализации связных списков, например, именно для этих целей передают указатель на указатель.


--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
Go to the top of the page
 
+Quote Post
igorle
сообщение Feb 28 2013, 06:45
Сообщение #73


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата(toweroff @ Feb 28 2013, 01:08) *
Да поправят меня, если не прав sm.gif

Формально - прав. Фактически - нет. Поправляю.
Вопрос был о char **argv.
Есть такая штука, как code convention. Именем argv принято обозначать статический массив указателей на строки. Поэтому упаси бог использовать его по тому же принципу, как используют при работе со списками. Например, здесь переменную answer назвать argv нельзя из соображений личной безопасности:

Код
void true_of_false(char **answer, int is_true)
{
    *answer = is_true ? "True" : "False";
}

void foo(void)
{
    char *b_char;

    true_of_false(&b_char, 2013);
    printf("He said %s %s %s!\n", b_char, b_char, b_char);
}


Сообщение отредактировал igorle - Feb 28 2013, 06:46
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Feb 28 2013, 07:06
Сообщение #74


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(igorle @ Feb 28 2013, 10:45) *
То что вы написали тут формально и гарантированно работать не будет ИМХО.
Т.к. вы инициализируете указатель адресом локальной не статической строки и используете этот указатель вне области жизни этих строк (в другом стековом фрейме).
Вот так все формальности будут соблюдены:

Код
void true_of_false(char **answer, int is_true)
{
    static char True[]  = "True";
    static char False[] = "False";

    *answer = is_true ? True : False;
}

Хотя набрёл тут на такое:
Цитата
4. Строковой литерал во всех прочих случаях
Во всех прочих случаях строковой литерал трактуется как НЕявно заведённый статический константный объект типа массив char'ов, инициализированный символами данного строкового литерала с включением неявного завершающего нуля, и далее взятие адреса на нулевой элемент данного объекта.
и немного из другой плюсатой оперы
Цитата
"Память под строковые литералы выделяется статически, поэтому их возврат из функций безопасен" Б. Страуструп

Захотелось найти это в первоисточнике....


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
igorle
сообщение Feb 28 2013, 07:37
Сообщение #75


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата(demiurg_spb @ Feb 28 2013, 10:06) *
То что вы написали тут формально и гарантированно работать не будет ИМХО....


Это таки будет работать гарантировано. Потому что моя функция возвращает указатели на read only строки из секции data
Ваша функция тоже будет работать, но в ней есть бесполезное копирование строк из read only секции data в read write секцию. Недостатки
- в два раза увеличился объем памяти
- нет защиты от случайного изменения текста (оно в данном случае не желательно)

Посмотрите здесь

Ну и посыпаю голову пеплом по поводу опечатки в названии функции. Должно было быть true_or_false. Хотя так даже прикольно получилось, многозначительно.

Сообщение отредактировал igorle - Feb 28 2013, 07:34
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Feb 28 2013, 07:39
Сообщение #76


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



На платформе АVR и так и сяк будет двойной расход памяти flash + копия в озу пока явно не зададим __flash.
Это так к слову...

Цитата(igorle @ Feb 28 2013, 11:37) *
Посмотрите здесь
Это объяснение не на том уровне. Хотелось бы в контексте Си стандарта...


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
igorle
сообщение Feb 28 2013, 07:45
Сообщение #77


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата(demiurg_spb @ Feb 28 2013, 10:39) *
На платформе АVR и так и сяк будет двойной расход памяти flash + копия в озу пока явно не зададим __flash.
Это так к слову...

На MSP430 - все литеральные строки хранятся во флэше. А для инициализированных массивов, если я не хочу переносить их п память, достаточно добавить const

Попутно. Оффтопик. Как вам удается редактировать свои сообщения, без того чтобы было написано "изменен тогда-то и тем-то"?
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Feb 28 2013, 07:58
Сообщение #78


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(igorle @ Feb 28 2013, 11:45) *
На MSP430 - все литеральные строки хранятся во флэше. А для инициализированных массивов, если я не хочу переносить их п память, достаточно добавить const

Это всё понятно. У MSP430 единое адресное пространство - просто и удобно... И про повсеместный static const я как бы тоже в теме. Меня интересует конкретный отсыл в стандарт и только...
Цитата
Попутно. Оффтопик. Как вам удается редактировать свои сообщения, без того чтобы было написано "изменен тогда-то и тем-то"?
Также как и вам. Нажимаю редактировать -> быстрое...

В avr-gcc вообще все очень непросто со строковыми литералами.
Можете почитать нашу дискуссию на сей счёт: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56263
И был бы очень рад если ещё кто-то меня поддержит в ней!


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
igorle
сообщение Feb 28 2013, 08:27
Сообщение #79


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата(demiurg_spb @ Feb 28 2013, 10:58) *
Также как и вам. Нажимаю редактировать -> быстрое...

Я так делаю - обязательно пишет что меняли текст.

Цитата
Можете почитать нашу дискуссию на сей счёт

Почитал. Познавательно. Я сам с AVR не работаю.
Go to the top of the page
 
+Quote Post
XVR
сообщение Feb 28 2013, 08:29
Сообщение #80


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата(demiurg_spb @ Feb 28 2013, 11:39) *
Это объяснение не на том уровне. Хотелось бы в контексте Си стандарта...
Запросто - С99 стандарт, глава 6.4.5 (String Literals), параграф 5
Цитата
In translation phase 7, a byte or code of value zero is appended to each multibyte
character sequence that results from a string literal or literals. The multibyte character
sequence is then used to initialize an array of static storage duration and length just
sufficient to contain the sequence.
Так что возвращать из функции можно biggrin.gif
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Feb 28 2013, 08:33
Сообщение #81


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(XVR @ Feb 28 2013, 12:29) *
О! Вот это вразумительно!
Спасибо! Приятно осознавать что ты поумнел после содержательной беседы. Серьёзно.
Отдельное спасибо igorle!


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
toweroff
сообщение Feb 28 2013, 08:48
Сообщение #82


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(igorle @ Feb 28 2013, 12:27) *
Я так делаю - обязательно пишет что меняли текст.

если после поста были добавлены посты других участников, то добавляется информация о редактировании. Возможно, на случай, что ваш пост процитировали, а вы потом что-то в нем поменяли
Если ваш пост последний - можно редактировать без опасения того, что информация о редактировании появится. Это касается конкретно этого форума. На других встречал упоминание о редактировании вне зависимости от других постов, причем даже была информация о всех редактированиях поста
Go to the top of the page
 
+Quote Post
Буратино
сообщение Feb 28 2013, 12:11
Сообщение #83


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



igorle ,вы привели программу
Код
void foo1(int argc, char **argv)
{
    while (argc--)
        printf("\"%s\"\n", argv++);
}

void foo(void)
{
    char *my_argv[] = {"Hello", "World", "one", "two", "four"};

    foo1(5, my_argv);
}


Мне кажется, что argv не указатель на указатель, скорее это указатель на массив указателей ! И в аргументах функции foo1 правильнее будет записать *argv[] вместо **argv
И в том виде в котором Вы запостили, код не компилится и нужно либо в аргументах printf разыменовывать argv либо использовать квадр. скобки и индекс для каждого элемента массива.

Мне больше нравится вот так:
Код
void foo1(char *argv[]) {
   while (*argv)
      printf("\"%s\"\n", *argv++);
}

int main(void) {
  
   char *my_argv[] = {"Hello", "World", "one", "two", "four", NULL};
   foo1(my_argv);
}


Мы подчеркнули природу аргумента функции foo1 ,но вынуждено используем "указательные" св-ва масива для упорядоченного, с начала в конец, вывода элементов на "печать".

Кароче трудно как-то все получаетсяsad.gif


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
igorle
сообщение Feb 28 2013, 13:49
Сообщение #84


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата
Мне кажется, что argv не указатель на указатель, скорее это указатель на массив указателей ! И в аргументах функции foo1 правильнее будет записать *argv[] вместо **argv

С точки зрения языка С, в данном случае (для прототипа функции), обе записи равнозначны. Используйте то, что вам понятнее.
Со временем придет "чуство" того, что имя массива и указатель - это одно и то-же.
Цитата
... код не компилится ...

Да, это я ошибся. Нужно *argv++
Ваш вариант, с последним элементом NULL, правильный, тем более что функция main действительно получает массив argv размером на единицу больше, чем argc, с NULL терминатором.

Цитата
Мы подчеркнули природу аргумента функции foo1 ,но вынуждено используем "указательные" св-ва масива для упорядоченного, с начала в конец, вывода элементов на "печать".

Короче, трудно как-то все получаетсяsad.gif

Массив и указатель - близнецы братья. При использовании - это одно и то-же. Немного практики, и это станет простым и естественным. И будет непонятно, как некоторые языки не используют указатели. Верной дорогой идете!

Сообщение отредактировал igorle - Feb 28 2013, 13:50
Go to the top of the page
 
+Quote Post
Буратино
сообщение Feb 28 2013, 14:33
Сообщение #85


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Не думаю, что массив и указатель одно и то же. Указатель это переменная, а массив это массив. Существует тесная, родственная связь механизма доступа к данным в массиве по индексам, и адресной арифметикой указателей, но это все же разные вещи.

Я спрашивал именно о указателе на указатель. Дело в том что гуглится что-то невразумительное на этот счет. В К&R нет подробного освещения вопроса. Уповаю на ваш експириентс. Спасибо!


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
igorle
сообщение Feb 28 2013, 14:52
Сообщение #86


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Указатель и массив - это не одно и то же. Но имя массива - это указатель на первый его элемент
a[0] то же самое что и *a
a[10] то же самое что и *(a+10)

Понятно, что при определении переменной
int a[] и int *b - разные вещи. Но после этого они во многом ведут себя одинаков. Во многом, но не во всем. a нельзя присваивать новое значение, b - можно.

int a[10];
int *b = a;

Теперь все, что вы хотите делать с a, вы можете делать с b. Обратное не верно
Например b[2] - это то-же самое что и a[2].

Я считаю, что это из области, где легче понять чем объяснить. Даже гугл не поможет. И приходит только с небольшим опытом. Просто поиграйте с указателями. Потом - с указателями на указатели. Это действительно просто. Наш экспириенс не поможет. Можете придумыват, писать и компилировать простые примеры из нескольких строк, и задавать конкретные вопросы если не работает. Когда поймете то что говорили про указатели и массивы - посмотрите примеры про обработку связных списков. Там указатели на указатели очень эффективно работают.

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

Сообщение отредактировал igorle - Feb 28 2013, 14:54
Go to the top of the page
 
+Quote Post
Tahoe
сообщение Mar 1 2013, 02:45
Сообщение #87


Местный
***

Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600



Цитата(igorle @ Feb 28 2013, 18:52) *
Указатель и массив - это не одно и то же. Но имя массива - это указатель на первый его элемент

Дьявол в мелочах (с).
Тот случай, когда пренебежение терминологией, привело к не верному выводу. А именно, "указатель" != "адрес". Имя массива - не "указатель" на первый элемент, а "адрес" первого элемента.

P.S.
Оказывается, объяснить тоже не сложно. wink.gif
Go to the top of the page
 
+Quote Post
Буратино
сообщение Mar 2 2013, 08:01
Сообщение #88


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Я вот думаю, что указатель на указатель используется только как формальный аргумент функции. А в качестве фактического аргумента используют адрес простого указателя. Не вижу смысла в использовании указателя на указатель где-то еще. Естественно могу ошибаться.

Скажите, а где можно посмотреть реализацию отдельных функций описаных в заголовочном файле string.h ?


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
igorle
сообщение Mar 2 2013, 10:41
Сообщение #89


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата(Буратино @ Mar 2 2013, 11:01) *
Скажите, а где можно посмотреть реализацию отдельных функций описаных в заголовочном файле string.h ?

http://www.uclibc.org/

http://git.uclibc.org/uClibc/tree/libc/string
Go to the top of the page
 
+Quote Post
XVR
сообщение Mar 2 2013, 14:39
Сообщение #90


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата(Буратино @ Mar 2 2013, 12:01) *
Я вот думаю, что указатель на указатель используется только как формальный аргумент функции. А в качестве фактического аргумента используют адрес простого указателя. Не вижу смысла в использовании указателя на указатель где-то еще.
Многомерный динамический массив.
Код
int** GenerateArray(int dim1, int dim2)
{
int** rv=new int*[dim1];
for(int i=0;i<dim1;++i)
  rv[i]=new int[dim2];
return rv;
}


// Usage:

int dim1=5;
int dim2=10;

int** my_array=GenerateArray(dim1,dim2);

for(int i=0;i<dim1;++i)
for(int j=0;j<dim2;++j)
   my_array[i][j] = ...

Go to the top of the page
 
+Quote Post
igorle
сообщение Mar 2 2013, 14:51
Сообщение #91


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата(XVR @ Mar 2 2013, 18:39) *
Код
    int dim1=5;
    int dim2=10;

    int** my_array=GenerateArray(dim1,dim2);

    my_array[i][j] = ...


Забавно. Никогда так не делал. Первая реакция была - "ерунда". Потом подумал - а ведь должно работать....

Сообщение отредактировал igorle - Mar 2 2013, 14:56
Go to the top of the page
 
+Quote Post
XVR
сообщение Mar 2 2013, 19:43
Сообщение #92


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата(igorle @ Mar 2 2013, 18:51) *
Забавно. Никогда так не делал. Первая реакция была - "ерунда".
Это один из классических способов реализаций многомерных динамических массивов (я бы даже сказал, что самый первый из классических)

Go to the top of the page
 
+Quote Post
Буратино
сообщение Mar 2 2013, 22:07
Сообщение #93


Профессионал
*****

Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215



Да, оч. интересно! Правда не совсем ппонимаю, как освобождать память из под такого массивчика? sm.gif
Если указатель связанный с данными через "new" погибнет, потеряется - память "потечет"!?

Если я использую библиотечные функции, ну например "strcat" библиотеки cLib, прототип описан в string.h, выделить память для результирующей строки должен программист? о_О

Код
/*
* Copyright (C) 2002     Manuel Novoa III
* Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
*
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/

#include "_string.h"

#ifdef WANT_WIDE
# define Wstrcat wcscat
#else
# define Wstrcat strcat
#endif

Wchar *Wstrcat(Wchar * __restrict s1, register const Wchar * __restrict s2)
{
    register Wchar *s = s1;

    while (*s++);
    --s;
    while ((*s++ = *s2++) != 0);

    return s1;
}
libc_hidden_def(Wstrcat)


--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Mar 3 2013, 07:16
Сообщение #94


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Tahoe @ Mar 1 2013, 04:45) *
Дьявол в мелочах (с).
Вот именно™
Цитата(Tahoe @ Mar 1 2013, 04:45) *
Тот случай, когда пренебежение терминологией, привело к не верному выводу. А именно, "указатель" != "адрес". Имя массива - не "указатель" на первый элемент, а "адрес" первого элемента.
Имя массива — это имя массива. Оно имеет тип «массив вон-того» (в зависимости от объявления).
Почти во всех выражениях оно автоматически приводится к указателю на первый элемент.
Цитата(C99)
6.3 Conversions
...
6.3.2 Other operands
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
igorle
сообщение Mar 3 2013, 07:22
Сообщение #95


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата(XVR @ Mar 2 2013, 23:43) *
Это один из классических способов реализаций многомерных динамических массивов (я бы даже сказал, что самый первый из классических)

Я считаю что хороший способ запутать (и запугать) новичка. Вы должны теперь объяснить, что my_array и your_array следующем примере:
Код
int** my_array=GenerateArray(6, 9);
int  your_array[6][9];

это две большие разницы. И вообще эти переменные - разного типа. Это неочевидно ученику.
Давайте спросил Буратино (задачу решить на листочке, не используя компилятор):
- какого типа your_array?
- что вернет sizeof(my_array) и sizeof(your_array)?
- можно ли сделать такое присвоение int **his_array = your_array; ?
Go to the top of the page
 
+Quote Post
ReAl
сообщение Mar 3 2013, 07:25
Сообщение #96


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Буратино @ Mar 3 2013, 00:07) *
Да, оч. интересно! Правда не совсем ппонимаю, как освобождать память из под такого массивчика? sm.gif
«наоборотом». Сначала удалить по каждому из указателей из массива указателей, потом удалить по указателю на массив.

Такие массивы удобны тем, что каждая «строка» выделена отдельно и хранится отдельно. Можно менять месстами строки, перемещая только значения указателей, не трогая данные.

Например, было актуально во времена «640 килобайт»
При фильтрации изображений, скажем, окном 3х3, можно выделить место на две дополнительных строки, начать фильтрацию в них. При получении третьей (номер 2) строки выходного изображения первая строка (номер 0) входного изображения уже не нужна, результат можно помещать в неё, потом в нужное место переписать указатель. В итоге через какое-то время строки изображений в памяти разбросаны как попало, но все работает :-)


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
igorle
сообщение Mar 3 2013, 07:38
Сообщение #97


Местный
***

Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753



Цитата
Если я использую библиотечные функции, ну например "strcat" библиотеки cLib, прототип описан в string.h, выделить память для результирующей строки должен программист? о_О

Да, и узнать это из исходников - похвальный, но не самый простой путь. Лучше читать man pages
Кстати - многие функции еще и не проверяют корректность параметров. Например strcat(NULL, "basa"); просто покрошится.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Mar 3 2013, 08:13
Сообщение #98


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(igorle @ Mar 3 2013, 09:22) *
это две большие разницы. И вообще эти переменные - разного типа. Это неочевидно ученику.
Давайте спросил Буратино
Давайте сначала Вы объясните ученику, как при помощи записи вида int your_array[что-то-одно][что-то-другое]; создать массив неизвестного заранее размера с времением жизни, выходящим за рамки функции, в которой он создан.

Был вопрос «зачем такое может быть нужно». Дан ответ. Дальше ученик должен думать. Различия можно объяснять.

Цитата(igorle @ Mar 3 2013, 09:22) *
- что вернет sizeof(my_array) и sizeof(your_array)?

sizeof(my_array) вернёт в точности то же самое, что тут вернёт sizeof(your_array)
Код
int foo(int your_array[6][9])
{
    return sizeof(your_array);
}
и всё равно придётся объяснять, почему sizeof(your_array) в двух разных местах возвращает разные значения.


Кстати, я считаю, что запись foo(char *arr[]) гораздо хуже, чем foo(char **arr).
В итоге-то одно и то же, у функций одинаковый прототип, принимают pointer to pointer to char.
В режиме компиляции С++ должно быть одинаковое mangled-имя.
В первой записи arr по сути тот же char **, только этого не видно (пресловутому ученику) и этот arr невозможно сделать константным.
foo(char const * const arr[])
Вот тут аж дальние char — константные. Указатели на них, хранящиеся в массиве, на который указывает аргумент arr (в С ведь массивы не передаются как параметры, не правда ли?) — тоже константные. А сам аргумент - не константный, хоть плачь.

Код
int foo(char const * const arr[])
{
        int i = 0;
        while( *arr++) ++i; // Тут всё отлчино!
        return i;
}

int moo(char const * const * const arr)
{
        int i = 0;
        while(*arr++) ++i; // А вот тут компилятор говорит об ошибке
        return i;
}
всё, что имеем:
Цитата
arrn.c: In function ‘moo’:
arrn.c:11: error: increment of read-only location ‘arr’

А с первой функцией все нормально, компилятор молчит.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Tahoe
сообщение Mar 3 2013, 08:53
Сообщение #99


Местный
***

Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600



Цитата(ReAl @ Mar 3 2013, 11:16) *
Имя массива — это имя массива. Оно имеет тип «массив вон-того» (в зависимости от объявления).Почти во всех выражениях оно автоматически приводится к указателю на первый элемент.

Ещё раз. Указатель, это переменная, занимающая место в памяти. Под адрес же, память не выделяется. Что там происходит дальше, на что похоже, как оптимизируется и т.п. - дело десятое.

Не знаю как сейчас, а еще 3-4 года назад тот же IAR/ARM, на максимальной оптимизации, генерил совершенно разный код в одном и том же цикле, для Array[i] и *(pArray+i). Т.е. работал совершенно по-разному ( через указатель гораздо быстрее ). "Хотя казалось бы..." (с). Пришлось ручками ковырять libavcodec, на предмет переделки обращения a[] в *pa, потому что иначе SAM7S64 не успевал размотать два канала честного ADPCM.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Mar 3 2013, 09:56
Сообщение #100


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Tahoe @ Mar 3 2013, 10:53) *
Ещё раз. Указатель, это переменная, занимающая место в памяти.
Ну хорошо.
«is converted to an expression with type ‘‘pointer to type’’»
приводится к выражению типа «указатель на»
Не к «переменной типа „указатель на”». А к выражению. Приводится, а не есть им.
Результат этого выражения может не сохраняться в памяти. Может сохраняться во временной переменной в регистре. Может в результате оптимизации сразу компилироваться в тело команды.
Но сначала имя массива приводится к указателю на. Везде, кроме & и sizeof.
Только в результате этого приведения выражения
Код
array[i]
и
Код
i[array]
эквивалентны.

Да, кстати. Возьмём char a, b;. Теперь возьмём выражение a+b.
Приянто говорить «перед сложением a и b приводятся к целому».
Вы и здесь будете говорить «Ещё раз. Целое это переменная, занимающая место в памяти.» ?
«Целое», «указатель на» — это типы. А не переменные этих типов.

Кстати, и «переменная типа „указатель на”» может не занимать место в памяти. И даже в регистре. После оптимизации, конечно.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post

19 страниц V   1 2 3 > » 
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 26th July 2025 - 12:00
Рейтинг@Mail.ru


Страница сгенерированна за 0.02714 секунд с 7
ELECTRONIX ©2004-2016