엑세스 위반 발생 오류 도와주세요ㅠㅠ

jo49973477의 이미지

과제하다가 코딩 오류가 나서 질문드립니다! 컴파일은 되었지만 첨부한 사진같이 코딩 도중에 끊겼고, 디버그 결과 "예외 발생: 0xC000005, 0xDDDDDDDD위치를 기록하는 동안 엑세스 위반이 발생했습니다. 라는 오류가 뜹니다. 코드는 대략 다음과 같습니다.
아마 저 근처에서 오류가 난 것 같고 혹시 아니라면 풀버전 올려드리겠습니다!! 어디가 오류인지 대체 모르겠네요ㅠㅠ

소스.cpp(main함수 있는 소수)

Stuff.h

using namespace std;
#include <string>
 
class Stuff{
private:
	string _name;
	int _price;
	int _stock;
	int _discount;
	int _discountStock;
public:
	Stuff();
	Stuff(string name, int price, int stock);
	~Stuff();
 
	void SetStuff(string name, int price, int stock);
	void SetDiscount(int discount, int discountStock);
	string nameShow();
	int priceShow();
	int stockShow();
	int discountShow();
	int discountStockShow();
 
};
 
#endif

Shoplist.h

#ifndef SHOPLIST_H
#define SHOPLIST_H
#include <string>
#include "Stuff.h"
 
class Shoplist {
private:
	Stuff * _list;
	string _name;
	int _items;
public:
	Shoplist();
	Shoplist(string name);
	~Shoplist();
 
	void AddStuff(Stuff stuff);
	void RemoveStuff(int num);
	void listShow();
	void setDiscount(int standard, double rate, int stocks);
	string nameShow();
};
 
 
#endif

ShopFunctions.cpp

#include <iostream>
#include <string>
using namespace std;
#include "Stuff.h"
#include "Shoplist.h"
#define SIZE_OF_SHOPLIST 30
 
void Shoplist::AddStuff(Stuff stuff) {
	_list[_items] = stuff;
	this->_items++;
}
 
void Shoplist::listShow() {
	cout << "--------------------------------------------------\n";
	cout << _name << endl;
	cout << "--------------------------------------------------\n";
	cout << "순번" << '\t' << "이름" << '\t' << "가격" << '\t' << "재고" << '\t' << "할인가격" << '\t' << "할인 상품 재고" << endl;
	if (_items == 0) {
		return;
	}
	for (int i = 0; i < _items; i++) {
		if(_list[i].discountShow() != 0 && _list[i].discountStockShow() != 0){
			cout << i + 1 << "." << '\t' << _list[i].nameShow() << '\t' << _list[i].priceShow() << '\t' << _list[i].discountShow() << '\t' << _list[i].discountStockShow() << endl;
		}
		else{
			cout << i + 1 << "." << '\t' << _list[i].nameShow() << '\t' << _list[i].priceShow() << endl;
		}
	}
}

#include <iostream>
#include <string>
using namespace std;
#include "Stuff.h"
#include "Shoplist.h"
 
 
int findList(string name, Shoplist catalog[], int size) {
	for (int i = 0; i < size; i++) {
		if (catalog[i].nameShow() == name) {
			return i;
		}
	}
}
 
 
int main(){
  //중략
 
	int what_to_do;
	string list_name;
	int a;
	double discount_rate;
	int stuff_num, discount_price, discount_stock;
 
	while (1) {
		for (int i = 0; i < num_list; i++) {
			catalog[i].listShow();
		}
 
		cout << "작업하고자 하는 리스트의 이름을 입력하시오: ";
		cin >> list_name;
		a = findList(list_name, catalog, num_list);
		cout << "\n원하는 작업을 입력하세요.\n" << "1. 항목 추가   2. 항목 삭제   3. 할인율 적용   Q.종료:::: ";
		cin >> what_to_do;
 
		switch (what_to_do) {
		case 1: {
			string stuff_name;
			int stuff_price, stuff_stock;
 
			cout << "이름: ";
			cin >> stuff_name;
			cout << "가격: ";
			cin >> stuff_price;
			cout << "재고: ";
			cin >> stuff_stock;
			Stuff addstuff(stuff_name, stuff_price, stuff_stock);
			catalog[a].AddStuff(addstuff); }
			break;
 
		//중략
		}
 
	}
 
	return 0;
 
return 0;
}

