I am writing a c file that takes in information from a .csv file, parse it, then delete whatever ive parsed. The problem that i am having is that, after it runs through one line of the .csv file i get a segmentation fault. I heard i can use GDB to help with this, but I don't know how to use that. This is my .c file
void parser(int argc, char ** argv)
{
FILE * songList;
char * theString;
char * theToken;
char songs[ROOM_STRING_LENGTH];
char artist[ROOM_STRING_LENGTH];
char title[ROOM_STRING_LENGTH];
int x;
int length;
double size;
char * type;
char songType[1];
char songTypeC;
MusicRec * next;
theToken = "";
songList = fopen(argv[1], "r");
if(songList == NULL)/*returns an error if file wasnt opened*/
{
printf("error opening file\n");
}
else
{
while(fgets(songs, ROOM_STRING_LENGTH, songList) != NULL)/*gets one string at a time until fgets equals NULL*/
{
theString = malloc((sizeof(char)*(strlen(songs)+1))); /* mallocs some memory*/
strcpy(theString, songs);
x = 0;
for(theToken = strtok(theString, ","); theToken; theToken = strtok(NULL, ","))
{
switch(x)
{
case 0:
strcpy(artist, theToken);
printf("%s\n", artist);
break;
case 1:
strcpy(title, theToken);
printf("%s\n", title);
break;
case 2:
sscanf(theToken, "%d",&length);
printf("%d\n", length);
break;
case 3:
size = atof(theToken);
printf("%.2f\n", size);
break;
case 4:
type = malloc(sizeof(char));
sscanf(theToken, "%s",type);
songType[0] = *type;
songTypeC = songType[0];
printf("%c\n", songTypeC);
free(type);
break;
}
x++;
}
next = malloc(sizeof(MusicRec));
next = createRecord(title, artist, size, length, songTypeC);
/*print = printRecord(toPrint);*/
destroyRecord(next);
/*free(print);*/
free(next);
}
free(theString);
free(theToken);
fclose(songList);
}
}
These are the 2 functions being called:
char * printRecord(MusicRec * toPrint)
{
char token[ROOM_STRING_LENGTH];
char * pointer;
sprintf(token, "%s (%s):%d[%.2f]", toPrint->title, toPrint->artist, toPrint->lengthInSeconds, toPrint->sizeInKB);
pointer = malloc(sizeof(char)*strlen(token));
strcpy(pointer, token);
return(pointer);
}
void destroyRecord(MusicRec * theRecord)
{
free(theRecord->title);
free(theRecord->artist);
}
Take a look at this piece of code:
case 4:
type = malloc(sizeof(char));
sscanf(theToken, "%s",type);
You're allocating a 1 byte string and reading an arbitrary length string into it.
That is prone to a segfault if the input token is larger than 1.
Related
i have created a headerfile containing a Struct:
functions.h
typedef struct ConfigData
{
char hostServerName[256];
unsigned short int portNmbr;
char gameKind[256];
} config;
extern config configInput;
in the file config.c I am adding data to the struct and I am able to print it correctly.
#include "functions.h"
config configInput;
char* splitString (char *lineInFile){
char *word = strtok (lineInFile, " ");
word = strtok (NULL, " ");
word = strtok (NULL, " ");
return word;
}
// Function removing spaces from a string
char * removeSpacesFromStr(char *string)
{
int non_space_count = 0;
for (int i = 0; string[i] != '\0'; i++)
{
if (string[i] != ' ')
{
string[non_space_count] = string[i];
non_space_count++;//non_space_count incremented
}
}
string[non_space_count] = '\0';
return string;
}
void readConfig (char* configFile){
FILE *fPointer= fopen (configFile, "r");
if (fPointer == NULL){
perror("ERROR: Couldnt open confg file!\n");
}
char bufferIn[256];
int count = 0;
while(fgets(bufferIn, 256, fPointer)) { // eventuell != NULL
if(strcmp(bufferIn, "") != 0){
bufferIn[strcspn(bufferIn, "\n")] = 0;
switch (count) {
case 0:
strcpy(configInput.hostServerName, splitString(bufferIn));
break;
case 1:
configInput.portNmbr = atoi(splitString(bufferIn));
break;
case 2:
strcpy(configInput.gameKind, splitString(bufferIn));
break;
}
count++;
}
}
printf("\n>>>Config File Data<<<\n");
printf("HostServerName: %s\n", configInput.hostServerName);
printf("PortNumber: %d\n", configInput.portNmbr);
printf("GameKind: %s\n\n ", configInput.gameKind);
}
but when I try to print the data from this struct in the main method, it doesn't work properly. It just prints some random chars
#include "functions.h"
int main (int argc, char *argv[]) {
char gamekindname[256]= "NMMorris";
char *hostname[256] = "sysprak.priv.lab.nm.ifi.lmu.de";
int portnumber = 1357;
char* gameID = argv[2];
char playerNumber[256];
char configFile[256] = "client.conf" ;
...
//read in Data from config File
readConfig(configFile);
config configInput;
strcpy(gamekindname, configInput.gameKind);
strcpy(hostname, configInput.hostServerName);
portnumber = configInput.portNmbr;
}
So when I try to access the data of the configInput struct it doesn't show the correct one.
Best Enno :)
I would suggest to pass a pointer to config in the readConfig()method.
Something like this:
config localConfig;
readConfig(configFile, &localConfig);
And the function:
void readConfig (char* configFile, config* ptr_config){
FILE *fPointer= fopen (configFile, "r");
if (fPointer == NULL){
perror("ERROR: Couldnt open confg file!\n");
}
char bufferIn[256];
int count = 0;
while(fgets(bufferIn, 256, fPointer)) { // eventuell != NULL
if(strcmp(bufferIn, "") != 0){
bufferIn[strcspn(bufferIn, "\n")] = 0;
switch (count) {
case 0:
strcpy(*ptr_config->hostServerName, splitString(bufferIn));
break;
case 1:
*ptr_config->portNmbr = atoi(splitString(bufferIn));
break;
case 2:
strcpy(*ptr_config->gameKind, splitString(bufferIn));
break;
}
count++;
}
}
printf("\n>>>Config File Data<<<\n");
printf("HostServerName: %s\n", *ptr_config->hostServerName);
printf("PortNumber: %d\n", *ptr_config->portNmbr);
printf("GameKind: %s\n\n ", *ptr_config->gameKind);
}
For starters the program should not compile at least due to this invalid declaration
char *hostname[256] = "sysprak.priv.lab.nm.ifi.lmu.de";
It seems that instead of the array of pointers you mean a character array
char hostname[256] = "sysprak.priv.lab.nm.ifi.lmu.de";
This statement
if(strcmp(bufferIn, "") != 0){
does not make sense. It seems you mean
if ( bufferIn[0] != '\n' ){
This switch statement within the while loop
switch (count) {
case 0:
strcpy(configInput.hostServerName, splitString(bufferIn));
break;
case 1:
configInput.portNmbr = atoi(splitString(bufferIn));
break;
case 2:
strcpy(configInput.gameKind, splitString(bufferIn));
break;
}
count++;
also does not make sense. After three iterations of the while loop the variable count will be equal to 3 and the compound statement of the switch statement will be skipped.
The function splitString looks suspecious.
char* splitString (char *lineInFile){
char *word = strtok (lineInFile, " ");
word = strtok (NULL, " ");
word = strtok (NULL, " ");
return word;
}
There is no check whether word is equal to NULL.
Within main you are using the local variable configInput that is not initialized
config configInput;
strcpy(gamekindname, configInput.gameKind);
strcpy(hostname, configInput.hostServerName);
portnumber = configInput.portNmbr;
Pay attention to that there is no sense to declare character arrays with 256 characters if they store string literals with much less characters as for example
char configFile[256] = "client.conf";
It is much better to declare a pointer like
const char *configFile = "client.conf";
Shortly speaking you need to rewrite the whole program anew.
my struct format is like this
struct {
char student_ID[11];
char full_name [MAX];
char program [MAX];
char year;
char e_mail [MAX*2];
char status;
} student_info;
And this is my function which tries to get one student information
void scanStudents(FILE *file, student_info *student) {
char get_line [500];
fgets(get_line,500,file);
char *ID = strtok(get_line,";");
strcpy(student->student_ID, ID);
char *NAME = strtok(get_line, ";");
strcpy(student->full_name, NAME);
char *PROGRAM = strtok(get_line,";");
strcpy(student->program, PROGRAM);
char *YEAR = strtok(get_line, ";");
strcpy(student->year,YEAR);
char *E_MAIL = strtok(get_line, ";")
strcpy(student->e_mail,E_MAIL);
char *STATUS = strtok(get_line,";");
strcpy(student->status, STATUS);
}
I open file in other function and by calling this function in that my aim is try to store student informations in one array which type is student_ınfo. The txt file contains many student information in type of
31300000010;DURU AY;Computer Engineering;2;duru.ay#tedu.edu.tr;
Here is an example including error fixes that #Retired Ninja and #Gerhardh stated.
The file content is:
31300000010;DURU AY;Computer Engineering;2;duru.ay#tedu.edu.tr;A
Now this one is for storing each field as string. The fixes I made to your code are the following:
student_info declaration and its definition are fixed.
Add MIN_STRING to comply min String length that is 1 character + 1 NULL termination.
Change the year and status fields so that they comply the minimum string space requirements.
Add some NULL checks, perhaps to avoid corrupted student info.
Used only one pointer temp to hold the pointer address which is returned by strtok function.
This sample code is for reference only. So you adapt the idea behind this code to your actual code.
#include <stdio.h>
#include <string.h>
// Minimum string size must be 2 in order to store 1 character + terminating (NULL or '\0') character
#define MIN_STRING 2
#define MAX (50+1) // 1 character space for the NULL terminator.
struct student_info {
char student_ID[12];
char full_name [MAX];
char program [MAX];
char year[MIN_STRING];
char e_mail [MAX];
char status[MIN_STRING];
};
const char *file_name = "students.txt";
int main(void) {
FILE *file_students = fopen(file_name, "r");
if(file_students == NULL) {
printf("The file named %s could not be read\n", file_name);
return 1; // Return with some failure code
}
char get_line[500];
char *temp = NULL;
struct student_info student;
fgets(get_line, 500, file_students);
temp = strtok(get_line,";");
strcpy(student.student_ID, temp);
// After the first invocation of strtok you must pust NULL
temp = strtok(NULL, ";");
// strtok returns NULL if there are not any tokens left
if(temp == NULL) {
puts("Student ID NULL");
return 1;
}
strcpy(student.full_name, temp);
temp = strtok(NULL,";");
if(temp == NULL) {
puts("Name NULL");
return 1;
}
strcpy(student.program, temp);
temp = strtok(NULL, ";");
if(temp == NULL) {
puts("Program NULL");
return 1;
}
strcpy(student.year,temp);
temp = strtok(NULL, ";");
if(temp == NULL) {
puts("Year NULL");
return 1;
}
strcpy(student.e_mail,temp);
temp = strtok(NULL,";");
if(temp == NULL) {
puts("E-mail NULL");
return 1;
}
strcpy(student.status, temp);
puts("Sample student information");
printf(
"ID: %s\nFull name: %s\nProgram: %s\nYear: %s\nE-mail: %s\nStatus: %s\n",
student.student_ID, student.full_name, student.program, student.year,
student.e_mail, student.status
);
// Close the file
fclose(file_students);
return 0;
}
This is the output of the sample code:
Sample student information
ID: 31300000010
Full name: DURU AY
Program: Computer Engineering
Year: 2
E-mail: duru.ay#tedu.edu.tr
Status: A
I'm fairly new to C. I'm trying to read a .CSV file, then parse each line, then store the data in a dynamic array of pointers to structs. Unfortunately I've gone wrong somewhere in my implementation which is resulting in an infinite loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dataSet {
char ID;
char postcode;
int population;
char contact;
double x;
double y;
}data;
int main(int argc, char* argv[]) {
char line[100] = "";
int count = 0;
int each = 0;
data *allData = NULL;
data *temp = NULL;
FILE *file = fopen("dataset.csv", "r");
if (file == NULL)
{
printf("Error! File null");
return 1;
}
while (fgets(line, sizeof line, file))
{
if(NULL == (temp = realloc(allData, sizeof(*allData) * (count + 1))))
{
fprintf(stderr, "realloc problem\n");
fclose(file);
free(allData);
return 0;
}
allData = temp;
if (6 == scanf(line, "%s, %s, %d, %s, %lf, %lf",
&allData[count].ID,
&allData[count].postcode,
&allData[count].population,
&allData[count].contact,
&allData[count].x,
&allData[count].y)) {
count++;
}
else {
printf("Problem with data\n");
}
}
fclose(file);
for (each = 0; each < count; each++)
{
printf("%s, %s, %d, %s, %lf, %lf\n",
&allData[count].ID,
&allData[count].postcode,
&allData[count].population,
&allData[count].contact,
&allData[count].x,
&allData[count].y);
}
free(allData);
return 0;
}
Any help or tips would be greatly appreciated.
[s]scanf() is a nasty function. You don't have enough control once it fails. Problem is: there are too many conditions: the input can be incorrect, or the destination is not large enough. Even reading complete lines with fgets(), and parsing them afterwards, will only allow you to skip complete lines; also: the line buffer is mostly fixed sized, and fgets() could read incomplete lines. A way to keep complete control is to read character-based. This might imply a Finite State machine.
A simpler reader (using a zero-state machine) could be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct omg {
char o;
int m;
char g[11];
};
struct wtf {
unsigned size;
unsigned used;
struct omg *array;
};
#define INITIAL_SIZE 7
struct wtf read_stuff(char *name)
{
FILE *fp;
unsigned icol,irec,len;
char buff[123];
struct wtf this = {0,0,NULL};
fp = fopen(name, "rb" );
if (!fp) return this;
for (icol=irec=len=0; ; ) {
int ch;
if (this.used >= this.size) {
size_t newsize;
struct omg *tmp;
newsize = this.size? this.size*2: INITIAL_SIZE;
fprintf(stderr, "Realloc(%zu)\n", newsize);
tmp = realloc(this.array, sizeof *this.array * newsize);
this.array = tmp;
this.size = newsize;
}
ch = getc(fp);
switch(ch) {
case '\r' : continue;
/* End of field or record: terminate buffer */
#if 0
case ',' :
#else
case '\t' :
#endif
case '\n' :
buff[len] = 0;
break;
case EOF :
goto done;
/* Normal character: assign to buffer
** You may want to report too long fields here
*/
default:
if (len >= sizeof buff -2) continue;
buff[len++] = ch;
continue;
}
/* When we arrive here, we have a new field. Let's process it ...*/
switch (icol) {
case 0: /* Assign first field here from buff[], (dont forget to check len!) */
this.array[this.used].o = buff[0];
break;
case 1: /* Assign second field from buff[], this may need some additional checks
** You may want to avoid sscanf() here ...
*/
sscanf(buff, "%d", &this.array[this.used].m );
break;
case 2: /* Assign third field from buff[] */
if (len >= sizeof this.array[this.used].g)
len = sizeof this.array[this.used].g -1;
memcpy (this.array[this.used].g, buff, len);
this.array[this.used].g[len] = 0;
break;
default: /* Ignore excess fields
** You may want to report hem.
*/
break;
}
/* Do some bookkeeping */
len = 0;
if(ch == '\n') {
/* You may want to check if icol==2, here */
icol=0; irec++; this.used++;
}
else icol++;
}
done:
fclose(fp);
/* You could do a final realloc() here */
return this;
}
int main(int argc, char **argv)
{
struct wtf result;
unsigned idx;
result = read_stuff(argv[1] );
fprintf(stderr, "Result=%u/%u\n", result.used,result.size);
for (idx=0; idx < result.used; idx++) {
printf("%c %d %s\n"
, result.array[idx].o
, result.array[idx].m
, result.array[idx].g);
if (idx >= 10) break;
}
return 0;
}
You ask for tips...
1 - your struct is wrong if your plan was to use dynamic memory. The char members should be pointers to char, ( char * not char ) as shown below. But to reduce complexity, use char arrays instead of forcing dynamic allocation for struct members: i.e. do not use this:
typedef struct dataSet {
char *ID;
char *postcode;
int population;
char *contact;
double x;
double y;
}data;
Rather use this:
typedef struct dataSet {
char ID[80];
char postcode[11];
int population;
char contact[80];
double x;
double y;
}data;
If the lengths are not right, then make them bigger, but this will reduce calls to calloc() and free().
2 - suggested steps:
Count lines in file. (example here). This will essentially open the file, count the lines and close the file.
Use the count to allocate memory for that number of instances of data (i.e. data *records = malloc(sizeof(*records)*countOfLines); )
Open the file again. If file != NULL, then...
Begin to read file line by line in a loop, such as the fgets(...) loop you have.
In this loop, suggest replacing scanf() with a series of calls to strtok() making the appropriate conversion one-by-one. Its a few more lines of code, but is easier in the long run to see what parsing problems you might run into.
The following pseudo code illustrates...
data *record = malloc(CountOfLines*sizeof(*record));
if(record)
{
int i = 0;
while(fgets(line, sizeof line, file))
{
tok = strtok(line, ",");
if(tok)
{ //convert string
strncpy(record[i].ID, tok, sizeof(record[i].ID) - 1);
tok = strtok(NULL, ",");
if(tok)
{//convert string
strncpy(record[i].postcode, tok, sizeof(record[i].postcode) - 1);
tok = strtok(NULL, ",");
if(tok)
{//convert int
record[i].population = atoi(tok);
//and so on ...
I am having an interesting memory problem with a simple string manipulation. The problem itself isn't actually in the reading of the string but right before it when I am trying to call the string.
char *removeInvalid(char *token){
fprintf(stderr," Before: %s \n", token);
char *newToken = malloc(sizeof(100) + 1);
fprintf(stderr," After: %s \n", token);
}
Whenever I run this, the string if truncated right after the char *newToken is malloc'd. So the printout of this results in
Before: Willy Wanka's Chochlate Factory
After: Will Wanka's Chochlate F!
Anyone have any clue what this is? I looked at other examples of malloc, but can't figure out how it is going wrong here.
EDIT: FULL CODE BELOW. Take note I am a college student who just began C, so it isn't perfect by anymeans. But it works up until this error.
Function calls goes as follows. Main->initialReadAVL (This part works perfectly)
Then after commandReadAVL is called which goes commandReadAVL->ReadHelper (Again works fine here.
Then CleanUpString->removeSpaces(works fine)
Then CleanUpString->removeInvalid(THIS IS WHERE IT ERRORS)
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "node.h"
#include "avl.h"
#include "scanner.h"
#include "bst.h"
/* Options */
int avlSwitch = 0;
int bstSwitch = 0;
int insertSwitch = 0;
int deleteSwitch = 0;
int frequencySwitch = 0;
int displaySwitch = 0;
int statisticSwitch = 0;
int ProcessOptions(int argc, char **argv);
char *cleanUpString(char *token);
char *turnToLowerCase(char *token);
char *removeSpaces(char *token);
char *removeInvalid(char *token);
char *readHelper(FILE *in);
void Fatal(char *fmt, ...);
void preOrder(struct node *root);
void initialReadAVL(avl *mainAVL, FILE *in);
void initialReadBST(bst *mainBST, FILE *in);
void commandReadBST(bst *mainBST, FILE *commandList);
void commandReadAVL(avl *mainAVL, FILE *commandList);
int main(int argc, char **argv) {
struct avl *mainAVL;
struct bst *mainBST;
FILE *text;
FILE *commandList;
if(argc != 4){
Fatal("There must be 4 arguments of form 'trees -b corpus commands' \n");
}
int argIndex = ProcessOptions(argc,argv);
text = fopen(argv[2], "r");
commandList = fopen(argv[3], "r");
//Protect against an empty file.
if (text == NULL){
fprintf(stderr,"file %s could not be opened for reading\n", argv[2]);
exit(1);
}
if (commandList == NULL){
fprintf(stderr,"file %s could not be opened for reading\n", argv[3]);
exit(1);
}
if (avlSwitch){
mainAVL = newAVL();
initialReadAVL(mainAVL, text);
preOrder(mainAVL->root);
fprintf(stderr,"\n");
commandReadAVL(mainAVL, commandList);
preOrder(mainAVL->root);
fprintf(stderr,"\n");
}
else if (bstSwitch){
mainBST = newBST();
initialReadBST(mainBST, text);
preOrder(mainBST->root);
commandReadBST(mainBST, commandList);
preOrder(mainBST->root);
}
return 0;
}
void commandReadAVL(avl *mainAVL, FILE *commandList){
char *command;
char *textSnip;
while(!feof(commandList)){
command = readHelper(commandList);
textSnip = readHelper(commandList);
textSnip = cleanUpString(textSnip);
if(command != NULL){
switch (command[0]) {
case 'i':
fprintf(stderr,"%s \n", textSnip);
insertAVL(mainAVL, textSnip);
break;
case 'd':
deleteAVL(mainAVL, textSnip);
break;
case 'f':
break;
case 's':
break;
case 'r':
break;
default:
Fatal("option %s not understood\n",command);
}
}
}
}
void commandReadBST(bst *mainBST, FILE *commandList){
char *command;
char *textSnip;
while(!feof(commandList)){
command = readHelper(commandList);
textSnip = readHelper(commandList);
textSnip = cleanUpString(textSnip);
if(command != NULL){
switch (command[0]) {
case 'i':
insertBST(mainBST, textSnip);
break;
case 'd':
deleteBST(mainBST, textSnip);
break;
case 'f':
break;
case 's':
break;
case 'r':
break;
default:
Fatal("option %s not understood\n",command);
}
}
}
}
char *readHelper(FILE *in){
char *token;
if (stringPending(in)){
token = readString(in);
}
else {
token = readToken(in);
}
return token;
}
void initialReadBST(bst *mainBST, FILE *in){
char *token;
while(!feof(in)){
token = readHelper(in);
token = cleanUpString(token);
if (token != NULL){
insertBST(mainBST, token);
}
}
}
void initialReadAVL(avl *mainAVL, FILE *in){
char *token;
while(!feof(in)){
token = readHelper(in);
token = cleanUpString(token);
if (token != NULL){
insertAVL(mainAVL, token);
}
}
}
//Helper Function to clean up a string using all the prerequisites.
char *cleanUpString(char *token){
char *output = malloc(sizeof(*token)+ 1);
if (token != NULL){
output = removeSpaces(token);
fprintf(stderr,"before : %s \n", output);
output = removeInvalid(output);
fprintf(stderr,"%s \n", output);
output = turnToLowerCase(output);
return output;
}
return NULL;
}
//Helper function to turn the given string into lower case letters
char *turnToLowerCase(char *token){
char *output = malloc(sizeof(*token) + 1);
for (int x = 0; x < strlen(token); x++){
output[x] = tolower(token[x]);
}
return output;
}
//Helper function to remove redundent spaces in a string.
char *removeSpaces(char *token){
char *output;
int x = 0;
int y = 0;
while (x < strlen(token)){
if (token[x]== ' ' && x < strlen(token)){
while(token[x] == ' '){
x++;
}
output[y] = ' ';
y++;
output[y] = token[x];
y++;
x++;
}
else {
output[y] = token[x];
y++;
x++;
}
}
return output;
}
char *removeInvalid(char *token){
fprintf(stderr," Before: %s \n", token);
char *newToken = malloc(sizeof(* token)+ 1);
fprintf(stderr," After: %s \n", token);
int x = 0;
int y = 0;
while (x < strlen(token)){
if (!isalpha(token[x]) && token[x] != ' '){
x++;
}
else {
newToken[y] = token[x];
y++;
x++;
}
}
return newToken;
}
//Processes a system ending error.
void Fatal(char *fmt, ...) {
va_list ap;
fprintf(stderr,"An error occured: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(-1);
}
//Processes the options needed to be executed from the command line
int ProcessOptions(int argc, char **argv) {
int argIndex;
int argUsed;
int separateArg;
argIndex = 1;
while (argIndex < argc && *argv[argIndex] == '-')
{
/* check if stdin, represented by "-" is an argument */
/* if so, the end of options has been reached */
if (argv[argIndex][1] == '\0') return argIndex;
separateArg = 0;
argUsed = 0;
if (argv[argIndex][2] == '\0')
{
separateArg = 1;
}
switch (argv[argIndex][1])
{
case 'b':
bstSwitch = 1;
break;
case 'a':
avlSwitch = 1;
break;
default:
Fatal("option %s not understood\n",argv[argIndex]);
}
if (separateArg && argUsed)
++argIndex;
++argIndex;
}
return argIndex;
}
void preOrder(struct node *root) {
if(root != NULL)
{
fprintf(stderr,"%s ", root->key);
preOrder(root->lChild);
preOrder(root->rChild);
}
}
ReadString()
char *
readString(FILE *fp)
{
int ch,index;
char *buffer;
int size = 512;
/* advance to the double quote */
skipWhiteSpace(fp);
if (feof(fp)) return 0;
ch = fgetc(fp);
if (ch == EOF) return 0;
/* allocate the buffer */
buffer = allocateMsg(size,"readString");
if (ch != '\"')
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"first character was <%c>\n",ch);
exit(4);
}
/* toss the double quote, skip to the next character */
ch = fgetc(fp);
/* initialize the buffer index */
index = 0;
/* collect characters until the closing double quote */
while (ch != '\"')
{
if (ch == EOF)
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"no closing double quote\n");
exit(6);
}
if (index > size - 2)
{
++size;
buffer = reallocateMsg(buffer,size,"readString");
}
if (ch == '\\')
{
ch = fgetc(fp);
if (ch == EOF)
{
fprintf(stderr,"SCAN ERROR: attempt to read a string failed\n");
fprintf(stderr,"escaped character missing\n");
exit(6);
}
buffer[index] = convertEscapedChar(ch);
}
else
buffer[index] = ch;
++index;
ch = fgetc(fp);
}
buffer[index] = '\0';
return buffer;
}
INPUT: Commands.txt
i "Willy Wonka's Chochlate Factory"
INPUT testFile.txt
a b c d e f g h i j k l m n o p q r s t u v w x y z
Thanks!
char *turnToLowerCase(char *token){
char *output = malloc(sizeof(*token) + 1);
for (int x = 0; x < strlen(token); x++){
output[x] = tolower(token[x]);
}
return output;
}
This is probably your main issue. You allocate enough space for two characters and then proceed to store lots more than that. You probably wanted:
char *output = malloc(strlen(token) + 1);
Since token is a char*, *token is a char. So sizeof(*token) is sizeof(char) -- definitely not what you want.
You almost certainly have a buffer overrun in some part of the code that you're not showing us. If I were to guess, I'd say you allocate too little storage for token to contain the full string you're writing into it in the first place.
Did you by any chance allocate token using the same erroneous code you have in removeInvalid():
malloc(sizeof(100) + 1);
^^^^^^^^^^^ this doesn't allocate 101 characters, it allocates sizeof(int)+1
char *readHelper(FILE *in){
char * token = malloc(sizeof(char *) + 1);
if (stringPending(in)){
token = readString(in);
}
else {
token = readToken(in);
}
return token;
}
It's hard to make sense of this without being able to see readString or readToken, but this can't possibly be right.
First, you allocate one more byte than is needed for a pointer to one or more characters. What use would such a thing be? If you're not storing a pointer to one or more characters, why use sizeof(char *)? If you are storing a pointer to one or more characters, why add one? It's hard to imagine the reasoning that lead to that line of code.
Then, in the if, you immediately lose the value you got back from malloc because you overwrite token by using it to store something else. If you weren't going to use the value you assigned to token, why did you assign it at all?
Bluntly, a lot of this code simply doesn't make any sense. Without comments, it's hard to understand the reasoning so we could point out what's wrong with it.
Either there was reasoning behind that line of code, in which case it's just completely wrong reasoning. Or worse, the line of code was added with no reasoning in the hopes it would work somehow. Neither method will produce working code.
When you're trying to debug code, first remove anything you added experimentally or that you didn't understand. If you do understand malloc(sizeof(char *) + 1), then please explain what you think it does so that your understanding can be corrected.
Why did you think you needed a buffer that was one byte larger than the size of a pointer to one or more characters?
With the help of David Schwartz and the other posters I was able to find the bug in my problem. When I was allocating memory for my token/output, I wasn't allocating enough space.. Using the erroneous code of
malloc(sizeof(100) + 1);
and
malloc(sizeof(*token) + 1);
both of which produced only a couple of bytes to be allocated. This caused a buffer problem causing random letters and numbers/ truncation to happen. The first resulting in the space equivalent to int + 1 and the second in char + 1. (as I was taking the sizeof token which is just the size of what it originally started as, a char)
To fix this I changed the allocation of my token variable to that of
malloc(strlen(token) + 1);
This allocates a space equivalent to the "string" length of token + 1. Allowing the appropriate space for my problem which would end up with space of <= token.
I have been working on the following bit of code and am having trouble with my file handling operations.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
int lineCount=0;
char line[200];
char *lineArray[lineCount];
char *CityName[20];
double longitudinal[10];
double latitudinal[10];
int serialno[10];
char *token;
const char j=' ';
int x=0,p=0;
FILE *file;
file=fopen("chota.txt","r");
if(file==NULL)
{
printf("file is not opened properly\n");
return -1;
}
//below one to give total number of lines.
while ((fgets(line,sizeof(line),file)) != NULL)
{
lineCount++;
}
lineArray = (char *)malloc(sizeof(char *)*lineCount);
rewind(file);
printf("The total number of cities in the file is: %d\n",(lineCount-1));
fgets(line,sizeof(line),file);//moves file pointer to beg of 2nd line
while ((fgets(line,sizeof(line),file)) != NULL)
{
lineArray[p]=malloc(strlen(line));//1st bunch of memory allocated
strcpy(lineArray[p],line);
printf("%s\n",lineArray[p]);
token = strtok(lineArray[p],j);
//printf("%s\n",token);
serialno[p]=atoi(token);
printf("%d\n",serialno[p]);
x=1;
/* walk through other tokens */
while( token != NULL )
{
//printf( " %s\n", token );
if((x%4)==1)
{
//longitudinal[p] =malloc(strlen(token));
longitudinal[p] =atof(token);
}
else if((x%4)==2)
{
//latitudinal[p]=malloc(strlen(token));
latitudinal[p]=atof(token);
}
else if((x%4)==3)
{
CityName[p] = malloc(strlen(token));
strcpy(CityName[p],token);
printf("%s\n",CityName[p]);
}
token = strtok(NULL, j);
x++;
} //end of inner while
p++;
}//end of outer while
}//end of main
The file that I am using is:
City_No Latitude Longitude City_Name
1 12.58 77.38 Bangalore
2 14.18 74.55 JogFalls
3 15.09 76.55 Bellary
4 26.48 84.33 Bettiah
5 25.37 85.13 Patna
6 19.18 84.51 Berahampur
7 20.15 85.51 Bhuvneshwar
8 25.30 90.30 Shillong
The problem is that I have been trying this for the past few days and I keep getting errors. I am not getting anywhere with debugging and cannot figure out where I am going wrong.
The array is better declared and allocated like this:
char **lineArray;.
lineArray = (char **)malloc(sizeof(char *) * (lineCount-1));
strtok take a string as second argument.
Replace const char j=' '; by const char *j=" ";
Get rid of the first strtok:
lineArray[p]=malloc(strlen(line));//1st bunch of memory allocated
strcpy(lineArray[p],line);
printf("%s\n",lineArray[p]);
//token = strtok(lineArray[p],j);
//printf("%s\n",token);
//serialno[p]=atoi(token);
//printf("%d\n",serialno[p]);
x=1;