Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Presbiopia - la 43 ani ?

Termen transcriere autovehicul

Cazare Timisoara pe 4-5 zile

Primele zile ale internetului per...
 Ditra 25

Casti USB-C ptr A-54

Aplicatie medicala / asistent med...

De ce vor atația politicieni...
 ERR_ADDRESS_UNREACHABLE

Legea 18/1968 Se mai aplica?

Digi conectare 2 routere prin fir

Succesiune notar versus instanta ...
 Montaj aer conditionat in balcon ...

Cont curent mulți valuta far...

Sugestii plan casa

Experiente cu firme care cumpara ...
 

[C++] error LNK2001: unresolved external symbol "public: static struct Vector<class Variable> Symbol_table::names"

- - - - -
  • Please log in to reply
19 replies to this topic

#1
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016
Salut!

Ma aflu la capitolul VII din "Programming: Principles and Practice using C++". Lucrez la un calculator ce se descurca cu adunari, scaderi, inmultiri, impartiri, impartiri cu rest, ridicari la putere, radical, folosirea parantezelor, crearea si editarea unor variabile si crearea unor constante de catre utilizator.
Sunt la un exercitiu ce spune urmatorul lucru:

Quote

4. The get_value(), set_value(), is_declared(), and define_name() functions all operate on the variable var_table.
Define a class called Symbol_table with a member var_table of type vector<Variable> and member functions
get(), set(), is_declared(), and declare(). Rewrite the calculator to use a variable of type Symbol_table.

Deocamdata sunt la partea dinainte de "Rewrite the calculator to use a variable of type Symbol_table.". Asadar, am creat o clasa Symbol_table in care am inclus toate acele functii (care folosesc names - vectorul in care se salveaza variabilele) si names. In loc de identificatorul var_tables, am folosit identificatorul names.

Initial, n-am introdus static inainte de fiecare functie, insa pentru a putea folosi functia in mod independent, am aflat ca am nevoie de acel static. Cu ocazia asta am aflat un lucru nou.

Problema este ca primesc eroarea

Quote

error LNK2001: unresolved external symbol "public: static struct Vector<class Variable> Symbol_table::names" (?names@Symbol_table@@2U?$Vector@VVariable@@@@A)
si nu ii pot da de cap. Sigur este ceva lipsa.

Am schimbat linia
static vector<Variable> var_table;

in
static vector<Variable> Symbol_table::var_table;

gandindu-ma ca rezolvarea este chiar in textul erorii, insa nu a functionat.

Va rog frumos sa ma ajutati. Daca aveti nevoie de mai multe informatii, va rog sa imi spuneti. Fiecare linie de cod este comentata pentru a elimina o parte din eventualele intrebari referitoare la ceea ce face o anumita bucata de cod, intrucat nu am inclus definitiile functiilor membre ale clasei. Multumesc!

class Variable {
public:
  string name; // numele
  double value; // valoarea
  bool var; // este o variabila sau constanta?
  Variable(string n, double v, bool va) :name(n), value(v), var(va) { }
};
class Symbol_table {
public:
  static double get(string s); // returneaza valoarea variabilei / constantei cu nume s
  static void set(string s, double d); // seteaza valoarea d variabilei / constantei cu nume s
  static bool is_declared(string s); // exista deja o variabila / constanta cu nume s?
  static void predefine_name(string s, double d, bool var); // adauga noua variabila / constanta cu nume s si valoare d la vectorul names
  static vector<Variable> names; // vector de variabile si constante
};


Edited by AnduIX, 15 September 2018 - 11:07.


#2
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,233
  • Înscris: 24.02.2007
Arata tot codul. Eroarea mentioneaza "names" pe care nu-l vad in ce ai postat.

Apoi, fereste-te cat poti de static.

#3
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016

View Postdani.user, on 15 septembrie 2018 - 10:56, said:

Arata tot codul. Eroarea mentioneaza "names" pe care nu-l vad in ce ai postat.
Apoi, fereste-te cat poti de static.

Scuze! Acel "names" este, de fapt, "var_tables". In enunt precizeaza ca vectorul se numeste "var_tables", insa eu l-am numit "names" in cod. Am editat postarea initiala pentru a elimina aceasta confuzie.

