How to use argv as variable - c++

I would like to use a given Variable for my Main-function in c++ to be used as part of the name of the outputfile. The code is:
int main(int argc, char* argv[]) {
fstream f,g;
string s1,s2,name;
name = argv[5];
s1 = name+("_systemvalues.dat");
f.open(s1.c_str(), ios::out);
...
c.close();
An, for example, argv[5] should be "test". The program is compiling and it is running as well, but the output file is not produced.
I can display s1 on the terminal and it is what it should be - but the outputfile is simply not produced.

Maybe you don't have the required write permissions to make changes to the filesystem / directory.
chmod -R 777 mydir
By the way you could use std::ofstream for the job. It will create the file for you if it doesn't already exist.
#include <string>
#include <iostream>
#include <fstream>
/* ... */
std::string name = "";
name.append(argv[5]);
name.append("_systemvalues.dat");
std::ofstream out(name.c_str());
out << "text" << std::endl;
out.close();
/* ... */

Ok... the problem was the input. The character '/' cannnot be used as part of a filename - with hindsight it is really clear.

Related

Cannot open file with relative path? (C++ ifstream)

I know this seems like a simple question, but I tried everything I can think of to no avail to something that shouldn't have been a problem in the first place.
This is a small C++ program that opens a file. When I open it with its absolute filepath, it works fine. With a relative path, however, it stops working.
Here's the file path of the program and the files I'm trying to read:
C++ program: "/Users/Baggio/C++/Lab0/Lab0/Lab0/main.cpp"
Files: /Users/Baggio/C++/Lab0/Lab0/Lab0/result.txt, /Users/Baggio/C++/Lab0/Lab0/Lab0/dict.txt
Here's the code snippet:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
using namespace std;
int main(int argc, const char * argv[]) {
// string dict_filename = "/Users/Baggio/C++/Lab0/Lab0/Lab0/dict.txt";
// string result_filename = "/Users/Baggio/C++/Lab0/Lab0/Lab0/result.txt";
string dict_filename_string = "dict.txt";
string result_filename_string = "result.txt";
const char* dict_filename = dict_filename_string.c_str();
const char* result_filename = result_filename_string.c_str();
// open files
ifstream dict_file(dict_filename, ifstream::in);
ifstream result_file(result_filename, ifstream::in);
if (!dict_file || !result_file) {
cerr << "File could not be opened." << endl;
exit(1);
}
}
Result of execution
File could not be opened.
I'm sure I've done all the includes right, and the data types right for the ifstream constructor arguments. The only thing I can think of worth mentioning is the system I'm on: I'm on a Mac and I'm using XCode6 as my IDE.
Also, I've tried to move the files' location (results.txt and dict.txt) to these locations to no avail:
/Users/Baggio/C++/Lab0/Lab0/Lab0/
/Users/Baggio/C++/Lab0/Lab0/
/Users/Baggio/C++/Lab0/
/Users/Baggio/C++/
Thanks for your help guys!! Any suggestions or thoughts appreciated.
Print out your current working directory when you run the program:
char buffer[256];
char *val = getcwd(buffer, sizeof(buffer));
if (val) {
std::cout << buffer << std::endl;
}
This will tell you where you are running your program from and thus why the path doesn't match for relative paths. A relative path is relative to the current working directory, not to where your binary is located.
If you want to make the path relative to the location of the binary then you will have to do that yourself. Many programming languages offer this as an option, but it is not built-in to C++. You can do this by finding the executable using the argv[0] from main. Then you need to drop the file component of the executable path and replace it with the file name that you are interested in.
Since C++17, you can use std::filesystem::current_path() instead of getcwd.
std::cout << std::filesystem::current_path() << std::endl;

fstream write/read to a binary file doesn't work as expected.!

#include <iostream>
#include <string.h>
#include <fstream>
#include <conio.h>
using namespace std;
int main(int argc, char*argv[])
{
ifstream fpr;
ofstream fpw;
char * rec1 = "helloWorld";
char * rec2 = "my";
char out1[50];
char out2[50];
fpw.open("sample.txt",ios::in|ios::binary|ios::app);
if(fpw.fail())
{
cout<<"The file could not be opened!\n";
exit(1); // 0 – normal exit, non zero – some error
}
fpr.open("sample.txt",ios::out|ios::binary);
if(fpr.fail())
{
cout<<"The file could not be opened!\n";
exit(1); // 0 – normal exit, non zero – some error
}
fpw.write(rec1,10);
fpr.read(out1,10);
out1[10] = '\0';
cout<<out1<<"\n";
fpw.seekp(2,ios::beg);
fpw.write(rec2,2);
fpr.seekg(0,ios::beg);
fpr.read(out2,strlen(rec1));
cout<<"\n"<<out2<<"\n";
getch();
}
With this code I just want to insert a string named 'my' to the 2byte location of 'helloworld' string. But it doesn't insert it(even though I'm seeking to the correct location). Could anyone help me out?
from documentation on ios::mode
ios::app:
the content to the current content of the file. This flag can only be
used in streams open for output-only operations.All output operations are performed at the
end of the file, appending
Remove the ios::app, and you will be able to write "my" over "ll" in `"helloworld".
Note that you won't be able to "insert" something into a file - the only way to achieve that is to read from the original file and write the new data to a new file [or read whatever is after you want to modify, insert the text you want, and write back the parts you want after the modified bit].

C++ write to file error with full PATH from GetEnvironmentVariable()

I'm noob in C++ but wanting to learn. I have a little program that writes some info to my \etc\hosts in Windows; I get the %WINDIR% variable via GetEnvironmentVariable(), if I put the full path manually everything is ok, but when I substitute with WINDIR variable my code isn't compiling. I know I don't do something right.
#include <windows.h>
#include <ios>
#include <fstream>
char buffer[1000];
int main() {
GetEnvironmentVariable("WINDIR",(char*)&buffer,sizeof(buffer));
std::ofstream log;
log.open("%s\\system32\\drivers\\etc\\hosts", buffer);
log << "127.0.0.1 domain.com\n" << std::endl;
return 0;
}
I get really ugly errors like:
C:\Documents and Settings\xtmtrx\Desktop\coding\windir.cpp no matching function for call to `std::basic_ofstream<char, std::char_traits<char> >::open(const char[30], char[1000])'
ofstream cannot format the path for you. You need to do that separately, eg:
#include <windows.h>
#include <ios>
#include <fstream>
char buffer[1000] = {0};
int main() {
GetEnvironmentVariable("WINDIR",buffer,sizeof(buffer));
strcat(buffer, "\\system32\\drivers\\etc\\hosts");
std::ofstream log;
log.open(buffer, ios_base::ate);
log << "127.0.0.1 domain.com\n" << std::endl;
return 0;
}
FYI, you should use GetWindowsDirectory(), GetSystemDirectory(), SHGetSpecialFolderPath() or SHGetKnownFolderPath() instead of GetEnvironmentVariable(). And you should use PathCombine() when concantenating paths together so it can ensure the slashes are correct.
open("%s\\system32\\drivers\\etc\\hosts", buffer); open doesn't understand format strings..you are using %s does not make sense. learn here
Try like this:
GetEnvironmentVariable("WINDIR",buffer,sizeof(buffer));
strcat(buffer, "\\system32\\drivers\\etc\\hosts");
std::ofstream log;
log.open(buffer.str().c_str(), ios_base::ate);
You need to concate the string together like this:
LPTSTR windir[MAX_PATH];
LPTSTR fullpath[MAX_PATH];
GetWindowsDirectory(windir, MAX_PATH);
if(PathCombine(fullpath, windir, _T("system32\\drivers\\etc\\hosts")) != NULL) {
std::ofstream log;
log.open(buffer, ios_base::ate);
log << "127.0.0.1 domain.com\n" << std::endl;
}
At first you need to concate the directory and the file part with PathCombine. Then you can open the file and write the content. You should also note that you need admin permissions to change this file and some antivirus programmes may reject the access of the hosts file.

Get the App path without the app name at the end of the app

I'm using xcode and want to get the path where my app is running without the app name at the end of the path, but i have tried:
printf("%s\n", argv[0]);
it give me the right path where my app is runing but it ends with /my app name, how can i remove the app name?
use dirname
#include <iostream>
#include <libgen.h>
int main(int argc, char* argv[])
{
std::string dir = dirname(argv[0]);
std::cout << dir << std::endl;
}
Run application:
$/data/temp/test
output:
$/data/temp
You can use the dirname function.
use std::string::find_last_of to find the last instance of the path seperator (/ if *nix, \ if windows) and use std::string::substr to copy everything up to that index.
Example :
std::string file = argv[0];
std::string path = file.substr(0,file.find_last_of("/"));
This should do what you want, barring any silly mistakes in my code
If you are looking for an equivalent of bash pwd, you can use:
#include <unistd.h>
char *getcwd(char *buf, size_t size);
Note that if you previously called chdir(). this will not return the path you're looking for.

C++ stream get unget not a nop?

I have the following C++ program and ran it using Visual Studio 2008 on Windows 7. I get and then unget a character. After doing so, the file position is different. Why? How do I get around this problem?
test.txt (download link below if you want)
/* Comment 1 */
/* Comment 2 */
#include <fstream>
int main (int argc, char ** argv) {
char const * file = "test.txt";
std::fstream fs(file, std::ios::in);
std::streampos const before = fs.tellg();
// replacing the following two lines with
// char c = fs.peek(); results in the same problem
char const c = fs.get();
fs.unget();
std::streampos const after = fs.tellg();
fs.seekg(after);
char const c2 = fs.get();
fs.close();
return 0;
}
c: 47 '/' char
c2: -1 'ÿ' char
before: {_Myoff=0 _Fpos=0 _Mystate=0 } std::fpos<int>
after: {_Myoff=0 _Fpos=-3 _Mystate=0 } std::fpos<int>
Adding | std::fstream::binary to the constructor seems to solve the problem. Perhaps it has to do with newlines in the file? If so, why does it affect code that doesn't even get close to reading a newline?
Updated with a seeking to the after position and getting another character.
It seems that saving via Notepad vs. Vim makes a difference. Saving via Notepad makes the stream work okay.
I have uploaded the file to google docs if you want to dl it:
https://docs.google.com/leaf?id=0B8Ufd7Rk6dvHZmYyZjgwYmItMTI3MC00MDljLWJjYTctMWMxYWM0ODk1MTE2&hl=en_US
Ok using your input file I see the same behavior you do. After some experimentation, it looks like the file was in Unix format, then had the ^M characters edited out (at least that's how I was able to reproduce it).
To fix it, I edited the file in Vim, executed ":set ff=dos", then added and deleted a character to dirty the file, then saved it.
The file position behaves as expected:
// unget.cpp
#include <fstream>
#include <iostream>
int main ()
{
char const * file = "test.txt";
std::fstream fs(file, std::fstream::in);
std::cout << fs.tellg() << std::endl; // 0
char c = fs.get();
std::cout << fs.tellg() << std::endl; // 1
fs.unget();
std::cout << fs.tellg() << std::endl; // 0
fs.close();
return 0;
}
Build and run:
$ clang++ unget.cpp
$ ./a.out
0
1
0
Or, I don't understand where is the problem.