I am writing code to sort a txt file of int's and then display them when the user asks for a number at a certain index but every time I run my code I get a segmentation fault.
What can I do to fix this?
void insert_sorted(long *sorted, int count, long value)
{
int i = 0;
sorted[1024] = value;
if (count == 0) return;
for (i = count; i >= 0; i--) {
if (value < sorted[i - 1])
sorted[i] = sorted[i - 1];
else break;
}
sorted[i] = value;
}
int main(int argc, char *argv[])
{
FILE *infile = NULL;
int count = 0;
long sorted[1024];
long value;
int i = 0;
if (argc < 2) {
fprintf(stderr, "Usage : %s <file_name>/n", argv[0]);
return 1;
}
infile = fopen(argv[1], "r");
if (NULL == infile) {
perror("fopen");
return -1;
}
/* while file not ends */
while (!feof(infile)) {
fscanf(infile, "%ld\n", &value); /* fetch value */
insert_sorted(sorted, count, value); /* sort */
++count; /* increase number of sorted values */
}
/* display values */
printf("Enter Index : ");
int index;
scanf("%d", &index);
if (index == -1)
fclose(infile);
printf("%d ", sorted[index]);
/* cleanup */
if (infile) {
fclose(infile);
infile = NULL;
}
return 0;
}
The operation in sorted[1024] =value; will crash your program. The size of sorted array is only 1024 so that the bigest index is 1023.
One way to fix that is to change the size of sorted to 1025 in the main() function.
An other operation in the for loop that can crash the program : while i =0, access to sorted [ i - 1 ] will catch an exception.
The size of array sorted is 1024:
long sorted[1024];
which means the valid index of array sorted range from 0 to 1023.
In insert_sorted() function, you are trying to access sorted array beyond its range:
sorted[1024] = value;
^^^^
Accessing an element of array beyond its size is undefined behavior which includes program may give segmentation fault.
In fact, there is a logical error in insert_sorted() function. It is never storing the first value at appropriate location in the sorted array because of this count value check:
if (count == 0) return;
For the first time count value will be 0 and the function return without storing value at appropriate location in sorted array. Also, you should put a check on count value and if it is greater than the array size, function should give appropriate error message. You can do:
#define ARR_SZ 1024
void insert_sorted(long *sorted, int count, long value) {
int i = 0;
if (count > ARR_SZ) {
fprintf (stderr, "Array is exhausted");
//may you want to change the return type of function from void to
//int and return a value in case of error.
//Based on the return value, the caller of this function can take
//appropriate action.
return;
}
for (i = count; i > 0; i--) {
if (value < sorted[i - 1])
sorted[i] = sorted[i - 1];
else
break;
}
sorted[i] = value;
}
int main(int argc, char *argv[])
{
FILE *infile = NULL;
int count = 0;
long sorted[ARR_SZ];
......
......
......
}
When you are taking index input from user, make sure to add a check whether it is less than 0 or greater than or equal to count. If it is, you should not access sorted[index].
scanf("%d", &index);
if ((index >= count) || (index < 0)) {
//print error message and do not access sorted[index]
}
You don't need this:
if (index == -1)
fclose(infile);
because of this when user enters -1, the fclose is getting called twice for infile. Make sure once you have closed the FILE * of a opened file, don't call fclose again on it.
Segmentation fault appear when you try to write in an element array with a key that is bigger than his dimension.
In this case you are writing on
sorted[1024] = value
that has as biggest key 1023 (long sorted[1024] means from 0 to 1023).
You should change
long sorted[1024];
with
long sorted[1025];
else you should change
sorted[1024] = value;
with
sorted[1023] = value;
I didn't read your code for telling you which is better.
What can I do to fix this?
You can run the program in a debugger.
You can either step through the code, one instruction at a time, inspecting the values of your variables as you go, or you can simply let the program run under the watchful eye of the debugger. If and when the program causes a seg-fault, the debugger will interrupt it at the exact point of failure, allowing you to see which code is responsible. It will even let you see the values of the variables involved, if there's any doubt about why the code did what it did.
Related
I am little bit familiar to C but I have still much to learn and I have a little problem now. I am trying read some specific Variables (specific text) from txt file and store it in structure for which I allocated memory and then work with the data I obtained and saved in allocated structure and change variables values during runtime to get correct answer.
So far, I have done first part.. to allocate and read variables from file and then if necessary dynamically reallocate existing memory for every variable for which current memory (before reallocation) is small to be saved in it.
I declared structure varData, instantiated 2 times and allocated memory for one of them in MAIN func:
varData *dynamicData;
dynamicData = (varData*)malloc(sizeof(varData));
varData *tmp;
tmp = NULL;
Then, I have created a function loadVariablesToMemory in which I am reading file and identifiing variables in text and reallocating memory (for which current memory is not sufficient) for additional variables to be stored.
I run a debug and everything works fine when I am inside the function loadVariablesToMemory. Memory dynamicData is filled with variable names, but as soon as program leaves the function, memory is LOST or garbage is in it and I dont know why? As soon program jumps out from function all data in memory is LOST and garbage is in it.
typedef struct data {
char varName[10];
int value;
} varData;
#include "functions.h"
int main()
{
//ALLOCATING MEMORY
varData *dynamicData;// = malloc(sizeof(varData));
dynamicData = (varData*)malloc(sizeof(varData));
varData *tmp;// = NULL;
tmp = NULL;
//tmp = (varData*)realloc(dynamicData, sizeof(varData));
int numOfVars = loadVariablesToMemory("u02v1_input_03.txt", "r", dynamicData, tmp);
printf("%i \n", numOfVars);
for (int k = 0; k<=numOfVars-1; k++) {
printf("%s \n", (dynamicData+k)->varName);
}
return 0;
}
Function loadVariablesToMemory looks like this:
int loadVariablesToMemory(const char* fileName, const char* fileAccessMode, varData *dynamicData, varData *tmp) {
FILE *fSource = fopen(fileName, fileAccessMode);
char oneChar = '\0';
char buffer[10];
memset(buffer,'\0',10); //inicialization of buffer chars to \0
int i = 0;
int varOrNum = 0;
int numOfVars = 0;
bool match = false;
while (!feof(fSource)) {
oneChar = fgetc(fSource); //Load letter in file
if((oneChar == ' ') | (oneChar == '\n')) {
i = 0;
if((strcmp(buffer,"NOT") == 0) || (strcmp(buffer,"AND") == 0) || (strcmp(buffer,"OR") == 0) || (strcmp(buffer,"LSHIFT") == 0) || (strcmp(buffer,"RSHIFT") == 0) || (strcmp(buffer,"->") == 0)) {
memset(buffer,'\0',10);
}
else{
varOrNum = atoi(buffer); //returns (0) if varOrNum is variable (0)
if((varOrNum == 0) & (buffer[0] != '0'))
{ //if varOrNum is a variable (0)
for(int j = 0; j<=numOfVars; j++) { //control in memory for match of variable name
if(strcmp((dynamicData+j-1)->varName, buffer) == 0){
memset(buffer,'\0',10);
match = true; //match found
break;
}
else
match = false; //no match found
} //endForCycle
if(match == false){ //no match found
numOfVars++; //number of variables for allocation
tmp = (varData*)realloc(dynamicData, numOfVars * sizeof(varData));
if(!tmp) { //or equal to NULL
//printf("Could not resize/reallocate memory %i times \n", numOfVars);
}
else{
dynamicData = tmp;
//printf("Reallocated memory %i times \n", numOfVars);
strcpy((dynamicData+numOfVars-1)->varName, buffer);
printf("%s \n", (dynamicData+numOfVars-1)->varName);
}
}
}
varOrNum = 0; //if varOrNum is a number (1)
memset(buffer,'\0',10);
}
}
else{
buffer[i] = oneChar;
i++;
}
} //endWhileCycle (!feof(fSource))
fclose (fSource);
return numOfVars;
}
Inside condition if(match == false) I am reallocating memory through pointer and copying to newly allocated part a "string" from buffer after that I am printing it out to console. Everything works fine until program leaves the function and return value I lost my data from memory.
Can anybody help me here how to use these pointers in argument to obtain values from function and not loose it after function is over? Because right now it doesnt give me any sense why data in memory are lost as I am returning them through pointer.
If I rewrite this funtion to only basic code in MAIN it works.
Thank you very much for any help. I am totally desperate.
Let's say I've got the file
5f2
3f6
2f1
And the code:(The printf should print the second numbers (i.e 2,6, and 1) but it doesn't
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main (int argc, char * argv[])
{
FILE *ptr;
char str[100];
char * token;
int a, b, i;
int arr[4];
if(argc > 1)
{
ptr = fopen(argv[1],"r");
if(ptr == NULL)
{
exit(1);
}
}
else
{
exit(1);
}
//And I'm looking to parse the numbers between the "f" so..
while(fgets(str,100,ptr) != NULL)
{
token = strstr(str,"f");
if(token != NULL)
{
a = atol(str); // first number
b = atol(token+1); // second number
arr[i] = b; // store each b value (3 of em) into this array
}
i++;
printf("Values are %d\n",arr[i]); //should print 2,6 and 1
}
}
I've tried to move the printf outside the loop, but that seems to print an even weirder result, I've seen posts about storing integers from a file into an array before, however since this involves using strstr, I'm not exactly sure the procedure is the same.
int i,j=0;
while(fgets(str,sizeof(str),file) != NULL)
{
size_t n = strlen(str);
if(n>0 && str[n-1] == '\n')
str[n-1] = '\0';
i = str[strlen(str)-1] - '0'; /* Convert the character to int */
printf("%d\n",i);// Or save it to your int array arr[j++] = i;
}
Just move to the last character as shown and print it out as integer.
PS: fgets() comes with a newline character you need to suppress it as shown
You are never initializing i, then you are reading into arr[i] (which just happens to not crash right there), then increment i (to "undefined value + 1"), then print arr[i] -- i.e., you are writing to and reading from uninitialized memory.
Besides, your FILE * is ptr, not file. And you should get into the habit of using strtol() instead of atol(), because the former allows you to properly check for success (and recover from error).
This might be a very inefficient way to do it, but its sort of working
This code reads through a file, stores 8 line of text at a time in a global array (Would like a better option to do this if possible ) and dispatches for further processing.
here's the code
int count = 0; //global
char *array_buffer[8]; //global
void line(char *line_char)
{
int lent = strlen(line_char);
array_buffer[count] = line_char;
printf("%d\n",count);
if (count == 8)
{
int row,col;
for(row = 0; row<count; row++){
printf("%d\n",row);
for(col = 0; col<=lent; col++) {
printf("%c", array_buffer[row][col]);
}
printf("\n");
}
count = 0;
}
count++;
}
int main(int argc,char **argv)
{
clock_t start = clock();
FILE *fp = fopen(argv[1], "r");
if(fp == NULL )
{
printf("Couldn't open file %s",argv[1]);
}
char buff[512];
while (fgets(buff, 512, fp) != NULL )
{
line(buff); /*sending out an array having one line*/
}
return 0;
}
The issue is that while printing out the contents of array_buffer, its printing out the last line in the buffer 8 times. (i.e. the 8th line its reading in every cycle). Its pretty obvious that
array_buff[0]
....
array_buff[7]
all point to the address of line 8
any help in solving this ? I know it might not be the correct way to buffer something at all !
The problem with your approach that leads to the behavior that you see is that your code never copies the data from the buffer. This line
array_buffer[count] = line_char;
puts a pointer to the same char buff[512] from main at all eight locations. Subsequent calls to fgets override the content of previous reads, so you end up with eight copies of the last line.
You can fix this issue by making a copy, e.g. with strdup or by allocating memory with malloc and making a copy. You need to free everything that you allocate, though.
void line(char *line_char){
if (count == 8){
int row,col;
for(row = 0; row<count; row++){
printf("%2d:",row);
printf("%s", array_buffer[row]);
free(array_buffer[row]);
}
count = 0;
}
int lent = strlen(line_char);
array_buffer[count] = malloc((lent + 1)*sizeof(char));
strcpy(array_buffer[count], line_char);
//printf("%d\n", count);
count++;
}
You have a stale pointer, here I will explain
while (fgets(buff, 512, fp) != NULL )
{
//buff updated
line(buff);
//...
//inside of the line function
somepointertopointers[currIndex]=buff;
now it is looking at the location at buff, so all of the elements are looking at the same location, you need to copy the chars, or make a longer buffer and make sure you are updating the location the pointer is looking at, you can make 8 separate char[] pointers as well
This will give you the result you want
buff[512][8];
char** curr = buff;
while(fget(*curr,512,fp)!= NULL)
{
line(*curr);
curr++;
}
or alternatively you could allocate the buffer that is passed
#def BUFF_SIZE 512
#def BUFF_ARRAY_LEN 8
//put this somewhere before calling line
//to initialize your array_buffer
for(i=0;i<BUFF_ARRAY_LEN;i++)
{
array_buffer[i]=NULL;
}
...
//update in function line
//makes more sense to just use
//the max len of a line
if(array_buffer[count] == NULL)
array_buffer[count]=(char*)malloc(sizeof(char)*BUFF_SIZE);
strcpy(array_buffer[count],line_char);
...
//you will also need to
//clean up after you are
//done with the memory
for(i=0;i<BUFF_ARRAY_LEN;i++)
{
free(array_buffer[i]);
}
I'm very new to C and I'm still learning the basics. I'm creating an application that reads in a text file and breaks down the words individually. My intention will be to count the amount of times each word occurs.
Anyway, the last do-while loop in the code below executes fine, and then crashes. This loop prints memory address to this word (pointer) and then prints the word. It accomplishes this fine, and then crashes on the last iteration. My intention is to push this memory address into a singly linked list, albeit once it's stopped crashing.
Also, just a quick mention regarding the array sizes below; I yet figured out how to set the correct size needed to hold the word character array etc because you must define the size before the array is filled, and I don't know how to do this. Hence why I've set them to 1024.
#include<stdio.h>
#include<string.h>
int main (int argc, char **argv) {
FILE * pFile;
int c;
int n = 0;
char *wp;
char wordArray[1024];
char delims[] = " "; // delims spaces in the word array.
char *result = NULL;
result = strtok(wordArray, delims);
char holder[1024];
pFile=fopen (argv[1],"r");
if (pFile == NULL) perror ("Error opening file");
else {
do {
c = fgetc (pFile);
wordArray[n] = c;
n++;
} while (c != EOF);
n = 0;
fclose (pFile);
do {
result = strtok(NULL, delims);
holder[n] = *result; // holder stores the value of 'result', which should be a word.
wp = &holder[n]; // wp points to the address of 'holder' which holds the 'result'.
n++;
printf("Pointer value = %d\n", wp); // Prints the address of holder.
printf("Result is \"%s\"\n", result); // Prints the 'result' which is a word from the array.
//sl_push_front(&wp); // Push address onto stack.
} while (result != NULL);
}
return 0;
}
Please ignore the bad program structure, as I mentioned, I'm new to this!
Thanks
As others have pointed out, your second loop attempts to dereference result before you check for it being NULL. Restructure your code as follows:
result = strtok( wordArray, delims ); // do this *after* you have read data into
// wordArray
while( result != NULL )
{
holder[n] = *result;
...
result = strtok( NULL, delims );
}
Although...
You're attempting to read the entire contents of the file into memory before breaking it up into words; that's not going to work for files bigger than the size of your buffer (currently 1K). If I may make a suggestion, change your code such that you're reading individual words as you go. Here's an example that breaks the input stream up into words delimited by whitespace (blanks, newlines, tabs, etc.) and punctuation (period, comma, etc.):
#include <stdio.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char buffer[1024];
int c;
size_t n = 0;
FILE *input = stdin;
if( argc > 1 )
{
input = fopen( argv[1], "r");
if (!input)
input = stdin;
}
while(( c = fgetc(input)) != EOF )
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
fclose(input);
return 0;
}
No warranties express or implied (having pounded this out before 7:00 a.m.). But it should give you a flavor of how to parse a file as you go. If nothing else, it avoids using strtok, which is not the greatest of tools for parsing input. You should be able to adapt this general structure to your code. For best results, you should abstract that out into its own function:
int getNextWord(FILE *stream, char *buf, size_t bufsize)
{
int c;
size_t n = 0;
while(( c = fgetc(input)) != EOF && n < bufsize)
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buf[n] = 0;
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
if (n == 0)
return 0;
else
return 1;
}
and you would call it like
void foo(void)
{
char word[SOME_SIZE];
...
while (getNextWord(inFile, word, sizeof word))
{
do_something_with(word);
}
...
}
If you expect in your do...while code, that result could be null (this is the condition for loop break), how do you think this code-line:
holder[n] = *result;
must work? It seems to me, that it is the reason for crashing in your program.
Change do while loop to while
use
while (condition)
{
}
instead of
do {
}while(condition)
It is crashing because you are trying to derefrance a NULL pointer result in do while loop.
I work mostly with Objective-C and was just looking at your question for fun, but I may have a solution.
Before setting n=0; after your first do-while loop, create another variable called totalWords and set it equal to n, totalWords can be declared anywhere within the file (except within one of the do-while loops), but can be defined at the top to the else block since its lifetime is short:
totalWords = n;
then you can set n back to zero:
n = 0;
Your conditional for the final do-while loop should then say:
...
} while (n <= ++totalWords);
The logic behind the application will thus say, count the words in the file (there are n words, which is the totalWords in the file). When program prints the results to the console, it will run the second do-while loop, which will run until n is one result past the value of totalWords (this ensures that you print the final word).
Alternately, it is better practice and clearer for other programmers to use a loop and a half:
do {
result = strtok(NULL, delims);
holder[n] = *result;
wp = &holder[n];
printf("Pointer value = %d\n", wp);
printf("Result is \"%s\"\n", result);
//sl_push_front(&wp); // Push address onto stack.
if (n == totalWords) break; // This forces the program to exit the do-while after we have printed the last word
n++; // We only need to increment if we have not reached the last word
// if our logic is bad, we will enter an infinite loop, which will tell us while testing that our logic is bad.
} while (true);
This function is supposed to get a file of vectors. The first line
contains the dimension. All other line are in the form of
"P:3,5,2". The letter is P or N and the numbers are coordinates.
This function read a line each time it is being invoked and it saves the P/N char and the
coordinates into an array of double.
void readSamplesFile(FILE *sample_p, double result[])
{
if (dimension == 0)
{
fscanf(sample_p,"%lf",&dimension);
}
printf("dimentions: %lf\n",dimension);
printf("LINE \n");
int index;
for (index = 0; index<dimension; index++)
{
printf("%d",index);
fscanf(sample_p,"%lf%*[:,]",&result[index]);
printf("%lf",result[index]);
}
}
when i run it i get an endless loop. the dimension is read correctly but the
it prints
LINE
00.00000010.000000dimentions: 2.000000
endlessly. any ideas why?
hope i was clear
EDIT:
I've added the calling function:
void fillArray(FILE *sample_p,FILE *separators_p){
double coordinates[MAX_DIMENSION];
while (!feof(sample_p)){
readSamplesFile(sample_p,coordinates);
}
}
p.s.
fscanf is set to read : and , but to ignore them.
Neither 'P' nor 'N' is a valid double, nor are they ':' or ',', so the fscanf() fails. You should always check the return value from fscanf().
We can also debate whether you'd be better off using fgets() to read a line and sscanf() to parse it. Doing so avoids some issues; it is the way I'd code it automatically.
This code seems to work on the input file:
3
P:3,5,2
N:21.12,2.345e6,1.9132e-34
yielding the output:
dimension: 3.000000
LINE: P:3,5,2
P:offset=2:0=3(2):1=5(4):2=2(6):
LINE: N:21.12,2.345e6,1.9132e-34
N:offset=2:0=21.12(2):1=2.345e+06(8):2=1.9132e-34(16):
I'm still not keen on the (mis)use of a floating point dimension, but it works.
#include <stdio.h>
enum { MAX_DIMENSION = 6 };
enum { MAX_BUFFSIZE = 4096 };
static double dimension = 0.0;
static int get_dimension(FILE *fin)
{
char buffer[MAX_BUFFSIZE];
if (fgets(buffer, sizeof(buffer), fin) == 0)
return -1;
if (sscanf(buffer, "%lf", &dimension) != 1)
return -1;
printf("dimension: %lf\n", dimension);
return 0;
}
static int readSamplesFile(FILE *sample_p, double result[])
{
char buffer[MAX_BUFFSIZE];
if (fgets(buffer, sizeof(buffer), sample_p) == 0)
return -1;
printf("LINE: %s", buffer);
char c;
int offset;
if (sscanf(buffer, " %c:%n", &c, &offset) != 1)
return -1;
printf("%c:", c);
printf("offset=%d:", offset);
for (int index = 0; index < dimension; index++)
{
int newoff;
if (sscanf(&buffer[offset], "%lf%*[:,]%n", &result[index], &newoff) < 1)
return -1;
printf("%d=%g(%d):", index, result[index], offset);
offset += newoff;
}
putchar('\n');
return 0;
}
static void fillArray(FILE *sample_p)
{
double coordinates[MAX_DIMENSION];
while (readSamplesFile(sample_p, coordinates) == 0)
;
}
int main(void)
{
if (get_dimension(stdin) == 0)
fillArray(stdin);
return 0;
}
Note that the fillArray() function, as written, does not do anything with the line of data. There is no checking that the dimension specified is positive and not greater than MAX_DIMENSION (that would go in get_dimension()). It feels cleaner to separate get_dimension() into a separate function than to hide it inside readSampleFile(). There is an argument that readSampleFile() should be renamed readSampleLine() since it does only process one line at a time, not a whole file at a time.
The use of the %n format specifier is a little tricky, but the code needs to know where to resume reading the buffer on the next cycle.