Премини към съдържанието
  • Добре дошли!

    Добре дошли в нашите форуми, пълни с полезна информация. Имате проблем с компютъра или телефона си? Публикувайте нова тема и ще намерите решение на всичките си проблеми. Общувайте свободно и открийте безброй нови приятели.

    Моля, регистрирайте се за да публикувате тема и да получите пълен достъп до всички функции.

     

Архивирана тема

Темата е твърде стара и е архивирана. Не можете да добавяте нови отговори в нея, но винаги можете да публикувате нова тема, в която да продължи дискусията. Регистрирайте се или влезте във вашия профил за да публикувате нова тема.

rusrusrus

Защо не извежда името коректно

Препоръчан отговор


Здравейте, онзи ден написах кодът, който ще пусна по-надолу.

Проблемът е, че не ми извежда името коректно. Бъркам някъде и е елементарно, просто не се усещам.

Идеята на кодът е да въвеждаме име, факултетен номер и три оценки на определен брой ученици и да връщаме данните за тях в сортиран (по среден успех) ред. Тук не съм ползвал нито динамична памет, нищо нищо. По-нататък ще я напиша по-добре и може би ще я постна, ако имам въпроси. Просто реших да го напиша и взе, че не ми изписва имената като хората. За по-лесно може да въведе 1 бр. ученици и така да видите резултата.

Ето го и кодът :

#include <iostream>
#include <iomanip>
using namespace std;
 
class Student
{
private:
int factnum;
char *name;
 
double marks[3];
 
public:
int get_factnum() const { return factnum; }
char* get_name() const { return name; }
double get_mark(int i) const { return marks; }
void set_factnum(int factnum) { this->factnum = factnum; }
void set_name(char names[]) { this->name = names; }
void set_mark(int mark, int index) { this->marks[index] = mark; }
void read();
double average_score(int number_of_marks) const;
 
};
 
void Student::read()
{
char buffer_name[30];
 
cout << "Enter the name of the student: ";
cin >> buffer_name;
set_name(buffer_name);
 
cout << "Enter the facultative numeber of the student: ";
int number;
cin >> number;
set_factnum(number);
 
cout << "Enter the grades of the student: ";
int temp = 0;
for (int i = 0; i <= 2; i++)
{
cin >> temp;
set_mark(temp, i);
}
 
cout << "Okey, now we have all the information for this student! ^_^" << endl;
}
 
double Student::average_score(int number_of_marks) const
{
double sum = 0;
for (int i = 0; i < number_of_marks; i++)
sum += marks;
 
return sum / number_of_marks;
}
 
void sort_students(Student *group_of_students[], int number_of_students, int number_of_marks)
{
for (int i = 0; i < number_of_students - 1; i++)
{
double min_average = group_of_students->average_score(number_of_marks);
int current_index = i;
for (int j = i + 1; j < number_of_students; j++)
{
if (min_average > group_of_students[j]->average_score(number_of_marks))
{
min_average = group_of_students[j]->average_score(number_of_marks);
current_index = j;
}
}
Student *swap = group_of_students;
group_of_students = group_of_students[current_index];
group_of_students[current_index] = swap;
}
}
 
 
void print_students_group_result(Student *group_of_students[], int count_of_students) // print the information for all of the students
{
for (int i = 0; i < count_of_students; i++) 
{
cout << "Name: " << group_of_students->get_name() << endl;
cout << "Facultive number: " << group_of_students->get_factnum() << endl;
cout << "Marks : ";
for (int j = 0; j <= 2; j++)
cout << group_of_students->get_mark(j) << " ";
cout << endl;
}
}
 
int main()
{
Student original_group_of_students[10];
 
cout << "Enter the number of students: ";
int number_of_students;
cin >> number_of_students;
 
Student *group_of_students[10];
for (int i = 0; i < number_of_students; i++)
{
group_of_students = &original_group_of_students;
}
 
for (int i= 0; i < number_of_students; i++)
{
group_of_students->read();
cout << endl;
}
 
sort_students(group_of_students, number_of_students, 3);
 
print_students_group_result(group_of_students, number_of_students);
 
 
system("pause");
return 0;
 

}

Благодаря предварително.

 

Сподели този отговор


Линк към този отговор
Сподели в други сайтове

Проблемът е, че не ми извежда името коректно. Бъркам някъде и е елементарно, просто не се усещам.

Къде според теб се съхранява името? Хем е елементарно като грешка, хем е много притеснително, че питаш за конструктори, а не знаеш далеч по-основни неща, като какво представляват C низовете, какво се случва със локалните променливи и т.н.

Сподели този отговор


Линк към този отговор
Сподели в други сайтове

Схванах си грешката - насочвам указател към нещо, което след малко ще се изтрие. Оправих го с динамична памет.Иначе като изключим това, кодът зле ли е написан ? Има тук-таме някое неудачно име, но има ли нещо по фрапантно като стил на писане. Няма коментари, но като цяло сметнах, че идеята е разбираема и че ако добавя коментари ще се дублират с имената на функциите едва ли не.

Благодаря за отделеното внимание.

Сподели този отговор


