我正在努力让我的代码能够将a file分成一个客户数据库(它由许多空格而不是制表符分隔)。我尝试使用strtok,但是我收到了EXC_BAD_ACCESS错误。这是我的main.cpp代码:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "Cust.h"
using namespace std;
int main (int argc, char * const argv[]) {
Cust customers[500];
int idx = 0;
string tmpString = "";
string tmpAcctFN = "";
string tmpAcctLN = "";
ifstream input("P3_custData.txt");
while (!input.eof()){
getline(input,tmpString);
tmpString.insert(0,"");
customers[idx].setAcctNum(atoi(strtok((char *)tmpString.c_str()," ")));
customers[idx].setAcctFN(strtok(NULL," "));
customers[idx].setAcctLN(strtok(NULL," "));
//customers[idx].setCurrBalance(atof(strtok((char *) tmpString.c_str()," ")));
}
cout << "return 0;";
return 0;
}
根据评论进行更改后,我仍然获得了EXC_BAD_ACCESS:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "Cust.h"
using namespace std;
int main (int argc, char * const argv[]) {
Cust customers[500];
int idx = 0;
string tmpString = "";
string tmpAcctFN = "";
string tmpAcctLN = "";
char * s;
ifstream input("P3_custData.txt");
while (!input.eof()){
getline(input,tmpString);
s = strdup (tmpString.c_str());
customers[idx].setAcctNum(atoi(strtok(s," ")));
customers[idx].setAcctFN(strtok(NULL," "));
customers[idx].setAcctLN(strtok(NULL," "));
//customers[idx].setCurrBalance(atof(strtok((char *) tmpString.c_str()," ")));
}
cout << "return 0;";
return 0;
}
答案 0 :(得分:2)
尝试修改std::string::c_str()
方法返回的字符串是非法的。 strtok
将进行这样的尝试(事实上你必须抛弃返回的字符串的常量是一个死的赠品)。换句话说,您无法对strtok
的结果使用std::string::c_str()
。
要么摆脱strtok
(更好),要么创建一个独立的可修改字符串副本并在其上使用strtok
(更糟糕)。
答案 1 :(得分:0)
c_str
方法将返回指向const
数据的指针。一种方法是替换:
customers[idx].setAcctNum(atoi(strtok((char *)tmpString.c_str()," ")));
customers[idx].setAcctFN(strtok(NULL," "));
customers[idx].setAcctLN(strtok(NULL," "));
使用:
char *s = strdup (tmpString.c_str());
// check if s is NULL
customers[idx].setAcctNum(atoi(strtok(s," ")));
customers[idx].setAcctFN(strtok(NULL," "));
customers[idx].setAcctLN(strtok(NULL," "));
free (s);
这为您提供了一个重复的可写字符串,您可以在其上运行strtok
。
我通常不是在C ++代码中使用旧式C语言的大粉丝,但我在实现代码运行方面也很务实。可能有一种更“C ++”的做事方式。
并且,如果您的实现没有strdup
(我认为它不是标准的一部分):
char *strdup (const char *s) {
char *d = (char *)(malloc (strlen (s) + 1));
if (d == NULL) return NULL;
strcpy (d,s);
return d;
}
更新
Anthony,基于您的问题的更新,如果您仍然收到错误,那么可能是因为字符串不是您所期望的。考虑一下,你应该不让EXC_BAD_ACCESS
写入c_str
的结果,因为内存在技术上不是只读的。 EXC_BAD_ACCESS
只应在您尝试写入只读内存(或在地址空间之外)时才会出现。正如一位评论者指出的那样,c_str
可以为某些简单的情况返回指向只读内存的指针,但如果您的文件有复杂的行,则不太可能出现这种情况。
在任何一种情况下,复制到可变字符串都会修复它。
我认为可能发生的是你的strtok
之一正在返回NULL。如果您正在处理少于三个字段的行(例如,“hello there”,其中第三个strtok
将返回NULL),则会出现这种情况。
在strtok
来电之前打印代码中的字符串:
std::cerr << "[" << s << "]" << std::endl;
(并确保在strtok
调用后释放字符串,以免最终导致内存泄漏。
如果结果是问题,解决方案取决于您的需求。您可以通过在调用set...()
之前检查并复制单个字符串来完全忽略这些行 - 换句话说,只有在所有三个字符串都为非null时才调用它们。
您可以事先检查字符串,以计算分隔符的数量,确保至少有两个。
我确信还有其他可能性,但直到我才能真正提供帮助:
希望有所帮助。
答案 2 :(得分:0)
strtok()
将返回NULL
。你必须检查那个指针,例如到std::string
的构造函数或赋值运算符。
char* token = ::strtok(0, " ");
if(!token) {
// handle error
}
不过,考虑使用字符串流或其他更多类似C ++的功能,以避免首先陷入此类陷阱。