Codul complet (comentat in engleza, deoarece am avut un exercitiu care cerea comentarea intregului cod, acolo unde este nevoie), numai ca layout-ul nu s-a pastrat in urma procesului de copy - paste din Visual Studio in browser:
#include "pch.h"
#include "D:\Programming\Additionals\std_lib_facilities.h"
const char let = 'L';			// declaration Token kind
const char quit = 'Q';
const char print = ';';
const char number = '8';
const char name = 'a';		   // name Token kind
const char squareroot = 's';	 // square root Token kind
const char power = 'p';		  // pow Token kind
const char con = 'C';	// const declaration Token kind
const string declkey = "#";	  // declaration keyword Token kind
const string quitkey = "exit";
const string constkey = "const"; // const declaration keyword Token kind
class Token {
public:
char kind;
double value;
string name;
Token(char ch) :kind{ ch }, value{ 0 } { }
Token(char ch, double val) :kind{ ch }, value{ val } { }
Token(char ch, string str) :kind{ ch }, name{ str } { }
};
class Token_stream {
public:
Token_stream() :full{ 0 }, buffer{ 0 } { }  // Token_stream that reads from cin
Token get();		// gets a Token
void unget(Token t) { buffer = t; full = true; }	// puts a Token back
void ignore(char c);		// discards Tokens up to and including c
private:
bool full;	  // is there a Token in the buffer?
Token buffer;   // holds a Token put back by unget()
};
Token Token_stream::get()   // reads characters from cin and composes a Token
{
if (full) { full = false; return buffer; }	// checks if there's a Token in the buffer
char ch;
cin >> ch;
switch (ch) {
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
case '%':
case '=':
case ',':
case print:
  return Token(ch);   // each character represents itself
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{ cin.unget();
double val;
cin >> val;
return Token(number, val);
}
default:
  if (isalpha(ch) || ch == '#') {  // starts with a letter
   string s;
   s += ch;
   while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_')) s += ch;	// letters and digits are fine
   cin.unget();
   if (s == declkey) return Token(let);
   if (s == quitkey) return Token(quit);
   if (s == "sqrt") return Token(squareroot);
   if (s == "pow") return Token(power);
   if (s == constkey) return Token(con);
   return Token(name, s);
  }
  error("Bad token");
}
}
void Token_stream::ignore(char c)
{
if (full && c == buffer.kind) {
  full = false;
  return;
}
full = false;
char ch;	// searches input
while (cin >> ch)
  if (ch == c) return;
}
class Variable {
public:
string name;
double value;
bool var;
Variable(string n, double v, bool va) :name(n), value(v), var(va) { }
};
class Symbol_table {
public:
static double get(string s);
static void set(string s, double d);
static bool is_declared(string s);
static void predefine_name(string n, double val, bool var);
static vector<Variable> names;
};
double Symbol_table::get(string s)  // returns the value of the Variable named s
{
for (unsigned i = 0; i < names.size(); ++i)
  if (names[i].name == s) return names[i].value;
error("get: undefined name ", s);
}
void Symbol_table::set(string s, double d)  // sets the value of the Variable named s
{
for (unsigned i = 0; i <= names.size(); ++i)
  if (names[i].name == s) {
   names[i].value = d;
   return;
  }
error("set: undefined name ", s);
}
bool Symbol_table::is_declared(string s)  // checks if there's already a Variable declared with name s
{
for (unsigned i = 0; i < names.size(); ++i)
  if (names[i].name == s) return true;
return false;
}
Token_stream ts;
double expression();	// analyzes expressions
double primary()		// analyzes primaries
{
Token t = ts.get();	 // it gets a token from the token stream
switch (t.kind) {
case '(':
{
  double d = expression();
  t = ts.get();
  if (t.kind != ')') error("')' expected");
  break;
}
case squareroot:	// layout: 's' + '(' + expression + ')'
{
  t = ts.get();
  if (t.kind != '(') error("'(' expected");
  double d = expression();
  if (d < 0) error("sqrt: the number must be positive");
  t = ts.get();
  if (t.kind != ')') error("')' expected");
  return sqrt(d);
}
case power:	// layout: 'p' + '(' + base + ',' + exponent + ')'
{
  t = ts.get();
  if (t.kind != '(') error("'(' expected");
  double base = expression();
  t = ts.get();
  if (t.kind != ',') error("',' expected");
  int exponent = narrow_cast<int>(expression());
  t = ts.get();
  if (t.kind != ')') error("')' expected");
  return pow(base, exponent);
}
case '-':
  return -primary();
case number:
  return t.value;
case name:
{
  Token t_next = ts.get();
  if (t_next.kind == '=')	 // handles name = expression
  {
   for (Variable& x : Symbol_table::names)
	if (x.name == t.name)
	 if (x.var)
	 {
	  double new_value = expression();
	  Symbol_table::set(t.name, new_value);
	  return new_value;
	 }
	 else error("can't change the value of a const");
  }
  ts.unget(t_next);
  return Symbol_table::get(t.name);   // it gets the value of the Variable
}
default:
  error("primary expected");
}
}
double term()	   // analyzes terms
{
double left = primary();
while (true) {
  Token t = ts.get();
  switch (t.kind) {
  case '*':
   left *= primary();
   break;
  case '/':
  { double d = primary();
  if (d == 0) error("divide by zero");	// it's not possible to divide by zero, so it throws an error
  left /= d;
  break;
  }
  case '%':
  {
   int i1 = narrow_cast<int>(left);
   int i2 = narrow_cast<int>(primary());
   if (i2 == 0) error("%: divide by zero");	// it's not possible to divide by zero, so it throws an error
   left = i1 % i2;
   break;
  }
  default:
   ts.unget(t);	// puts the token back to the stream
   return left;
  }
}
}
double expression()
{
double left = term();
while (true) {
  Token t = ts.get();
  switch (t.kind) {
  case '+':
   left += term();
   break;
  case '-':
   left -= term();
   break;
  default:
   ts.unget(t);	// puts the token back to the stream
   return left;
  }
}
}
double declaration()	// the function that works with the declaration of a new Variable
{
Token t = ts.get();
if (t.kind != name) error("name expected in declaration");  // if the kind of token isn't a name
string new_name = t.name;
if (Symbol_table::is_declared(new_name)) error(new_name, " declared twice");  // if the name was already declared before
Token t2 = ts.get();
if (t2.kind != '=') error("= missing in declaration of ", new_name);	// if "=" is missing in declaration, right after the name
double d = expression();	// calls expression() for parsing the value of the new variable
Symbol_table::names.push_back(Variable(new_name, d, true));  // adds the new Variable to the vector which holds all Variables
return d;
}
double const_declaration()	// the function that works with the declaration of a new const
{
Token t = ts.get();
if (t.kind != name) error("name expected in declaration");  // if the kind of token isn't a name
string new_name = t.name;
if (Symbol_table::is_declared(new_name)) error(new_name, " declared twice");  // if the name was already declared before
Token t2 = ts.get();
if (t2.kind != '=') error("= missing in declaration of ", new_name);	// if "=" is missing in declaration, right after the name
double d = expression();	// calls expression() for parsing the value of the new variable
Symbol_table::names.push_back(Variable(new_name, d, false));  // adds the new const to the vector which holds all Variables
return d;
}
void Symbol_table::predefine_name(string name, double value, bool var)
{
if (is_declared(name)) error(name, " declared twice");
names.push_back(Variable(name, value, var));
}
double statement()  // analyzes statements
{
Token t = ts.get();
switch (t.kind) {
case let:   // if "let" was entered, starts the "process" of declaring a new Variable
  return declaration();
case con:
  return const_declaration();
default:
  ts.unget(t);	// puts the token back and calls expression() for analyzing the input
  return expression();
}
}
void clean_up_mess()
{
ts.ignore(print);   // discards Tokens up to and including the print character
}
const string prompt = "> ";
const string result = "= ";
void calculate()	// it actually creates the loop for calculating multiple expressions
{
while (true) try {
  cout << prompt;
  Token t = ts.get();
  while (t.kind == print) t = ts.get();
  if (t.kind == quit) return;
  ts.unget(t);
  cout << result << statement() << endl;  // calls statement() for evaluating the input further
}
catch (runtime_error& e) {
  cerr << e.what() << endl;
  clean_up_mess();
}
}
int main()
try {
Symbol_table::predefine_name("k", 1000, true);
calculate();
return 0;
}
catch (exception& e) {
cerr << "exception: " << e.what() << endl;
char c;
while (cin >> c && c != ';');
return 1;
}
catch (...) {
cerr << "exception\n";
char c;
while (cin >> c && c != ';');
return 2;
}