Линк към този отговор
Сподели в други сайтове

Схванах си грешката - насочвам указател към нещо, което след малко ще се изтрие. Оправих го с динамична памет.

Проблемът е, че няма да "се изтрие". Просто тази част от стека ще се маркира като свободна и някой друг може да го използва. Ключовата дума тука е може. Зависи кой и как ползва стека след това. Може да ти изтрият една буква от средата на името. Може от 1000 пускания на програмата, само в 7 да има проблем. Не знаеш. Тези проблеми са едни от най-трудните за хващане. (може би най-трудните в еднонишков код.) Всеки път когато дефинираш указател, се замисли кой ще го насочи към валидно място/ ще му задели памет. гарантирано ли е, че никой няма да го използва преди това, кога тази стойност ще стане невалидна / паметта ще се освободи, гарантирано ли е че никой няма да го използва след това... Указателите са като ядрено оръжие. Толкова мощни и толкова опасни.

Сега относно решението ти:

необходимо ли е да ползваш динамична памет?

локалната ти променлива не трябва ли да е динамична?

Не казвам, че едното или другото е вярно. Просто искам да се уверя, че си се замислил, а не просто пляснал там някакъв код, който в момента работи.

Относно стила:

Публични get и set функции за всеки член на класа? А защо членовете да не са публични? Необходимо ли е да се ползват гет и сет функци в методите на класа?

Трябва ли функцията за задаване на стойности от клавиатурата да е метод на класа? А защо нямаме такава която печата студент? Защо метода за средна оценка взима броя оценки отвън - някой извън класа по-добре знае колко са оценките или първите n са най-важни, още повече че сет метода позволява да инициализирам само последната оценка примерно.

Ако успееш да отговориш аргументирано на всеки от тези въпроси, значи стила ти няма проблеми. Мислиш ли, че можеш?

Клас се пише така, все едно ще го ползва човек, дето много те мрази и е най-добрия приятел на шефа ти.

Сподели този отговор


Линк към този отговор
Сподели в други сайтове

Извинявам се за късният отговор, просто явно преди съм цъкнал това за известията и след това съм забравил да го видя пак.

Искам да попитам относно get и set. Като цяло забелязах, че на упражненията( в университета) ни карат да ги правим винаги. Ако имаме read функция както в случая и print_student функция нуждаем ли се от get и set ? Нали тези функции си имат достъп до private атрибутите. Т.е., ако не ми трябва например да изписвам само името на студента има ли смисъл от get_name() например? Т.е. трябват ни, ако искаме да достигаме само до определенна данна, а не до всички общо или?

Имам и още един въпрос. Когато предефинираме операторът '=', то в интернет прочетох, а и ни бяха казахали единия път на упражнения, че трябва да имаме проверка дали не се опитваме да присвоим самото нещо на себе си. Например house = house, където house е от клас Home.

т.е. трябва да правим следната проверка в началото:

Home& operator=(const Home& other_home)

{

if(this == &other_home) return *this;

.....

}

 

Обаче като пробвах без тази проверка и всичко си работеше нормално? Та къде е истината? В интернет на едно място прочетох, че първо се освобождава паметта на това, на което искаме да присвояваме, а после се записва на нея. Тогава има логика наистина да тярбва да се прави проверка.

А без проверка би тръгнало, ако се прави странично копие, освобождава се паметта и после се записва, но това пък би било по-бавно и ме съмнява, че става така работата. Нещо може би аз не правя каkто трябва.

Благодаря предварително.

П.П. Също така има ли смисъл да използваме set функциите в конструктора? Пишем set_factnum(x) или factnum = x ? Аз честно казано не виждам смисъл да се вика set, но все пак да питам.


Сподели този отговор


Линк към този отговор
Сподели в други сайтове

Извинявам се за късният отговор, просто явно преди съм цъкнал това за известията и след това съм забравил да го видя пак.Искам да попитам относно get и set. Като цяло забелязах, че на упражненията( в университета) ни карат да ги правим винаги.

Това "винаги" е много грешно. Идеята на обектите е да капсуловат данни и методи за работа с тях. Давайки гет и сет методи за всичките си член-променливи, прави цялата работа много безсмислена. Ти трябва да дадеш минималния набор от публични методи и променливи на потребителя, който хем не ограничава работата на класа, хем не дава на потребителя му средства да го използва не по предназначение. Като винаги приемай че потребителя иска да те прецака.

Ако имаме read функция както в случая и print_student функция нуждаем ли се от get и set ? Нали тези функции си имат достъп до private атрибутите. Т.е., ако не ми трябва например да изписвам само името на студента има ли смисъл от get_name() например? Т.е. трябват ни, ако искаме да достигаме само до определенна данна, а не до всички общо или?

На тези въпроси само ти, като проектиращ класа може да отговориш. Има ли случаи, когато потребителя ще се нуждае/променя от тези данни без да прибягва до другите методи? Ако да, просто публични член-променливи не вършат ли работа? Възможно ли е, вместо това да трябва да добавиш метод, който да върши истинската задача, вместо да оставяш потребителя на класа да я имплементира чрез гет и сет методите?

