Really struggling here and cannot figure out how to get my value's from an array.
I first declare this array which I want to hold a set of numbers. IDK why the size is 64, I simply am frustrated and gave it a size.
char *numberList1[64];
I then read in a file using some code I found.
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
char string[100];
int counter = 0;
printf("\n\nEnter name of File 1: ");
scanf("%s", string);
fp = fopen(string, "r");
if (fp == NULL) {
printf("invalid filename of %s",string);
exit(EXIT_FAILURE);
}
while ((read = getline(&line, &len, fp)) != -1) {
numberList1[counter] = line;
counter++;
}
Now if were to say something like printf("%s",numberList1[counter]); within the while, I would get all my numbers back.
However when I say the following, I only get the last item printed out however times there are numbers. (vectorLength).
int j;
//vectorLength is the user-entered # of lines/numbers in the file.
for (j = 0; j < vectorLength; j++) {
printf("Writing out: %s \n", numberList1[j] );
//write(pipe1[WRITE], currentNum, bitSize+1);
}
i.e. If I had numbers, 1, 2, 3, 4
I would get: 4 4 4 4
What am I doing wrong??? I have tried to find guides on understanding pointers and arrays in C but I cannot figure it out...
You're not preparing the parameters sent to getline() properly. According to the documentation:
If *lineptr is set to NULL and *n is set 0 before the call, then getline() will allocate a buffer for storing the line. This buffer should be freed by the user program even if getline() failed.
You want a new line buffer for each line, and you at-least-seem to want getline() to make that for you, so, after each successful read, and once you save the returned buffer pointer allocated by getline() in your array, clear the line pointer back to NULL and the length parameter back to zero:
char * line = NULL;
size_t len = 0;
while ((read = getline(&line, &len, fp)) != -1 && counter < 64)
{
numberList1[counter++] = line;
line = NULL; // <<==== ADDED
len = 0; // <<==== ADDED
}
free(line); // note: this is here because, though getline() failed, the
// documentation for the api mandates its presence.
I believe I've found the root of the problem.
In the code below, you are reading each line into memory at the location pointed to by line. You are then storing the pointer to the memory into each index in the array. The problem is that you are overwriting the memory at the location pointed to by line each time you read in a line. As a result, only the last-read value is stored at that location. Since each index in the array points to the same location, each iteration of the final loop in your code will display the same value.
char * line = NULL;
while ((read = getline(&line, &len, fp)) != -1) {
numberList1[counter] = line; // You are storing the pointer here, NOT the value
counter++;
}
Instead, allocate memory for the array (getline does this automatically) at each iteration of the loop and copy that pointer into the array.
while ((read = getline(&line, &len, fp)) != -1) {
numberList1[counter] = line;
line = NULL;
counter++;
}
Make sure to free all memory allocated during this process.
Related
I need to read a file of ints into an array in C. A sample of the file I need to read is below, though note the files this will process can have thousands or hundreds of thousands of lines.
127
234
97
8723
I've gotten the file open in C, read how many lines there are so I know how many spaces my array needs, but I can't seem to read/parse each line into the array.
FILE *file;
int N = 0;
char filePath[30];
char endFile;
printf("What file should be used?\n");
scanf("%s", filePath);
file = fopen(filePath, "r");
if(file == NULL) {
printf("This file failed to open.\n");
break;
}
for(endFile = getc(file); endFile!=EOF; endFile=getc(file))
if(endFile == '\n') {
N = N+1;
}
int myArray[N];
while(fscanf(file, "%d\n", &a) != EOF) {
fscanf(file, "%d\n", &a); // I'm not sure this line is needed...
printf("%d\n", a);
M[i] = a;
}
From here, I need to read the file contents into myArray, with each line being the corresponding spot in the array (i.e. line zero is myArray[0], line one is myArray[1], etc.). I can't seem to find a way to do this, though I see several methods to do tab-delimited 2d arrays or csv multi-dimensional arrays.
Please also let me know if creating the array/determining the array size can be done in a better way than literally counting new-line characters...
There's no need to first "count the number of lines".
The following code cautiously grows an array of integers (by increments of 10).
#define GROW 10
int *rec = NULL, nRec = 0, sz = 0;
while( fgets( buf, sizeof buf, ifp ) != NULL ) {
if( nRec == sz ) {
rec = realloc( rec, (nRec+GROW) * sizeof *rec );
/*omitting test for failure */
sz += GROW;
}
rec[ nRec++ ] = atoi( buf );
}
This shows what is possible.
Note that realloc() can fail, returning NULL... It's up to you to add a bit of code to handle that condition.
Further, some conventional thought is to double the size of the allocation when needed (because realloc() may not be 'cheap'.) You can decide if you want to grow the array in increments (of 1024?) or grow it exponentially.
How can I retrieve an array of floating-point values from a file in C? This is the code I have used so far, but I am running into a segmentation fault(marked in my code where). If you see a less painful way of doing this that would be helpful as well.
The values are stored in the file with a single space after each value like so:
-667.0897114275529 544.6798599456312 -148.0586015260273 -323.4504101541069 .
// open file
FILE *fp;
fp = fopen(sig_file, "r");
if (fp == NULL){
printf("File opened incorrectly or is empty");
return 1;
}
// find file size
fseek(fp, 0L, SEEK_END);
long sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
// store file contents to f_contents
char *f_contents = 0;
f_contents = malloc(sz);
if (f_contents){
fread(f_contents, 1, sz, fp);
}
fclose(fp);
if (f_contents){
// find how many points are in the file
long pt_count = 0;
int i;
for (i=0; i<sz; i++){
if (f_contents[i] == ' '){
pt_count++;
}
}
// store points to a float array
double signal[pt_count];
char *pt;
pt = strtok(f_contents, " ");
// seg fault 11:
if (pt == NULL){
printf("error with pt");
return 1;
}
signal[0] = atof(pt);
//
for (i=1; i<pt_count; i++){
pt = strtok(NULL, " ");
signal[i] = atof(pt);
}
}
free(f_contents);
If you see a less painful way of doing this that would be helpful as well.
I haven't studied your code enough to identify the source of the segfault, because it should just be rewritten anyway. I might be inclined to do something more like this:
// open file
FILE *fp = fopen(sig_file, "r");
if (fp == NULL){
perror("fopen");
return 1;
}
size_t sz = 0;
for (int c = getc(fp); c != EOF; c = getc(fp)) {
if (c == ' ') sz++;
}
rewind(fp);
double signal[sz];
for (size_t i = 0; i < sz; i++) {
if (fscanf(fp, "%lf", &signal[i]) != 1) {
fclose(fp);
fputs("I/O error, malformed input, or premature EOF\n", stderr);
return 1;
}
}
fclose(fp);
If the file is long, then it might be worthwhile to read it all in one pass instead of counting elements first (and especially instead of slurping the entire file into memory). You can achieve such a one-pass read by storing the values in a more flexible data structure: some variety of linked list, or a dynamically allocated (and reallocated as necessary) array.
A linked list would need to be postprocessed into array form, but you might be able to use a dynamically allocated array as-is. You would need to use either a dynamically allocated array or a large-enough fixed-size array with a C implementation that does not support variable-length arrays, such as MS Visual Studio.
The first argument to strtok() must be a null-terminated string. fread() doesn't add a null terminator, and even if it did, you didn't allocate enough space for f_contents to hold it.
So use this code to allocate and fill in f_contents
f_contents = malloc(sz+1);
if (f_contents){
fread(f_contents, 1, sz, fp);
f_contents[sz] = '\0';
}
fclose(fp);
I am trying to compare 2 texts from files byte by byte using memcmp, after I read both of them into memory, one file into a buffer(char* or char[], tried both). the problem is, the file I read into a buffer have a lot of 0 bytes, which makes him stop at the first 0 byte thinking it is a null terminating zero, which makes a segmentation fault. how can I make the function keep compare bytes even so there are 0 bytes?
I already tried to check if the buffer is full or not, I printed it byte by byte and it showed all of the bytes including the 0 bytes. when I print it completely using printf("%s", buffer) I get only the first byte(the second byte is 0 byte).
void detect_virus(char *buffer, unsigned int size){
link* l = (link*) malloc(sizeof(link));
load(l);
unsigned int location = 0;
while(l != NULL){
location = 0;
while(location < size - l->vir->SigSize){
int isVirus = memcmp(buffer + location, l->vir->sig, l->vir->SigSize);
if(isVirus == 0)
printf("%d, %s, %d\n", location, l->vir->virusName, l->vir->SigSize);
location++;
}
}
free(l);
}
void detect(link* list){
char filename[50];
fgets(filename, 50, stdin);
sscanf(filename, "%s", filename);
FILE* file = fopen(filename, "rb");
char* buffer = (char*) malloc(10000);
fseek(file, 0, SEEK_END);
unsigned int size = ftell(file);
fseek(file, 0, SEEK_SET);
fread(buffer, 1, size, file);
detect_virus(buffer, size);
fclose(file);
}
I get a segmentation fault at the first time the memcmp function is called, instead of fully compare the texts. any ideas how to fix that?
edit
code for load function:
void load(link* list){
printf("Enter Viruses file name: \n");
char* filename = (char*) malloc(100);
fgets(filename, 100, stdin);
sscanf(filename, "%s", filename);
FILE* file = fopen(filename, "r");
while(!feof(file)){
short length = 0;
fread(&length, 2, 1, file);
if(length == 0)
break;
struct virus* v = (struct virus*)malloc(length);
fseek(file, -2, SEEK_CUR);
fread(v, length, 1, file);
v->SigSize = v->SigSize - 18;
list_append(list, v);
}
list = list->nextVirus;
free(filename);
fclose(file);
}
as a note, I tested the function before and it worked.
edit
I found out the problem, thank you all!
Per 7.21.6.7 The sscanf function, paragraph 2 of the C standard (bolding mine):
The sscanf function is equivalent to fscanf, except that input is obtained from a string (specified by the argument s) rather than from a stream. Reaching the end of the string is equivalent to encountering end-of-file for the fscanf function. If copying takes place between objects that overlap, the behavior is undefined.
Note the bolded portion.
In your code:
sscanf(filename, "%s", filename);
the filename array certainly overlaps with the filename array, thus invoking undefined behavior.
Remove that line of code.
You also need to add error checking, especially checking that the return from fopen() is not NULL.
I have been doing some practice problems for job interviews and I came across a function that I can't wrap my mind on how to tackle it. The idea is to create a function that takes the name of two files, and the allowed buffer size to read from file1 and allowed buffer size for write to file2. if the buffer size is the same, I know how to go trough the question, but I am having problems figuring how to move data between the buffers when the sizes are of different. Part of the constraints is that we have to always fill the write buffer before writing it to file. if file1 is not a multiple of file2, we pad the last buffer transfer with zeros.
// input: name of two files made for copy, and their limited buffer sizes
// output: number of bytes copied
int fileCopy(char* file1,char* file2, int bufferSize1, int bufferSize2){
int bytesTransfered=0;
int bytesMoved=o;
char* buffer1, *buffer2;
FILE *fp1, *fp2;
fp1 = fopen(file1, "r");
if (fp1 == NULL) {
printf ("Not able to open this file");
return -1;
}
fp2 = fopen(file2, "w");
if (fp2 == NULL) {
printf ("Not able to open this file");
fclose(fp1);
return -1;
}
buffer1 = (char*) malloc (sizeof(char)*bufferSize1);
if (buffer1 == NULL) {
printf ("Memory error");
return -1;
}
buffer2 = (char*) malloc (sizeof(char)*bufferSize2);
if (buffer2 == NULL) {
printf ("Memory error");
return -1;
}
bytesMoved=fread(buffer1, sizeof(buffer1),1,fp1);
//TODO: Fill buffer2 with maximum amount, either when buffer1 <= buffer2 or buffer1 > buffer2
//How do I iterate trough file1 and ensuring to always fill buffer 2 before writing?
bytesTransfered+=fwrite(buffer2, sizeof(buffer2),1,fp2);
fclose(fp1);
fclose(fp2);
return bytesTransfered;
}
How should I write the while loop for the buffer transfers before the fwrites?
I am having problems figuring how to move data between the buffers when the sizes are of different
Layout a plan. For "some practice problems for job interviews", a good plan and ability to justify it is important. Coding, although important, is secondary.
given valid: 2 FILE *, 2 buffers and their sizes
while write active && read active
while write buffer not full && reading active
if read buffer empty
read
update read active
append min(read buffer length, write buffer available space) of read to write buffer
if write buffer not empty
pad write buffer
write
update write active
return file status
Now code it. A more robust solution would use a struct to group the FILE*, buffer, size, offset, length, active variables.
// Return true on problem
static bool rw(FILE *in_s, void *in_buf, size_t in_sz, FILE *out_s,
void *out_buf, size_t out_sz) {
size_t in_offset = 0;
size_t in_length = 0;
bool in_active = true;
size_t out_length = 0;
bool out_active = true;
while (in_active && out_active) {
// While room for more data
while (out_length < out_sz && in_active) {
if (in_length == 0) {
in_offset = 0;
in_length = fread(in_buf, in_sz, 1, in_s);
in_active = in_length > 0;
}
// Append a portion of `in` to `out`
size_t chunk = min(in_length, out_sz - out_length);
memcpy((char*) out_buf + out_length, (char*) in_buf + in_offset, chunk);
out_length += chunk;
in_length -= chunk;
in_offset += chunk;
}
if (out_length > 0) {
// Padding only occurs, maybe, on last write
memset((char*) out_buf + out_length, 0, out_sz - out_length);
out_active = fwrite(out_buf, out_sz, 1, out_s) == out_sz;
out_length = 0;
}
}
return ferror(in_s) || ferror(out_s);
}
Other notes;
Casting malloc() results not needed. #Gerhardh
// buffer1 = (char*) malloc (sizeof(char)*bufferSize1);
buffer1 = malloc (sizeof *buffer1 * bufferSize1);
Use stderr for error messages. #Jonathan Leffler
Open the file in binary.
size_t is more robust for array/buffer sizes than int.
Consider sizeof buffer1 vs. sizeof (buffer1) as parens not needed with sizeof object
while(bytesMoved > 0) {
for(i=0; i<bytesMoved && i<bufferSize2; i++)
buffer2[i]=buffer1[i];
bytesTransfered+=fwrite(buffer2, i,1,fp2);
bytesMoved-=i;
}
If bufferSize1 is smaller than the filesize you need an outer loop.
As the comments to your question have indicated, this solution is not the best way to transfer data from 1 file to another file. However, your case has certain restrictions, which this solution accounts for.
(1) Since you are using a buffer, you do not need to read and write 1 char at a time, but instead you can make as few calls to those functions possible.
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
:from the man page for fread, nmemb can = bufferSize1
(2) You will need to check the return from fread() (i.e. bytesMoved) and compare it with both of the bufferSize 1 and 2. If (a) bytesMoved (i.e. return from fread()) is equal to bufferSize1 or if (b) bufferSize2 is less than bufferSize1 or the return from fread(), then you know that there is still data that needs to be read (or written). So, therefore you should begin the next transfer of data, and when completed return to the previous step you left off on.
Note: The pointer to the File Stream in fread() and fwrite() will begin where it left off in the event that the data is larger than the bufferSizes.
PseudoCode:
/* in while() loop continue reading from file 1 until nothing is left to read */
while (bytesMoved = fread(buffer1, sizeof(buffer1), bufferSize1, fp1))
{
/* transfer from buffer1 to buffer2 */
for(i = 0; i < bytesMoved && i < bufferSize2; i++)
buffer2[i] = buffer1[i];
buffer2[i] = '\0';
iterations = 1; /* this is just in case your buffer2 is super tiny and cannot store all from buffer1 */
/* in while() loop continue writing to file 2 until nothing is left to write
to upgrade use strlen(buffer2) instead of bufferSize2 */
while (bytesTransfered = fwrite(buffer2, sizeof(buffer2), bufferSize2, fp2))
{
/* reset buffer2 & write again from buffer1 to buffer2 */
for(i = bufferSize2 * iterations, j = 0; i < bytesMoved && j < bufferSize2; i++, j++)
buffer2[j] = buffer1[i];
buffer2[j] = '\0';
iterations++;
}
/* mem reset buffer1 to prepare for next data transfer*/
}
void inputData()
{
FILE* fp = fopen("input_001.txt", "r");
if(fp == NULL)
{
exit(FILE_FAILED_TO_OPEN);
}
fseek(fp, 0, SEEK_END); //set position to end of file
int size = ftell(fp);
if(size == 0)
{
exit(PARSING_ERROR_EMPTY_FILE);
}
int i;
char *input;
char *errPtr = NULL;
char *data;
fgets(input, 64, fp);
for(i = 0; i < size; i++)
{
strtol(input[i], *errPtr, 10);
//testing the output
printf("%d\n", input[i]);
}
fclose(fp);
if(fclose(fp) != 0)
{
exit(FILE_FAILED_TO_CLOSE);
}
}
I am trying to input data from a text file of unknown size into an array and keep only the integers. The format of the text file is one number per line and there can be any number of lines. I have included my attempt at trying to input the data, but my coding was not going so well. I want to use fgets() and then strtol() to convert the lines I get from fgets() into integers and put them in an array so I can work with that data. Any help is appreciated!
You haven't allocated any space for input to point to. I saw your
earlier version had a malloc; you can use that, or just a char
array.
Did you mean to use data? Because you're not, yet.
fgets reads at most one line at a time, so you need to put your reads
in a loop.
You appear to be converting the string to a number multiple times. For
instance, if the first line were "12345", this code would get 12345,
then 2345, 345, etc. This was presumably not your intention.
You're incrementing i up to size. size is the file size and might
be quite large, but you only read a maximum of 64 characters into the
buffer. (Or would have, if space had been allocated.)
In short, this code is very confused and I recommend starting over from
scratch. Decide whether you want to read the entire file at once, or one
line at a time; I recommend the latter, it takes less memory and is
simpler. If you want to store them in an array, you can do that with
malloc and then realloc as needed to grow the array dynamically.
do not use strtol, use atoi instead.
and use a loop to read the lines.
just a quick answer:
int count = 0;
while( fgets (input, 64, fp) != NULL )
{
count++;
}
fseek(fp, 0, SEEK_SET);
int* arr = new int[count];
count = 0;
while( fgets (input, 64, fp) != NULL )
{
int a =atoi(input);
arr[count++] = a;
}
If you don't know how many lines are in the file, you have a few options:
Loop through the file, counting the number of lines (call it nlines). Then declare the array int numbers[nlines].
Use a linked list instead of an array to store the numbers.
Dynamically allocate blocks of an array.
As for reading the integer data itself, something like this would work if you decide to go with the first option:
void inputData(const char* fname, const unsigned int nlines)
{
FILE* fp = fopen(fname, "r");
if (fp == NULL) {
exit(EXIT_FAILURE);
}
int numbers[nlines];
double d = 0;
fscanf(fp, "%lf", &d);
int i = 0;
while (!feof(fp)) {
numbers[i++] = (int)floor(d);
fscanf(fp, "%lf", &d);
}
fclose(fp);
}