#4
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,233
  • Înscris: 24.02.2007
Campurile statice din clase/structuri trebuie "declarate" din nou intr-un cpp.

static vector<Variable> Symbol_table::name;


#5
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016
Am inteles. Trebuia ca acea "declaratie" sa fie plasata dupa declararea si "corpul" clasei Symbol_table, nu?
Din cate am inteles, acel static reprezinta faptul ca o functie, spre exemplu, ce este membru al unei clase oarecare, precedata de acest static, poate fi invocata in mod independent, fara a fi nevoie de vreun obiect (adica obiect.functie()), nu?

Edited by AnduIX, 15 September 2018 - 11:45.


#6
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006

View PostAnduIX, on 15 septembrie 2018 - 11:45, said:

Am inteles. Trebuia ca acea "declaratie" sa fie plasata dupa declararea si "corpul" clasei Symbol_table, nu?
Din cate am inteles, acel static reprezinta faptul ca o functie, spre exemplu, ce este membru al unei clase oarecare, precedata de acest static, poate fi invocata in mod independent, fara a fi nevoie de vreun obiect (adica obiect.functie()), nu?
Corect.

static inseamna ca nu programezi OOP.

#7
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016
Am inteles. Faptul ca nu fac POO nu este un lucru bun, cel putin in cazul folosirii limbajului C++, nu?