Имам и още един въпрос. Когато предефинираме операторът '=', то в интернет прочетох, а и ни бяха казахали единия път на упражнения, че трябва да имаме проверка дали не се опитваме да присвоим самото нещо на себе си. Например house = house, където house е от клас Home.т.е. трябва да правим следната проверка в началото:Home& operator=(const Home& other_home){if(this == &other_home) return *this;.....} Обаче като пробвах без тази проверка и всичко си работеше нормално? Та къде е истината? В интернет на едно място прочетох, че първо се освобождава паметта на това, на което искаме да присвояваме, а после се записва на нея. Тогава има логика наистина да тярбва да се прави проверка.А без проверка би тръгнало, ако се прави странично копие, освобождава се паметта и после се записва, но това пък би било по-бавно и ме съмнява, че става така работата. Нещо може би аз не правя каkто трябва.Благодаря предварително.

Първо. Избий си от главата тази работа "щом нещо веднъж е тръгнало нормално, значи е правилно и ще работи винаги и във всеки друг случай." Това е най-грешния начин на мислене, който може да имаш. По-миналата седмица съм дебъгвал 4 или 5 проблема, които ставаха веднъж на няколко хиляди опита.Ами ти сам си отвори. Простата логика показва, че не трябва да правиш нищо ако присвояваш себе си, т.е. проверката ти спестява излишни операции. А иначе, ако заделяш динамично ресурси, или трябва излишно да усложниш кода или пък направо ще доведе до погрешно поведение.

П.П. Също така има ли смисъл да използваме set функциите в конструктора? Пишем set_factnum(x) или factnum = x ? Аз честно казано не виждам смисъл да се вика set, но все пак да питам.

Отново зависи. Обикновено не се налага, но може да го използваш за същата причина поради която изобщо се ползват гет и сет методи - да направиш всякакви промени по данните на класа прозрачни за този който ги ползва или променя.

Сподели този отговор


Линк към този отговор
Сподели в други сайтове

Ясно, благодаря много. Имам още няколко въпроса.

Онзи ден написах един клас rational, който беше най-елементарен и експериментален. В него имах дефинирани:

operator char*() { return "fail"; }
operator int() { return numerator; }
Това, което ме учуди е, че при cout << num, където num е инстанция на rational, ми изведе числителя на числото т.е. изплзва се преобразуването до int().
Това, което ме озадачи е защо избра компилаторът да използва int(), а не char*() ? Честно казано, очаквах да не компилира кода и да мрънка за двусмислица. Сигурен съм, че има причина, но не я знам.
И още един въпрос. Мога ли да създам чрез new много елементи върху, които викам НЕподразбиращ се конструктор? Мисля, че може, но не знам как. Казаха ми, че става с {} , но не ми се получава при този експерименталния клас.
Пример:
int* pointer = new int[2]{50, 100}; - Това създава 2 динамични int-чета със стойност 50 и 100.
Обаче при този клас като напиша това(обект от класа може да е създаде и само с едно цяло число, тъй като по подразбране знаменателя е 1) и ми пише, че има internal error.
А дори и това да работи пак трябва да въвеждам всяка от стойностите - например 50 пъти да пиша 100. Та има ли някакъв начин да стане това, за кеото питам.Не, че е толкова важно, просто ми е интересно.
П.П. Също така искам да попитам за присвояването на NULL на някой указател в инициализиращ списък. Кога се прави?
На упражнения сме правили това в следния случай: имаме метод на класа, който използваме 2-3 пъти (например в копиращ конструктор и оператор =) и ако този метод започва с delete[] pointer, тогава при копиращия конструктор ще имаме грешка, тъй като трием указател, който не е инициализиран,а така като той е NULL нямаме проблем да го изтрием. Но онзи път на едно обучение, казаха, че присвояването на NULL на указател много пъти ни спасява от някакви грешки, които се откривали доста трудно и откриването им отнемало доста време. Можете ли да ми кажете има ли наистина такова нещо и кога това е необходимо и/или удобно освен в примера, които дадох по-горе(там по-скоро е по-удобно, въпреки, че правим едно триене, което е излишно).
Съжалявам за много въпроси, просто ми е интересно, а и като съм го чул, по-добре да питам, че да го науча.
Благодаря предварително.
П.П.2 Имам още един въпрос. В този експериментален клас имам това:
ostream& operator<<(ostream& out, const Rational & rat){return out << (int)rat.numerator << " " << rat.denominator << endl; }

 

А също и това:

 operator int() { return numerator + 2.3124242; }

Въпросът ми е защо като напиша: 

Rational chislo(100, 200);cout << chislo;

ми изписва:   "100 200", а не "102 200" ?

 

П.П.3

Имам още един въпрос( знам, че станаха доста). Нека имаме 

int a = 101;cout << ++(++a);cout <<(a++)++;

 

Защо първият cout е валиден, а вторият ще ни даде грешка? Ясно е,че единият връща референция, а другият връща по стойност(някаква си константа), но каква е логиката да е така???

Сподели този отговор


Линк към този отговор
Сподели в други сайтове

×
×
  • Добави ново...