File attachments: 
첨부파일 크기
Image icon 캡처.PNG23.54 KB
Image icon 캡처2.PNG28.68 KB
Stephen Kyoungwon Kim@Google의 이미지

아래 라인이 문제라고 가정해 보죠.

catalog[a].AddStuff(addstuff)

우선 catalog[a]에 AddStuff를 하시기 전에, cout 같은 거 넣어서 원하는 객체를 찾는지 보시고요.

만약 그게 이상 없다면, 아래 블록에서 _list에 버퍼가 제대로 할당되어 assign 되었는지 확인해 보세요. 그리고 dynamic하게 할당된 (new나 malloc으롷 할당된) array를 _list가 가리키고 있어야 되는 상황인 거 같은데 할당한 크기가 얼마였는지도 확인해 보세요. 그리고 cout 등을 통해 혹시 _items에 이상한 값(초기화 되지 않아서 쓰레기값이 들어간다거나)이 들어가는지도 보세요.

void Shoplist::AddStuff(Stuff stuff) {
	_list[_items] = stuff;
	this->_items++;
}

그리고 cout을 넣었다 지웠다 하시기 귀찮다면 디버거를 배워서 거기 브레이크 포인트를 걸고 값을 확인해 보세요.

jo49973477의 이미지

작성자분의 말씀을 듣고 sizeof(_list)의 크기와 sizeof(_list[0])의 크기를 재보았는데, sizeof(_list)=4, sizeof(_list[0])=44가 나왔습니다.

#define SIZE_OF_SHOPLIST 30
 
Shoplist::Shoplist() {
	_list = new Stuff[SIZE_OF_SHOPLIST];
	_name = "Default";
	_items = 0;
 
}
 
Shoplist::Shoplist(string name) {
	_list = new Stuff[SIZE_OF_SHOPLIST];
	_name = name;
	_items = 0;
 
}

생성자를 다음과 같이 설정했으면 원래대로면 sizeof(_list)가 sizeof(_list[0])의 30배가 되어야 정상일텐데 말이죠.
제 생각으로는 생성자에서 제대로 _list의 크기를 할당하지 못한 것 같습니다ㅠㅠ 아마 이 부분도 문제삼을 수 있겠군요. main함수 바로 밑에 있습니다.

	int num_list = 0;
 
	cout << "리스트의 개수를 입력하시오: ";
	cin >> num_list;
 
	Shoplist * catalog = new Shoplist[num_list];
	string * name = new string[num_list];
 
	for (int i = 0; i < num_list; i++) {
		cout << "리스트" << i + 1 << "의 이름을 입력하세요: ";
		cin >> name[i];
		Shoplist list(name[i]);
		catalog[i] = list;
	}

어떻게 해결하면 될까요?

Stephen Kyoungwon Kim@Google의 이미지

이 부분만 봐서는 문제 같지는 않네요. sizeof는 이상하지 않구요. 포인터 크기가 8이 아니라 4가 나온 게 좀 이상하긴 한데 그건 이 문제와는 관계가 있어 보이지 않습니다.

그냥 코드를 다 올려보세요.

jo49973477의 이미지

좀 많이 길어요ㅠ
도와주셔서 감사합니다!

댓글 첨부 파일: 
첨부파일 크기
Package icon Project7.zip2.56 KB
Stephen Kyoungwon Kim@Google의 이미지

포인터 개념을 다시 이해하시고 다시 작성하시는 게 좋을 것 같습니다.

	for (int i = 0; i < num_list; i++) {
		cout << "¸®½ºÆ®" << i + 1 << "ÀÇ À̸§À» ÀÔ·ÂÇϼ¼¿ä: ";
		cin >> name[i];
		Shoplist list(name[i]);
		catalog[i] = list;
	}

main 함수에서 그 부분을 보세요. list(name[i])로 Shoplist를 하나 만들어서 그 내용을 catalog[i]에 복사하죠? 그리고 Shoplist는 사라집니다. 사라진다는 건 destructor를 부른다는 뜻인데, 그건 이렇게 되어 있네요.

Shoplist::~Shoplist() {
	delete[] _list;
}

즉, 자기가 할당받았던, _list가 가리키는 버퍼를 반납하고 사라집니다. 그런데 사라지기 앞서 다음 라인이 있죠.

		catalog[i] = list;

