Loading...
zen00 avatar zen00 0 Точки

C++ / JA1-Task-1-Average-Color.cpp

Здрайте ,

Вероятно имам големи пропуски в началните стъпки тъй като не мога да си обясня следното :) :      


 46     for ( int i=0; i<6 ; i+=2 ) {                                               
 47         char firstPair [7];                                                     
 48         char secondPair [7];                                                    
 49         std::strncat(firstPair,&digitOne[i],1);                                 
 50         std::strncat(firstPair,&digitOne[i+1],1);                               
 51         int firstR = std::stoi (firstPair,nullptr,16);                          
 52         std::strncat(secondPair,&digitTwo[i],1);                                
 53         std::strncat(secondPair,&digitTwo[i+1],1);                              
 54         int secondR = std::stoi (secondPair,nullptr,16);                        
 55         std::cout << firstPair << " + "<< secondPair << std::endl;              
 56         std::cout << firstR << " + " << secondR << std::endl;                   
 57     }

Защо под ягодите ;) се случва това  а не се инициализира нов char array всеки път ?

#2b00b5 #0ff1ce
2b + 0f
43 + 15
2b00 + 0ff1
11008 + 4081
2b00b5 + 0ff1ce
2818229 + 1044942

Поздрави!

Тагове:
0
C++ Programming
georgi.stef.georgiev avatar georgi.stef.georgiev 921 Точки

Здравей,

Основният проблем идва от това, че предполагаш, че като направиш char arr[7]; този масив се инициализира с 0-ли целия. Доста пъти вече по лекциите казахме, че в C++ ако не кажеш изрично, че трябва да се занули масива - той няма да се занули (същото като ако направиш char a;, в това "a" може да има всичко, защото не си му казал колко е). Това, което виждаш да се случва е недефинирано поведение, но в твоя случай (и в повечето случаи с този тип масив използван в цикъл), това, което става, е че тези char масиви попадат на същото място в паметта при всяко изпълнение на цикъла (защото всеки път се освобождават и веднага след като се освободят се заделят нови). Оттам, понеже не ги зануляваш, на практика се оказва, че просто на всеки цикъл записваш в следващите позиции от паметта, а предишните позиции се преизползват, защото масивите ти винаги се оказват да почват от една и съща позиция в паметта. Нарисувай си на един лист на всяка итерация на цикъла какво става с масивите, а масивите ги нарисувай като правоъгълници в най-лявата част на листта. Най-вероятно си помисли да ги нарисуваш всяка итерация на нов ред, нали? Е, не, C++ няма причина да рисува на нов ред, защото той знае, че първия ред вече не се ползва и може да си пренарисува масива отгоре върху него. Само че като пренарисува не ползва гумичка да изтрие предишните стойности, защото не си му казал. strncat почва да прикача след края на destination стринга, а края му се определя от това какво е станало на предишната итерация, заради факта, че не си занулил паметта, която ти се пада същата всеки път.

Ако искаш да ползваш char масив който е занулен, трябва да ползваш char arr[7] = {}; (или char arr[7] {}), тъй като в тези скоби (initializer list) числата се присвояват на елементите на масива, а всеки елемент, за който няма число, му се поставя нула (говорили сме за това).

Това беше обяснението защо работи така, но като цяло ми се струва, че правиш излишни неща в това решение. Най-вече, защо правиш масиви от 7 елемента, след като ползваш само по 2 символа всеки път (т.е. 3 с null-terminator-а)? Ако масивите ти бяха по 2 елемента и винаги записваше на тях от индекс 0 (вместо да се мъчиш да пишеш на същите индекси от които четеш), дори нямаше да попаднеш на този проблем с инициализацията, защото щеше да презаписваш напълно масива (може би си пробвал с 3 елемента обаче ти е гърмяло, защото се е опитвало да записва след края на масива, заради липсата на зануляване?). Цикъла, който винаги ще се изпълни точно 3 пъти и операциите в него са сравнително прости също ми се струва леко излишен (направи функция, която изпълнява това, което правиш в тялото на цикъла и просто я повикай 3 пъти с различни индекси). Да, ако очакваше дължината да се променя, или ако беше по-дълго, хубаво, цикъл, ама за 3 итерации, всяка от които сама по себе си не е много код, не мисля, че си заслужава. И нещото, което ми е най-странно: защо C-Strings (char масиви)? Защо просто не 2 string обекта - string класа си има substr метод, който ти връща стринг с точно толкова елемента. Тоест можеш да кажеш

string hex1, hex2;
cin >> hex1 >> hex2;
string redHex1 = hex1.substr(1 + 0, 2); // правим 1 + заради #-а в началото
string greenHex1 = hex1.substr(1 + 2, 2);
string blueHex1 = hex1.substr(1 + 4, 2);

И аналогично за hex2 - без да се мъчиш с char масиви и strncat и адреси в паметта и т.н.

Оттам нататък тези стрингове са точно от по 2 елемента и директно можеш да ги обърнеш в числа - или със stoi, или със stringstream, за който сме учили (има начин да четеш и печаташ в hex от него).

Поздрави,

Жоро

1
zen00 avatar zen00 0 Точки

Мерси Жоро за коментара .. борих се прекалено дълго време и верно бях оглупял,  използвах какви ли не функции за целта. Хубаво е че прочетох и "уж" разбрах някои от тях ;) И да позна че бях направил първо char firstPair[2] ; и ми гърмеше ;) хихих. Най интересното е че 2 реда по-нагоре имах substr:

 int firstIdx = inputLine.find("#") + 1 ;                                    
 int secondIdx = inputLine.find("#",firstIdx+1) + 1;                         
 string digitOne = inputLine.substr(firstIdx,6);                             
 string digitTwo = inputLine.substr(secondIdx,6);   

и въобще не съм се сетил да го използвам по правилния начин .... ами влязох във големите филми ;) пфхихи

Поздрави!

0
gydigydi avatar gydigydi 12 Точки

Неверен коментар. Ако може да се изтрие поста.

0
25/03/2017 21:21:58
georgi.stef.georgiev avatar georgi.stef.georgiev 921 Точки

Инициализацията НЕ СЕ прави преди да тръгне да се изпълнява програмата, това не е възможно. Инициализацията се случва когато изпълнението достигне до декларицията на съответната променлива, или до инициализацията ѝ, ако има такава (примерно ако е във функция, която се вика при определено условие, ако това условие не се спази, инициализацията на съответната променлива никога няма да се случи). Напълно обикновена операция си е и можеш да го тестваш като направиш масив от обекти на някакъв клас, който има default constructor и видиш кога ще се изпълни този default constructor. 

Стриктно погледнато, ако бъде деклариран масивът преди цикъла, не е гарантирано, че поведението ще е същото - това зависи от начина, по който работи автоматичната C++ памет на съответната система (което обикновено означава, че зависи от това как работи програмния стек на съответната система).

Какво визираш относно инициализацията по подразбиране по време на декларация, че не трябва да му се вярва много?

0
gydigydi avatar gydigydi 12 Точки

Какво визираш относно инициализацията по подразбиране по време на декларация, че не трябва да му се вярва много?

 Че  char firstPair [7] нищо не инициализира

0
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.