Problema a fost rezolvata datorita voua. Multumesc mult, baieti!

Apropo, in declaratia ulterioara, cea de dupa corpul clasei Symbol_table, nu a trebuit sa mai adaug "static".

Metoda prin care as putea evita folosirea "static" ar fi sa nu declar acele functii si acel vector in interiorul clasei, nu? Cred ca asa ar fi cel mai simplu. Pana acum asa am abordat scrierea codului, insa daca exercitiul mi-a cerut sa fac o noua clasa, am facut-o. :)

#8
jegmihai

jegmihai

    Senior Member

  • Grup: Senior Members
  • Posts: 11,536
  • Înscris: 03.09.2013

View PostAnduIX, on 15 septembrie 2018 - 13:56, said:

Faptul ca nu fac POO nu este un lucru bun, cel putin in cazul folosirii limbajului C++, nu?
În principiu trebuie să fii constant. Ți-ai ales o paradigmă, rămâi cu ea.

C++ nu te leagă de OOP, poți bine mersi să programezi procedural.

#9
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016

View Postjegmihai, on 15 septembrie 2018 - 19:14, said:

În principiu trebuie să fii constant. Ți-ai ales o paradigmă, rămâi cu ea.

C++ nu te leagă de OOP, poți bine mersi să programezi procedural.

Am inteles. Multumesc!

#10
Mosotti

Mosotti

    Geniu umil

  • Grup: Senior Members
  • Posts: 33,295
  • Înscris: 21.04.2004
- Comentariile nu au sens atunci cind numele variabilei/functiei/etc este cit se poate de clar

const char name = 'a';			 // name Token kind


Daca ai proasta idee sa numesti variabilele de genul "xjgb" atunci probabil ca ar fi o idee sa comentezi

- Incearca sa gindesti numele de functii ca actiuni, adica sa contina un verb cit mai descriptiv. De exemplu pentru mine functia "expression()" sau functia "primary()" nu-mi spune nimic. Degeaba pui comentariu acolo unde o definesti, codul trebuie sa fie cit mai usor si rapid de inteles acolo unde functia este folosita. Practic comentariile nici nu trebuie sa existe decit acolo unde treburile sint cu adevarat imputite, codul trebuie sa se autodescrie. Pe vremuri, cind codul se scria manual, exista un motiv plauzibil pentru tot felul de prescurtari, acum cind exista autocomplete si scrii doar 2-3 litere, nu mai exista nici o scuza pentru a-l supune la chinuri pe fraieru care vine peste enspe ani sa faca un bug :w00t:

- POO nu trebuie sa fie o religie. Functiile statice au si ele rolul lor

#11
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016
Iti multumesc mult pentru sfaturi! Voi tine cont de ele! :)

#12
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006

View PostAnduIX, on 16 septembrie 2018 - 15:18, said:

Iti multumesc mult pentru sfaturi! Voi tine cont de ele! Posted Image
Metodele/functiile statice sunt ok atunci cand nu citesti si nu scrii din/in nimic altceva decat variabile locale/parametri si return value; adica: nu folosesti alte variabile statice; adica: nu exista absolut nicio situatie in care apelezi de doua ori aceeasi functie cu aceiasi parametri, si primesti rezultate diferite.

Proprietatile statice sunt mereu nasoale, evita-le; ele sunt variabile globale.

#13
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016
Inteleg. Multumesc!