이게 뭘 하게 될까요? list라는 Shoplist 객체가 갖고 있던 버퍼를 item by item으로 카피하는 게 아니라 그냥 _list에 들어 있던 포인터 값만 카피합니다. shallow copy를 하는 거죠. catalog[i]는 루프가 다 끝난 후에도 살아남아서 사용이 됩니다. catalog[i]가 갖고 있는 _list는 아까 루프 내에서 임시 생성된 Shoplist list가 갖고 있다가 사라지면서 반납한 버퍼를 가리키고 있는 상태네요.

왜 이런 일이 벌어지나요? 컴파일러는 기본적으로 클래스나 struct를 카피할 때, member by member로 카피합니다. 일단 멤버 함수들은 생각하지 말고 필드만 보죠.

class Shoplist {
private:
	Stuff * _list;
	string _name;
	int _items;
};

여기서 _items는 int이니까 그냥 값을 카피합니다. string은 생각하지 말죠. 사실상 값을 카피하도록 내부적으로 구현되어 있다고 생각합시다. (정확한 얘기는 아니에요)

Stuff* _list는 어떻게 할까요? 프로그래머 (질문하신 분) 의도야 _list에다 N개의 Stuff 객체 배열을 달아놓는 것이겠죠. 컴파일러가, 그렇다고 이 _list에 몇 개가 붙어 있는지 알 방법이 있을까요?

_list에는 그냥 어떤 주소값이 적혀 있습니다. 따라서 컴파일러 디폴트에 맡기면, _list 따라가서 나오는 N개의 객체를 일일이 카피해 주는 게 아니라 그냥 _list에 들어 있는 주소값을 src에서 dest로 카피해 주게 되는 거죠. 이 경우는 그 src가 할당받아놨던 버퍼를 반납해서, dest까지 카피된 주소값이 invalid하게 된 것입니다.

그냥 Shoplist에 setName(const string& name)을 추가하세요.

그밖에..

		case 'Q':
			return 0;
			break;

이거 하시려고 다음 라인에서 Q를 입력하시게 되면 어떻게 될까도 생각해 보세요.

		cin >> what_to_do;

what_to_do는 int니까 cin은 int로 해석 가능한 문자열 패턴을 기다립니다. 15가 오면 그걸 십진수 15로 해석하죠. 그런데 Q가 오면 그걸 십진수로 어떻게 해석할까요?

그밖에도 자잘한 문제들이 많이 보입니다.

jo49973477의 이미지

덕분에 완벽하게 문제 해결했습니다!
지적하신 부분 외의 부분도 많이 잡아낸 것 같네요!
도와주셔서 감사합니다!

익명 사용자의 이미지

1. 많은 초보자들이 컴파일러 에러에 학을 뗀 나머지, 컴파일이 잘 되었다면 뭔가 대단한 milestone을 찍었다고 생각합니다.

사실은 그렇지 않다는 걸 깨닫게 되려면 경험과 지식이 좀 필요합니다.

컴파일이 잘 된다는 건, 대충 비유하자면 내가 쓴 글이 맞춤법 검사를 통과했다는 것과 크게 다를 바 없죠.

의미가 아주 없는 건 아니기는 합니다만.

2. 제시된 코드에서 가장 불안해 보이는 부분은 Shoplist::AddStuff 입니다.

_list는 충분한 크기의 메모리를 가리키고 있는지, _items는 적절히 초기화가 되었는지가 궁금하군요.

원래 이런 초기화는 Shoplist::Shoplist에서 되었어야 합니다. 근데 그 부분 코드를 안 주셨네요.

jo49973477의 이미지

#define SIZE_OF_SHOPLIST 30
 
Shoplist::Shoplist() {
	_list = new Stuff[SIZE_OF_SHOPLIST];
	_name = "Default";
	_items = 0;
 
}
 
Shoplist::Shoplist(string name) {
	_list = new Stuff[SIZE_OF_SHOPLIST];
	_name = name;
	_items = 0;
 
}

Shoplist의 생성자는 다음과 같습니다.
class의 private 파트에서 _list를 Stuff*형으로, _items를 int형으로 선언했습니다.

익명 사용자의 이미지

흠. 조금 비효율적이긴 해도 문제될 건 없어 보이는데...

catalog[a].AddStuff(addstuff); 직전에 a 한번 출력해보시죠.

jo49973477의 이미지

a도 정상적으로 작동하는 것 같습니다

댓글 첨부 파일: 
첨부파일 크기
Image icon 캡처3.PNG25.25 KB

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.