Handling strings inside Files [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to save data from a file into an array but I've had no luck for now. It's easy to save data after it was read from the file in case it's just numbers, but for example if I'm trying to save strings, the program keeps crashing over and over again. I'm using fscanf(); function since the whole .txt file is written in the same format: "First Name, Last Name". Now then, I've tried using the for loop in this way:
char *firstName = (char*)malloc(sizeof(char)*10240);
char *lastName = (char*)malloc(sizeof(char)*10240);
for(int i = 0; i<10; i++){
fscanf(fp, "%s %s", firstName[i],lastName[i]);
}
And that's where it crashes.

Pure C code:
You have to allocate the array of arrays first, then allocate each string one by one
It's best to scan the strings into temp strings with a big size, and duplicate the strings later.
int i,nb_names = 10;
char **firstName = malloc(sizeof *firstName * nb_names);
char **lastName = malloc(sizeof *lastName *nb_names);
char tempn[1000],templ[1000];
for(i = 0; i<nb_names; i++){
fscanf(fp,"%s %s", tempn,templ);
firstName[i] = strdup(tempn);
lastName[i] = strdup(templ);
}
Note that I have changed for (int i to for (i because it is not C compliant but rather C++ compliant (or C99, not sure).
For C++, drop the mallocs and use std::vector and std:string instead.
I'd recommend to use C++ if you can. I answered a lot of C/C++ questions on people trying (and failing) to allocate 2D arrays properly (including me 5 minutes ago damn :)). C++ using C++ library code is much clearer.
Full C++ example, reading from standard input
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
int nb_names = 10;
vector<string > firstName(nb_names);
vector<string > lastName(nb_names);
for(int i = 0; i<nb_names; i++){
cin >> firstName[i];
cin >> lastName[i];
}
return 0;
}

The error in your code is : firstName[i] is a character not a string but you use it like a string by using %s instead of %c.
you should use a char ** instead of char *.
char **firstName = (char**)malloc(10*sizeof(char)*10240);
I think also that 10240 is too much for firstName. Use 255 or less.

Related

sprintf into char* var[1] fails with Segmentation fault [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 11 months ago.
Improve this question
consider code:
using std::cout; using std::cerr;
using std::endl; using std::string;
using std::vector;
// . . .
char* envp[10];
vector<string> lines;
char* c_line = nullptr;
size_t len = 0;
while ((getline(&c_line, &len, input_file)) != -1) {
string line;
lines.push_back(line.assign(c_line));
}
fclose(input_file);
free(c_line);
sprintf(envp[0], "SERVER=%s", lines[0].data());
// printing envp[0] here OK
sprintf(envp[1], "DOMAIN=%s", lines[1].data());
// printing envp[1] never happened - Segmentation fault prints in output instead
I am C# dev I havent used C for couple decades. Something obvious is missing. Mem allocation?
P.S. I am mixing "old" char * for strings with std strings as the app uses 3rd party dll with chars*
EDIT declaring char envp[10][512]; fails down the line when I try to assing to the 3rd party property somedllObj.envps = envp; with cannot convert char[10][512] to char**
I do not recommend mixing std::string and old C-strings in such a wild manner. Instead I'd rely on C++ classes as long as possible:
std::ifstream inputFile("path to file");
if(!inputFile)
{
// error handling
}
std::vector<std::string> lines;
std::string tmp;
while(std::getline(inputFile, tmp))
{
lines.emplace_back(std::move(tmp)); // since C++11, not copying the strings...
}
if(!inputFile.eof())
{
// not the entire file read
// -> error handling!
}
// TODO: size check; what, if not sufficient lines in file?
lines[0] = std::string("SERVER=") + lines[0];
lines[1] = std::string("DOMAIN=") + lines[1];
std::vector<char*> envp;
envp.reserve(lines.size());
for(auto& l : lines) // C++11: range based for loop...
{
// note that this ABSOLUTELY requires the library not
// modifying the strings, otherwise undefined behaviour!
envp.emplace_back(const_cast<char*>(l.c_str()));
// UPDATE: this works as well:
envp.emplace_back(l.data());
// the string is allowed to be modified, too – apart from
// the terminating null character (undefined behaviour!)
}
// so far, pure C++...
// now we just get the pointers out of the vector:
libraryFunction(envp.size(), envp.data());
Bonus: No manual memory management at all...
(Note: Assuming the strings are not modified in the library!)
Assuming servers and domains are in the input file, they do not have whitespaces, thus getline is not necessary.
vector<string> lines;
std::ifstream input_file("path to file");
std::copy(std::istream_iterator<std::string>(input_file),
std::istream_iterator<std::string>(),
std::back_inserter(lines));
lines[0] = "SERVER="s + lines[0];
lines[1] = "DOMAIN="s + lines[1];
std::vector<char*> envp;
for(auto& line : lines)
envp.emplace_back(line.data());
envp.emplace_back(nullptr); // Usually env arrays end with nullptr, thus +1 to array size
somedllObj.envps = envp.data();

Replacements for deprecated strcpy/strcat when using char*

I have code for a 'zombie translator' as an example from my professor. From what I can tell it takes a string of english words and applies a few rules to it via functions. It currently uses strcpy and strcat to do this, however it will not compile even if I change them to strcpy_s. Without including the other functions (for the sake of space), here is my main function as an example
int main()
{
char english[MAX];
char zombie[MAX];
char zombie_word[MAX];
int pos_e; /* Current position in english line of text */
int pos_z; /* Current position in line of translated zombie text */
while (1) {
pos_e = 0;
pos_z = 0;
strcpy(zombie, "");
cout << ("Enter English text: ");
cin >> english;
/* This loop translates the line from english to zombie. */
do
{
get_next_word(english, &pos_e, zombie, &pos_z);
translate_word(english, &pos_e, zombie_word, &pos_z);
strcat(zombie, zombie_word);
} while (pos_e < strlen(english));
print_translation(zombie);
}
return 0;
}
So more specifically, what should i do to the line strcat(zombie, zombie_word); to make it compile properly in Visual Studio 2015?
It's not for a grade, I just really want to be able to understand this before the midterm, and it's a bit difficult to play around with it. I would prefer not to have to disable it through _CRT_SECURE_NO_WARNINGS so that I know what to do if I need to do something similar.
Perhaps changing the char variables into strings or something like that? I've been looking around for awhile and can't find the actual process.
Thank you very much for any assistance, I greatly appreciate your time.
From Microsoft: strncat_s
You need to include the length of the array to prevent buffer overflow dangers.
The API is:
errno_t strncat_s(
char *strDest,
size_t numberOfElements,
const char *strSource,
size_t count
);
numberOfElements is size of destination array.

Error in reading the file in C [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
I'm trying to write and read from file. writing works fine, but when it tries to read, the program crashed. tell me whats the error?
The objective of this program is to store the record of students in a file.
Calculate the percentage, and find the highest and lowest percentage of student.
#include <stdio.h>
#include <conio.h>
#include <string.h>
struct result
{
char name[15];
int batchNo;
int rgtNo;
int marks;
float perc;
};
int main()
{
char answer, i = 1;
FILE *ptr, *abc;
result s, st;
int j;
ptr = fopen("rec.txt","a");
abc = fopen("rec.txt","r");
if(!ptr)
printf("Error opening file");
else if(!abc)
printf("Error opening read file");
else {
do
{
int sum = 0;
printf("\nEnter name of student %d: ", i);
scanf("%s", s.name);
printf("\nEnter Batch #: ");
scanf("%d", &s.batchNo);
printf("\nEnter Registeration no: ");
fflush(stdin);
scanf("%d", &s.rgtNo);
printf("\nEnter marks of Five subjects: ");
scanf("%d",&s.marks);
/*for(j = 0; j < 5; j++)
{
scanf("%d",&s.marks[j]);
sum += s.marks[j];
}*/
s.perc = sum / 5.0;
printf("Percentage of student %d: %f", i+1, s.perc);
fprintf(ptr, "%s %d %d %d %f", s.name, s.batchNo, s.rgtNo, s.marks, s.perc);
printf("\n\n\n");
printf("Do you want to add another record? (y/n) ");
answer = getche();
i++;
} while(answer == 'y');
printf("outside loop\n");
fclose(ptr);
fflush(stdin);
rewind(abc);
do
{
fscanf(abc, "%s%d%d%d%f", s.name, s.batchNo, s.rgtNo, s.marks, s.perc);
printf("in loop");
} while( !feof(abc));
fclose(abc);
}
}
So many defects, so little time.
C is not C++
They are two different languages. Remove the C++ tag.
But since you tagged it as C++, you should use the fstream and iostream libraries as well as the std::string type.
One pointer per physical file
You have one FILE * for each different mode of the same file. In many cases, this will confuse the operating system and heck some won't allow it.
Instead, use one FILE * and open the file as rw+ for read, write and append.
See fseek function.
Buffer overflow with scanf
You have reserved 15 letters for the name. What happens if the user types in a name longer than 15 letters? Buffer overflow. You could write over other variables that follow the name member.
You could resolve this by using fscanf with the C language or std::cin and std::string with the C++ language.
Flushing the input
The flush function only works with output buffers. Don't use with input streams.
In the C language you have to read characters until the buffer is empty or until your terminator character is found (such as 'n').
In C++ this is accomplished by cin.ignore(1000000, '\n').
Checking input functions for errors
You can't trust the User. You must check the scanf return value for errors. If you ask for a number and the User types in a number, the scanf will fail. The value is undefined.
the program crashes whenever you type something different than 'y' at the last question Do you want to add another record? (y/n).
think what happens after this stage in your program...
hint - take a look at your ptr and abc File pointers - do they point to the same file?
The issue which makes your program segfault is the fscanf call: you're supposed to pass pointers to variables for arguments. I guess you quickly C&P without double checking your code.
As mentioned in another answer: fflush behaviour isn't specified for input streams, though many implementations behave as you expect. Another way to flush is to do a loop on the stream and read char by char:
void flush_stdin(){
char c;
while (c != '\n' && c != EOF)
c = getchar();
}
Note: I'm using getchar, as getche isn't available on my system. I suppose you should have it too, and would recommend using it for portability.
Regarding multiple opening of the same file in different modes: I don't think it should be a problem, though it seems much more straightforward to open it in append mode first, close it when the input session is done, and then reopen it for reading afterwards. In a more complex program, you'd probably split these two functionalities in separate functions, each doing its own I/O, thus following that pattern.
One last thing: you probably want to test the result of your calls to scanf and the like. Perhaps a small macro like the following would help:
#define CHECK_SCAN(x) do { \
int err = (x); \
if (err <= 0) { \
printf("error on scan: %s", strerror(err)); \
exit(1); \
} } while(0)

Issue in file operations in C++ [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
This is part of a c++ code that writes value of a vector of strings into a file.
int main () {
//freopen ("out.txt", "w+", stdout);
ofstream data;
data.open("data.txt");
BinaryTree<string>* bt = new BinaryTree<string>;
LoadBinaryTree(bt);
fillArrayOfNodes(bt);
for (int i = 0; drawArray[i] != "\0"; i++)
data << drawArray[i] << endl;
data.close();
delete bt;
return 0;
}
First, I couldn't write into the file. I mean after running the program and checking the output file, it was empty. after that, I noticed that my output format wasn't right. I changed it and now I can write into the file. (the code shown above is the modified code)
The problem is the way you're attempting to iterate through the array. The Standard C++ string class std::string should not be handled like a regular char array. That is, you shouldn't base your condition upon finding the null character. The correct way would be to iterate until you reach the length of the string.
Moreover, you should be using a vector of strings and inserting strings using push_back():
std::vector<std::string> v;
// fill vector with push_back()
for (int i = 0; i < v.size(); ++i)
data << v[i] << endl;
You need to include the right headers like <fstream>.
Try this example: http://www.cplusplus.com/doc/tutorial/files/

Skip last K lines while traversing a file [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
A user had posted a similar question earlier this day which was very soon closed due to its vagueness. Thus re-posting the question in detail with a solution as I didn't find a specific article dealing with it on the internet.
The requirement is to read and print all lines of a file except the last K.
Suppose a file contains text as:
Hello there!
My name is
Mr. XYZ
I like playing football
And if K is 2, then it should print all the lines except the last 2. i.e.:
Hello there!
My name is
Why not simply put lines into a std::deque and dump one element when its size is greater k ?
#include<iostream>
#include<fstream>
#include<deque>
int main()
{
std::fstream fs;
fs.open("output.txt",std::ios::in);
std::deque<std::string> deq;
std::string str;
int k=2;
while(std::getline(fs,str))
{
deq.push_back(str);
if(deq.size() > k)
{
std::cout <<deq.front()<<std::endl;
deq.pop_front();
}
}
}
This can easily be solved by creating a window of size K and then traversing the file till the right end of the window reaches the end of the file. The basic steps being:
Traverse the first K lines of the file without printing it.
Open the same file using another stream object.
Now simultaneously traverse both the streams so that fisrt stream is always K lines ahead of the second stream.
Run a loop while the second first stream is valid. In the loop, read through the first stream as well and keep print the lines.
The code would be
#include<iostream>
#include<fstream>
#include<string>
int main()
{
fstream fs;
fs.open("abc.txt",ios::in);
string str;
int K = 2;
while(getline(fs,str) && K>1)
{
K--;
}
if(K==1)
{
fstream fsNew;
fsNew.open("abc.txt",ios::in);
while(getline(fs,str))
{
getline(fsNew,str);
cout<<str;
}
}
cin.ignore();
}