Doresc sa mai spun ceva, numai ca este cam off-topic.
Dupa cum am precizat in urma cu cateva zile, eu invat programare folosind cartea "Programming: Principles and Practice using C++", scrisa de Bjarne Stroustrup. Cartea este orientata catre incepatori si asa si pare.
Conceptele si modul de a scrie cod din carte sunt orientate catre realitate, te invata cum sa scrii cod organizat si cat mai bine, astfel incat sa poti face atat tu debugging mai usor (avand cod bine structurat), cat si celelalte persoane care vor vedea codul.
Pare a fi o carte paralela cu ceea ce se face in liceu / facultate. In a XI-a n-am vazut si nici nu cred ca vom invata sa folosim clase. In carte se foloseste std::vector, ce se poate redimensiona foarte usor, la liceu folosim tablouri (arrays). In carte nu se vorbeste despre niciun algoritm de sortare, ci se foloseste sort(). Ce-i drept, nu este o carte de algoritmica, dar ca idee. Probabil ca trebuie sa combin mai multe carti, mai multa documentatie, pentru a putea dobandi cunostinte din mai multe surse si pentru a-mi mari orizontul.

Cu toate acestea, eu unul cred ca "Programming: Principles and Practice using C++" este o carte buna, insa voi stiti mult mai bine decat mine. Am auzit ca este o carte buna, importanta, insa as dori si parerile voastre.

Multumesc!

#14
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,233
  • Înscris: 24.02.2007
Programarea se bazeaza pe abstractizari.

Cand inveti ce-i aia o sortare, scrii tu diversi algoritmi.

Cand ai doar nevoie, folosesti ce exista deja.

#15
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016
Am înțeles. Mulțumesc!

#16
TS030

TS030

    Guru Member

  • Grup: Senior Members
  • Posts: 15,193
  • Înscris: 25.06.2012

View PostAnduIX, on 17 septembrie 2018 - 15:20, said:

Cu toate acestea, eu unul cred ca "Programming: Principles and Practice using C++" este o carte buna, insa voi stiti mult mai bine decat mine. Am auzit ca este o carte buna, importanta, insa as dori si parerile voastre.

Multumesc!
Spre deosebire de programa scolara, cartea respectiva isi propune sa faca un lucru dar sa-l faca bine. Continua, apoi treci la urmatoarea carte buna, apoi la urmatoarea (cu practica de rigoare, constanta - cum de altfel te si indeamna Stroustrup) si tot asa.
Ai atitudinea potrivita; persevereaza.

Pentru algoritmi, hmm... poate Sedgewick?

Edited by TS030, 18 September 2018 - 00:40.


#17
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016

View PostTS030, on 18 septembrie 2018 - 00:38, said:

Spre deosebire de programa scolara, cartea respectiva isi propune sa faca un lucru dar sa-l faca bine. Continua, apoi treci la urmatoarea carte buna, apoi la urmatoarea (cu practica de rigoare, constanta - cum de altfel te si indeamna Stroustrup) si tot asa.
Ai atitudinea potrivita; persevereaza.

Pentru algoritmi, hmm... poate Sedgewick?

Inteleg. Multumesc mult!
Voi incerca sa fiu constant si sa mentin un echilibru intre munca si relaxare.

Cartea de algoritmica recomandata de tine, cea scrisa de Robert Sedgewick, pare interesanta.

Am auzit si de "Introduction to algorithms", de Cormen. Am tot vazut ca este recomandata. Ce parere aveti?

Edited by AnduIX, 18 September 2018 - 15:39.


#18
parabellum

parabellum

    Senior Member

  • Grup: Senior Members
  • Posts: 2,453
  • Înscris: 06.01.2010

View PostTS030, on 18 septembrie 2018 - 00:38, said:

Pentru algoritmi, hmm... poate Sedgewick?

Sau Thomas Cormen. O parere foarte buna :)

Edited by parabellum, 18 September 2018 - 15:30.


Anunturi

Second Opinion Second Opinion

Folosind serviciul second opinion ne puteți trimite RMN-uri, CT -uri, angiografii, fișiere .pdf, documente medicale.

Astfel vă vom putea da o opinie neurochirurgicală, fără ca aceasta să poată înlocui un consult de specialitate. Răspunsurile vor fi date prin e-mail în cel mai scurt timp posibil (de obicei în mai putin de 24 de ore, dar nu mai mult de 48 de ore). Second opinion – Neurohope este un serviciu gratuit.

www.neurohope.ro

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate