In an effort to learn plain ansi C++, I am creating a console program that will hopefully
check to see if a file/folder exists.
Then differentiate between a file or a folder.
Count the number of lines in a file.
Recurse through all the files in a folder.
I don't want to include any libraries, just trying to get my head around basic c++ for the moment.
The problem I am having is with stage 2 of the application. I was struggling to find a way to tell if I had a file or directory, and after doing some reading I came across the library.
When the program calls the
checkIsDir()
function I get thrown an error
thread1 : EXEC_BAD_ACCESS(code = 1, address = 0x8)
I am presuming it is a memory problem, but I don't really have a hang of the basics with c++ never mind memory management. Here is my code
#include <iostream>
#include <fstream>
#include <dirent.h>
#include <sys/stat.h>
using namespace std;
bool checkIsDir(const char *fileData);
bool checkFileExists(const char *fileName, const char *directory);
int countTheNumberOfLines(const char *fileName);
int main(int argc, const char * argv[])
{
string directory, fileName;
while(fileName != "-1"){
cout << "Please enter your filename or enter -1 to quit:" << endl;
getline(cin, fileName);
cout << "Please enter your directory :" << endl;
getline(cin, directory);
if(checkFileExists(fileName.c_str(), directory.c_str())){
cout << fileName << " : exists" << endl;
if(checkIsDir(fileName.c_str())){ //code breaks when calling this function
cout << "==================| ";
cout << fileName << " is a Directory";
cout << " |==================";
}
if(checkIsDir(fileName.c_str())){
cout << fileName << " is a directory" << endl;
}
} else {
cout << fileName << " : not found";
cout << endl;
}
}
cout << "\nGoodbye";
return 0;
}
bool checkFileExists(const char *fileName, const char *directory){
const char* dirContent;
dirent* dirStruct;
DIR* dir;
dir = opendir(directory);
if(dir == NULL) return false;
while((dirStruct = readdir(dir))){
dirContent = dirStruct->d_name;
if(strcmp(fileName, dirContent) == 0){
closedir(dir);
return true;
}
}
closedir(dir);
return false;
}
bool checkIsDir(const char * fileData){
struct stat data;
struct dirent *file;
DIR *dir;
dir = opendir(fileData);
while((file = readdir(dir))){
stat(file->d_name, &data);
if(S_ISDIR(data.st_mode)){
closedir(dir);
return true;
} else {
closedir(dir);
return false;
}
}
closedir(dir);
return false;
}
int countTheLines(const char *fileName){
int lineNums = 0;
//implement
return lineNums;
}
StackExchange is the best place for hemp on the internet and I appreciate all the help that everyone gives.
Thanks in advance
Related
I'm new to C++, and I'm trying to write a project that interacts through command line. Right now, whenever I run my main (which is the executable), I always receive a segmentation fault error when the main program finished.
Edit comment:
I'm told by tutor to use as little as C++ features such as vectors or strings ... I'm also very new to C++, so i'm trying to utilize as many basic C functions as I can.
I'm
My main function looks like this:
int main(int argc, char** argv) {
cout << "starting mvote..." << endl;
int run_flag = 1;
char* actionBuffer = (char*)malloc(100 * sizeof(char));
char* action = (char*)malloc(16 * sizeof(char));
char* readPtr;
char exit[4] = { 'e','x','i','t' };
//parse command line argumentand get the filename
char* filename = argv[2];
cout << filename;
FILE* fp;
char line[64];
//from here, I'm opening the file and read it by lines
fp = fopen(filename, "r");
if (fp == NULL) {
cout << "file not exists";
return -1;
}
while (fgets(line, 64, fp) != NULL) {
cout << line << "\n";
}
fclose(fp);
while (run_flag == 1) {
cout << "what do you want?\n " << endl;
cin.getline(actionBuffer, 1024);
if (strcmp(actionBuffer, exit) == 0) {
cout << "bye!";
run_flag = 0;
break;
}
//if not exit, Look for the space in the input
readPtr = strchr(actionBuffer, ' ');
int size = readPtr - actionBuffer;
//extract the operation
strncpy(action, actionBuffer, size);
for (int i = 0; i < size; i++) {
cout << "operation:" << action[i];
}
// depend on the operation specified before the first empty space
run_flag = 0;
}
free(actionBuffer);
free(action);
return 0;
}
Description:
I first try to open up a csv file which lies in the same folder as main, and I read the file line by line. Then, I just implement a simple command where you can type exit and quit the program.
I allocate two memory, actionBuffer and action, which are used to hold command
Problem: a segmentation fault [core dumped] always exists when I type exit and hit enter, and then the process finished.
Research: So I learned that segmentation fault is due to accessing a memory that does not belongs to me. But where in my program am I trying to access such a memory?
Any advice is appreciated! Thank you.
Just to give you an idea, this would be an example of C++ code
#include<iostream>
#include<fstream>
#include<string_view>
#include<string>
#include<sstream>
#include<exception>
int main(int argc, char** argv) {
std::cout << "starting mvote...\n";
//parse command line argumentand get the filename
std::string filename = argv[2]; // NO CHECKS!
std::cout << filename <<'\n';
//from here, I'm opening the file and read it by lines
{
std::ifstream ifs(filename);
if (!ifs) {
throw std::invalid_argument("file not exists");
}
std::string line;
while (std::getline(ifs, line)) {
std::cout << line << '\n';
}
}
bool run_flag = true;
while (run_flag) {
std::cout << "what do you want?\n";
std::string userInput;
std::getline(std::cin, userInput);
if (userInput == "exit") {
std::cout << "bye!\n";
return 0;
}
std::stringstream userInputSs(userInput);
std::string operation;
while(userInputSs >> operation){
std::cout << "operation: " << operation << '\n';
}
}
}
Total newbie in c++
Here's my problem. I am trying to write a c++ prog that reads a path from a user and prints the contents of the direcory on the screen. I am able to read a directory and print it but I cannot make it read from the outside.
#include <iostream>
#include <dirent.h>
using namespace std;
int main()
{
struct dirent *entry;
int files = 0;
DIR *folder;
const char *path;
path = userdir();
folder = opendir(path);
if (folder == NULL)
{
cout << "Unable to open the directory \n\n";
return(1);
}
else
{
cout << "Directory opened\n\n";
}
while ((entry=readdir(folder)))
{
files++;
cout << "File " << files << " " << entry->d_name << endl;
}
closedir(folder);
return(0);
}
I just want to create a function that reads the path from the user and passes the value to the main function, but somehow the fact that "path" is a const char doesn't allow me to do it.
Apologies for my ignorance...my experience in c++ is just 2 days....
OK
I managed to get a bit further, and added the following funcion
char * userdir()
{
char * ppath;
cout << "\nInsert path\n";
getline(cin,ppath);
return ppath;
}
And now the error I get is :
In function 'char* userdir()':
[Error] no matching function for call to 'getline(std::istream&, char*&)'
NB: funcion placed before int main()
Since this is C++, you can do the following to read the path:
cin >> path;
I want to use mount function to implement NFS.
int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data);
I can implement it by using mount command e.g mount 172.16.0.144:/tmp/test /tmp/test. But when I use the mount() function , it doesn't work. This is my code here .
#include<sys/mount.h>
#include<iostream>
#include<errno.h>
#include<fstream>
#include<string.h>
using namespace std;
int main(int argc, char**argv) {
const char* srcPath = "/tmp/watchman";
const char* targetPath = "172.16.0.144:/tmp/watchman";
if (argc == 3) {
srcPath = argv[1];
targetPath = argv[2];
cerr << "reset the src && target path\n";
} else {
if (argc != 1) {
cerr << "wrong input argument!\n";
return 0;
}
}
cerr << "srcPath = " << srcPath << endl;
cerr << "target = " << targetPath << endl;
int ret_val = mount(srcPath, targetPath, "", MS_SHARED, "");
if (ret_val == 0) {
cerr << "mount succeed\n";
string filename = string(srcPath) + "/" + "tmp.txt";
fstream fin(filename.c_str(), ios::out);
fin << "there is a write test from client\n";
fin.close();
ret_val = umount(srcPath);
if (ret_val == 0) {
cerr << "umount succeed \n";
} else {
cerr << "umount failed \n";
printf("%s/n", strerror(errno));
}
} else {
cout<<"ret_val = "<<ret_val<<endl;
cerr << "mount failed \n";
cerr << strerror(errno) << endl;
}
return 0;
}
It printf mount failed,No such file or directory. anyone can help me? please !!!
If you read the mount manual page you will see that
mount() attaches the filesystem specified by source (which is often a pathname referring to a device, but can also be the pathname of a directory or file, or a dummy string) to the location (a directory or file) specified by the pathname in target.
You have switched the source and target in your application.
I'm reading files in a directory and passing it to a function, I think I'm doing it in a wrong way, not able to figure out.
Here is my code first it reads files in a folder and send it to a function for further operations.
#include <dirent.h>
#include <stdio.h>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
std::vector<std::string> fileName;
int main(void)
{
DIR *d;
struct dirent *dir;
vector<string> fileList;
int i=0;
d = opendir("files");
if (d)
{
while ((dir = readdir(d)) != NULL)
{
i++;
fileList.push_back(dir->d_name);
}
for(int i=0;i<fileList.size();i++) {
cout<<fileList[i]<<endl;
doSomething(fileList[i]);
}
closedir(d);
}
return(0);
}
int doSomething(fileName) {
//do something
}
Error
main.cpp: In function ‘int main()’:
main.cpp:29:28: error: ‘doSomething’ was not declared in this scope
doSomething(fileList[i]);
^
main.cpp: At global scope:
main.cpp:37:26: error: cannot convert ‘std::vector<std::basic_string<char> >’ to ‘int’ in initialization
int doSomething(fileName) {
^
main.cpp:37:28: error: expected ‘,’ or ‘;’ before ‘{’ token
int doSomething(fileName) {
^
Since your doSomething function is defined after main, it is not visible, that causes the first error. The correct way would be to at least declare the function first:
int doSomething(); //declaration
int main()
{
doSomething(); //now the function is declared
}
//definition
int doSomething()
{
}
Now, the second and third errors is emited because you didn't include the fileName parameter's type in your function definition. Based on your code, it should be a string:
int doSomething(string fileName)
{
}
I also noticed that, while this function returns int, you are not using it's returned value. Nevertheless, don't forget to return something from doSomething, otherwise it will cause undefined behavior.
Yes, Boost is great, but it's a bit bloaty. So, just for completenessapplied to reading images in a directory for OpenCV:
// you need these includes for the function
//#include <windows.h> // for windows systems
#include <dirent.h> // for linux systems
#include <sys/stat.h> // for linux systems
#include <algorithm> // std::sort
#include <opencv2/opencv.hpp>
#include <iostream> //cout
using namespace std;
/* Returns a list of files in a directory (except the ones that begin with a dot) */
int readFilenames(std::vector<string> &filenames, const string &directory)
{
#ifdef WINDOWS
HANDLE dir;
WIN32_FIND_DATA file_data;
if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE)
return; /* No files found */
do {
const string file_name = file_data.cFileName;
const string full_file_name = directory + "/" + file_name;
const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if (file_name[0] == '.')
continue;
if (is_directory)
continue;
filenames.push_back(full_file_name);
} while (FindNextFile(dir, &file_data));
FindClose(dir);
#else
DIR *dir;
class dirent *ent;
class stat st;
dir = opendir(directory.c_str());
while ((ent = readdir(dir)) != NULL) {
const string file_name = ent->d_name;
const string full_file_name = directory + "/" + file_name;
if (file_name[0] == '.')
continue;
if (stat(full_file_name.c_str(), &st) == -1)
continue;
const bool is_directory = (st.st_mode & S_IFDIR) != 0;
if (is_directory)
continue;
// filenames.push_back(full_file_name); // returns full path
filenames.push_back(file_name); // returns just filename
}
closedir(dir);
#endif
std::sort (filenames.begin(), filenames.end()); //optional, sort the filenames
return(filenames.size()); //Return how many we found
} // GetFilesInDirectory
void help(const char **argv) {
cout << "\n\n"
<< "Call:\n" << argv[0] << " <directory path>\n\n"
<< "Given a directory of images, create a vector of\n"
<< "their names, read and display them. Filter out\n"
<< "non-images\n"
<< endl;
}
int main( int argc, const char** argv )
{
if(argc != 2) {
cerr << "\nIncorrect number of parameters: " << argc << ", should be 2\n" << endl;
help(argv);
return -1;
}
string folder = argv[1];
cout << "Reading in directory " << folder << endl;
vector<string> filenames;
int num_files = readFilenames(filenames, folder);
cout << "Number of files = " << num_files << endl;
cv::namedWindow( "image", 1 );
for(size_t i = 0; i < filenames.size(); ++i)
{
cout << folder + filenames[i] << " #" << i << endl;
cv::Mat src = cv::imread(folder + filenames[i]);
if(!src.data) { //Protect against no file
cerr << folder + filenames[i] << ", file #" << i << ", is not an image" << endl;
continue;
}
cv::imshow("image", src);
cv::waitKey(250); //For fun, wait 250ms, or a quarter of a second, but you can put in "0" for no wait or -1 to wait for keypresses
/* do whatever you want with your images here */
}
}
I have an issue with the recursive call in the walkThroughFunction.
The code is supposed to go through directories and count the sub directories and if it finds a file it should open it and search a certain string.
The code only goes through one directory. Can someone help me with this. You will find the braces misplaced a little. Kindly ignore those.
int directories=0;
void walkThroughDirectory(char *directory_name,char *searchString){
DIR * directory;
struct dirent * walker;
char d_name[PATH_MAX];
int path_length;
char path[PATH_MAX];
directory=opendir(directory_name);
if(directory==NULL){
cout<<"Error"<<endl;
cout<<directory_name<<" Cannot be Opened"<<endl;
exit(10000);
}
while((walker=readdir(directory)) !=NULL){
strcpy(d_name,walker->d_name);
cout<<directory_name<<"/"<<endl;
if (strcmp (d_name, "..") == 0 &&
strcmp (d_name, ".") == 0){
continue;
}
else{
path_length = snprintf(path,PATH_MAX,"%s/%s\n",directory_name,d_name);
cout<<"HELLO"<<endl;
cout<<path<<endl;
if (path_length >= PATH_MAX){
cout<<"Path is too long"<<endl;
exit (1000);
}
if(walker->d_type==DT_DIR){
cout<<"Hello"<<endl;
directories++;
walkThroughDirectory (path,searchString);
}
else if(walker->d_type==DT_REG){
ifstream openFile;
openFile.open(path);
char line[1500];
int currentLine = 0;
if (openFile.is_open()){
while (openFile.good()){
currentLine++;
openFile.getline(line, 1500);
if (strstr(line, searchString) != NULL)
cout<<path<<": "<<currentLine<<": "<<line<<endl;
}
}
openFile.close();
}
/*
struct stat directory_stat;
if (stat(path, &directory_stat) == -1){
return;
}
if (S_ISDIR(directory_stat.st_mode)){
cout<<"HELLO"<<endl;
directories++;
walkThroughDirectory(path, searchString);
}
else if (S_ISREG(directory_stat.st_mode)){
ifstream openFile;
openFile.open(path);
char line[1500];
int currentLine = 0;
if (openFile.is_open()){
while (openFile.good()){
currentLine++;
openFile.getline(line, 1500);
if (strstr(line, searchString) != NULL)
cout<<path<<": "<<currentLine<<": "<<line<<endl;
}
}
// it's a file so search for text in file
}
*/
}
}
if (closedir (directory))
{
cout<<"Unable to close "<<directory_name<<endl;
exit (1000);
}
}
int main(){
char * name;
name=new char;
cout<<"Total Directories "<< directories<<endl;
name=get_current_dir_name();
cout<<"Current Directory is: "<<name<<endl;
/*
cout<<"Now Enter The Desired Directory from the root or the current path"<<endl;
char *desiredDirectory;
desiredDirectory=new char;
cin>>desiredDirectory;
cout<<"Enter The String You want to search"<<endl;
char *searchString;
searchString=new char;
cin>>searchString;
*/
char ourpath[400];
strcpy(ourpath,name);
walkThroughDirectory(ourpath,"diminutive");
cout<<"Total Directories "<< directories<<endl;
return 0;
}
This code has several problems. First, when you perform the strcmp to check if d_name is "." or "..", you need to use an OR, not an AND. Second, when you call sprintf to create your c-string path, you should not have a newline at the end of the string. This is what was causing your code to only go one level deep. Third, when you call get_current_dir_name, it does all the malloc work for you. What you're doing is allocating space for a single char, which won't work in itself and is not a correct use of the API. See the man page for get_current_dir_name.
The below code addresses these issues (and also has proper indentation).
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
int directories=0;
void walkThroughDirectory(char *directory_name,char *searchString)
{
DIR *directory;
struct dirent *walker;
char d_name[PATH_MAX];
int path_length;
char path[PATH_MAX];
directory = opendir(directory_name);
if(directory == NULL)
{
std::cout << directory_name << " Cannot be Opened" << std::endl;
exit(1);
}
while((walker=readdir(directory)) != NULL)
{
strcpy(d_name, walker->d_name);
// Needs to be || not &&
if (strcmp(d_name, "..") == 0 || strcmp(d_name, ".") == 0)
{
continue;
}
else
{
// No newline on the path name.
path_length = snprintf(path, PATH_MAX, "%s/%s", directory_name, d_name);
if (path_length >= PATH_MAX)
{
std::cout << "Path is too long" << std::endl;
exit(2);
}
if(walker->d_type == DT_DIR)
{
directories++;
walkThroughDirectory(path, searchString);
}
else if(walker->d_type==DT_REG)
{
std::ifstream openFile;
openFile.open(path);
char line[1500];
int currentLine = 0;
if (openFile.is_open())
{
while (openFile.good())
{
currentLine++;
openFile.getline(line, 1500);
if (strstr(line, searchString) != NULL)
std::cout << path << ": " << currentLine << ": " << line << std::endl;
}
}
openFile.close();
}
}
}
if (closedir(directory))
{
std::cout << "Unable to close " << directory_name << std::endl;
exit(3);
}
}
int main()
{
// get_current_dir_name() mallocs a string for you.
char *name;
name = get_current_dir_name();
walkThroughDirectory(name, "matthew");
free(name);
std::cout << "Total Directories: " << directories << std::endl;
return 0;
}