I keep getting the same error, I'm new to programming so I'm not so sure if the Syntax is correct.
Every time I run it, it returns Segmentation Fault(core dumped), I'm not even sure If I can open a file with a string (address) instead of the filename in extense.
Also the files I'm reading from are CSV but in txt format.
I'm using C99
#define BUFFER_SIZE 1024
#define TAM_PERGUNTAS 128
struct question{
char category[TAM_PERGUNTAS];
char question[TAM_PERGUNTAS];
char option1[TAM_PERGUNTAS];
char option2[TAM_PERGUNTAS];
char option3[TAM_PERGUNTAS];
char correct[TAM_PERGUNTAS];
};
struct question vec_question[BUFFER_SIZE];
void questions() {
FILE *perguntas;
int numaleat=0;
int num_questions, counter = 0, index, temp_randomizer=0;
char line[BUFFER_SIZE];
char answer[32];
char address[TAM_PERGUNTAS];
address[0] = '\0';
srand(time(NULL));
printf("Digite agora o numero de perguntas desejadas.(MAX 20) : "); //Insert Number of questions
scanf("%d", &num_questions);
printf("\n");
for (counter = 0; counter < num_questions; counter++) {
temp_randomizer = rand() % j; //j Represents the number o CATEGORIES at play and acts as a marker in the SELECTION string
sprintf(address, "%s.txt", SELECTION[temp_randomizer]);
perguntas = fopen(address, "r");
if (perguntas == NULL) {
printf("ERROR OPENING FILE!");
}
index = 0;
while (fgets(line, sizeof(line), perguntas) != NULL) {
strcpy(vec_question[index].category, strtok(line, ";"));
strcpy(vec_question[index].question, strtok(NULL, ";"));
strcpy(vec_question[index].option1, strtok(NULL, ";"));
strcpy(vec_question[index].option2, strtok(NULL, ";"));
strcpy(vec_question[index].option3, strtok(NULL, ";"));
strcpy(vec_question[index].correct, strtok(NULL, ";"));
vec_question[index].correct[strlen(vec_question[index].correct) - 1] = '\0';
index++;
}
fclose(perguntas);
index = 20;
numaleat = rand() % index;
printf("%s : %s\n%s\n%s\n%s",vec_question[numaleat].category,vec_question[numaleat].question,vec_question[numaleat].option1,vec_question[numaleat].option2,vec_question[numaleat].option3);
for (int i = 0; i < num_users; i++) {
printf("\n%s: ", &users[i][20]);
scanf("%s", &answer[32]);
if (answer == vec_question[numaleat].correct)
userspoints[i] += 1;
}
}
}
In general one should assume that functions like strtok can fail.
Sometimes it fails and returns a NULL value. A short record in your input is a likely cause.
Consider using it with a loop, and breaking out of the loop once strtok returns NULL.
I found a simple example here.
#include <string.h>
#include <stdio.h>
int main () {
char str[80] = "This is - www.tutorialspoint.com - website";
const char s[2] = "-";
char *token;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, s);
}
return(0);
}
Note that it does one strtok to get the first token. That might return NULL in which case the loop doesn't run. If it doesn't return NULL then it prints that token, and asks strtok for the next token. It keeps doing that until strtok returns NULL.
Related
I have to write this code, I mean I should read from the file name of students and their mark, and then sort students by the grow of mark. Now I just want to output only mark. I want to display grades using structures. I don't know where the problem is.
text.file
Jon 3
Alina 5
Ron 1
#include <stdio.h>
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
int main()
{
const int N = 3;
int i = 0;
struct student {
char surname[50];
int mark;
};
struct student PI1[N];
char str[50];
const char s[1] = " ";
char* token;
FILE* ptr;
token = strtok(str, s);
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
printf("file can't be opened \n");
}
while (fgets(str, 50, ptr) != NULL){
token = strtok(str, s);
strcpy(PI1[i].surname, token);
token = strtok(NULL, s);
PI1[i].mark = atoi(token);
i++;
}
fclose(ptr);
printf("The marks is:\n");
printf("%d %d %d", PI1[0].mark, PI1[1].mark, PI1[2].mark);
return 0;
}
You need to prevent the program from reading from the file pointer if opening the file fails:
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
perror("test.txt");
return 1; // this could be one way
}
The second argument to strok should be a null terminated string. const char s[1] = " "; only has room for one character. No null terminator (\0). Make it:
const char s[] = " "; // or const char s[2] = " "; or const char *s = " ";
Don't iterate out of bounds. You need to check so that you don't try to put data in PI1[N] etc.
while (i < N && fgets(str, sizeof str, ptr) != NULL) {
// ^^^^^^^^
Check that strok actually returns a pointer to a new token. If it doesn't, the line you've read doesn't fulfill the requirements.
while (i < N && fgets(str, sizeof str, ptr) != NULL) {
token = strtok(str, s);
if(!token) break; // token check
strcpy(PI1[i].surname, token);
token = strtok(NULL, s);
if (token) // token check
PI1[i].mark = atoi(token);
else
break;
i++;
}
You could also skip the strcpy by reading directly into your struct student since char str[50]; has the same length as surname. str should probably be larger though, but for now:
while (i < N && fgets(PI1[i].surname, sizeof PI1[i].surname, ptr) != NULL) {
token = strtok(PI1[i].surname, s);
if(!token) break;
token = strtok(NULL, s);
if (token)
PI1[i].mark = atoi(token);
else
break;
i++;
}
Only print as many marks as you successfully read
printf("The marks are:\n");
for(int idx = 0; idx < i; ++idx) {
printf("%d ", PI1[idx].mark);
}
putchar('\n');
I'm not sure where I'm messing up so I've given a summary of each function so my logic can be checked!
The main program takes arguments from the command line and stores them in char pointer array.
The correct command to run program is ./re-do_hw4_prob6 filename. (filename is sears_kmart_stores_closing_2019.txt in this case)
After checking if argument number is correct, the file is opened.
A while loop copies strings of text from file to buffer until NULL is met.
Then the function getState() is called. The state is printed.
The file is closed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "redo_hw4_functs.h"
int main(int argc, char* argv[])
{
char** states;
FILE* pFile;
char buffer[80];
int i = 0;
if(argc < 2){
printf("Too few arguments! \n");
}
else if(argc > 2){
printf("Too many arguments! \n");
}
pFile = fopen(argv[1], "r");
states = malloc(50*sizeof(char));
for (i = 0; i < 50; i++)
{
states[i] = malloc(3*sizeof(char));
while(fgets(buffer, sizeof(buffer), pFile) != NULL)
{
getState(states[i], buffer);
printf("State: %s \n", states[i]);
}
}
fclose(pFile);
}
The getState() function takes in two char arrays. One to read from the other to copy too.
It tokenizes the string being read from using a comma, a tab, and a new line as the delimiters. -> ",\t\n"
On the last token it copies the last two chars to the empty string array.
//accepts a line of string formatted as expected and stores the store state in char file ¡OJO! This is the hardest one because you cant rely on delimeters alone to find state
void getState(char strState[], char strLine[])
{
int i;
char* token;
char delim[] = ",\t\n";
token = strtok(strLine, delim);
token = strtok(strLine, delim);
token = strtok(strLine, delim);
for(i = (strlen(token) - 2); i < strlen(token); i++)
{
strState[i] =token[i];
}
}
I have also included my other functions to see if there are any other mistakes to be corrected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "redo_hw4_functs.h"
//accepts a line of string formatted as expected and stores the store name in char file
void getName(char strName[], char strLine[])
{
char* token;
char delim[] = " ,\t\n";
token = strtok(strLine, delim);
while(token != NULL)
{
if(strcmp(token, "sears") == 0 || strcmp(token, "kmart"))
{
strcpy(strName, token);
break;
}
token = strtok(NULL, delim);
}
}
//accepts a line of string formatted as expected and stores the store address in char file
void getAddress(char strAddress[], char strLine[])
{
char* token;
char delim[] = ",\t\n";
token = strtok(strLine, delim);
while(token != NULL)
{
if(isdigit(token[0]) && isalpha(token[sizeof(token)-1]))
{
strcpy(strAddress, token);
break;
}
token = strtok(NULL, delim);
}
}
//accepts a line of string formatted as expected and stores the store city in char file
void getCity(char strCity[], char strLine[])
{
int i;
char* token;
char delim[] = ",\t\n";
token = strtok(strLine, delim);
token = strtok(strLine, delim);
token = strtok(strLine, delim);
for(i = 0; i < (strlen(token) - 3); i++)
{
strcpy(strCity[i], token[i]);
}
}
//accepts a line of string formatted as expected and stores the store state in char file ¡OJO! This is the hardest one because you cant rely on delimeters alone to find state
void getState(char strState[], char strLine)
{
int i;
char* token;
char delim[] = ",\t\n";
token = strtok(strLine, delim);
token = strtok(strLine, delim);
token = strtok(strLine, delim);
for(i = (strlen(token) - 2); i < strlen(token); i++)
{
strcpy(strState[i], token[i]);
}
}
Here is an example of input text that is to be read:
Kmart, 217 Forks Of River Pkwy, Sevierville TN
Kmart, 4110 E Sprague Ave, Spokane WA
Kmart, 1450 Summit Avenue, Oconomowoc WI
Sears, 2050 Southgate Rd, Colorado Spgs CO
Sears, 1650 Briargate Blvd, Colorado Spgs CO
Sears, 3201 Dillon Dr, Pueblo CO
Here is an example of what the program is expected to be outputting:
State:TN
State:WA
State:WI
State:CO
State:CO
State:CO
Here is an example of what the program is outputting:
I assume that you want not only the status but also all the other fields so that you can deal with them later.
The code below may be quite different from yours, but I think that it is easier to use a single function to read each record.
The function read_data() reads data from the file pointer fp and store them in data, which is a pointer to a predefined struct data_t.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 1024
typedef struct {
char name[64];
char addr[64];
char city[64];
char state[8];
} data_t;
int read_data(FILE *fp, data_t *data) {
char buffer[BUFFER_SIZE];
// Read a record. If end-of-file is read, return -1.
if (fgets(buffer, BUFFER_SIZE, fp) == NULL) {
return -1;
}
char delim[] = ",\t\n";
// Find the name of the record.
char *token = strtok(buffer, delim);
strcpy(data->name, token);
// Find the address of the record.
token = strtok(NULL, delim);
while (*token == ' ') {
++token;
}
strcpy(data->addr, token);
// Find the city and status of the record.
// We cannot split them by strtok() easily, so we handle it later.
token = strtok(NULL, delim);
while (*token == ' ') {
++token;
}
// Find the position of the state.
char *ptr = token;
while (*ptr != '\0') {
++ptr;
}
ptr -= 2;
strcpy(data->state, ptr);
// Use NULL to separate the city and the state so that we can use strcpy().
while (*(ptr - 1) == ' ') {
--ptr;
}
*ptr = '\0';
// Copy the city field.
strcpy(data->city, token);
return 0;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "The number of arguments is incorrect.\n");
fprintf(stderr, "Usage: %s filename\n", argv[0]);
return -1;
}
FILE *fp = fopen(argv[1], "r");
data_t *data = malloc(sizeof(data_t));
while (read_data(fp, data) == 0) {
printf("State: %s\n", data->state);
}
free(data);
fclose(fp);
return 0;
}
The way to read data is hard-coded, so if the input format is different, you may need to change the content of read_data(), but it works well for your sample input.
Somehow I can't get this to display correctly, no matter how i rearrange things. I should be able to accomplish this without using malloc, by the way.
void ArrayFormatter(FILE* cipherKey)
{
char line[1000];
char* fileWords[5000];
static int wordCount = 0;
//This loop stores each word into its corresponding position in an array
while(fgets(line, 1000, cipherKey) != NULL)
{
fileWords[wordCount] = strtok(line, " ");
fprintf(stdout, "_%s_", fileWords[wordCount]); //test
wordCount++;
for(i = 0; i < sizeof(line) - 1; i++)
{
fileWords[wordCount] = strtok(NULL, " ");
if(fileWords[wordCount] == NULL)
break;
fprintf(stdout, "_%s_", fileWords[wordCount]); //test
wordCount++;
}
}
fprintf(stdout, "\n\n\n");
//Issue here is that it's not displaying the same values that it is above
//This loop displays current strings, in order, in array
for(i = 0; i < wordCount; i++)
{
fprintf(stdout, "_%s_", fileWords[i]);
}
I should be able to accomplish this without using malloc, by the way.
You can do it without malloc, but you will need a large stack, and to change the following line:
char* fileWords[5000];
To:
char fileWords[5000][anticipated largest string length+1];
And, create a char *buf={0}; (or similar) to use with strtok
As mentioned in the comments, there are other problems in your code.
If you should decide to use malloc...
Three Four suggestions to make initial debugging easier:
0) Allocate memory for each char* fileWords[5000]; before using, free after.
1) make sure the delimiter contains the right values.
2) check the return coming out of strtok.
3) move the print loop out of the read/parse loop.
char *buf={0};
int wordCount = 0;
while(fgets(line, 1000, cipherKey) != NULL)
{
buf = strtok(line, " ");//are you certain this is the right delimiter list?
while(buf)//check the return of strtok before using
{
fileWords[wordCount] = malloc(strlen(buf)+1);
strcpy(fileWords[wordCount], buf);//store intermediate results
wordCount++;
buf = strtok(line, NULL);//get new token from string
}
}
for(i = 0; i < wordCount; i++)
{
fprintf(stdout, "_%s_", fileWords[i]); //test
free(fileWords[i]);
}
Here's the corrected code. It has a few more safety checks for array overflow and blank lines. On the odd chance that no malloc was a requirement, I've added a "non malloc" version of strdup(3) [please pardon the gratuitous style cleanup]:
#define LINESIZE 1000
#define WORDMAX 5000
#define BUFMAX ((WORDMAX + 1) * LINESIZE)
char strarea[BUFMAX];
char *strptr;
// xstrdup -- "no malloc" version of strdup(3)
char *
xstrdup(const char *src)
{
int len = strlen(src) + 1;
char *dst;
if (strptr == NULL)
strptr = strarea;
dst = strptr;
strptr += len;
memcpy(dst,src,len);
return dst;
}
void
ArrayFormatter(FILE *cipherKey)
{
char line[LINESIZE];
char *bp;
char *cp;
char *fileWords[WORDMAX];
int wordCount = 0;
// This loop stores each word into its corresponding position in an array
while (fgets(line, sizeof(line), cipherKey) != NULL) {
bp = line;
for (; wordCount < WORDMAX; ++wordCount) {
cp = strtok(bp, " ");
bp = NULL;
if (cp == NULL)
break;
// standard way or if no malloc is hard requirement, use xstrdup
#if 1
fileWords[wordCount] = strdup(cp);
#else
fileWords[wordCount] = xstrdup(cp);
#endif
fprintf(stdout, "_%s_", fileWords[wordCount]); // test
}
if (wordCount >= WORDMAX)
break;
}
fprintf(stdout, "\n\n\n");
// Issue here is that it's not displaying the same values that it is above
// This loop displays current strings, in order, in array
for (i = 0; i < wordCount; i++) {
fprintf(stdout, "_%s_", fileWords[i]);
}
#if 0
for (i = 0; i < wordCount; i++) {
free(fileWords[i]);
}
#endif
}
the following code
cleanly compiles
performs the desired functions
does not use malloc() nor calloc() nor realloc()
is limited to words with a max length of 49 characters
is limited to 5000 words
and now the code
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LEN (1000)
#define MAX_WORDS (5000)
#define MAX_WORD_LEN (50)
void ArrayFormatter(FILE* cipherKey)
{
char line[MAX_LINE_LEN];
size_t wordCount = 0;
static char fileWords[ MAX_WORDS ][ MAX_WORD_LEN ];
//This loop stores each word into its corresponding position in an array
while(wordCount < MAX_WORDS && fgets(line, MAX_LINE_LEN, cipherKey) )
{
char * token = strtok(line, " ");
while( token )
{
strncpy( fileWords[wordCount], token, MAX_WORD_LEN);
fprintf(stdout, "_%s_", fileWords[wordCount]); // test
wordCount++;
token = strtok(NULL, " ");
}
}
fprintf(stdout, "\n\n\n");
//This loop displays current strings, in order, in array
for(size_t i = 0; i < wordCount; i++)
{
fprintf(stdout, "_%s_", fileWords[i]);
}
} // end function: ArrayFormatter
I am getting a segmentation fault error. When I comment out "wordlength = strlen(token);" it runs fine. I don't know why it the seg fault happens when I assign a strlen(token) just fine to an int a few lines before this one. I would appreciate any help possible.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define char_max 60
int main(int argc, char *argv[])
{
FILE *fp = fopen(argv[2],"r");
char **wordlist;
int row = 1;
int i;
char temp[100];
char *token;
int wordlength;
int lengthcounter;
wordlist = (char**)malloc(row*sizeof(char*));
for(i = 0; i < row; i++)
{
wordlist[i] = (char*)malloc(char_max*sizeof(char*));
}
while(fgets(temp, sizeof(temp), fp) != NULL)
{
lengthcounter = 0;
wordlength = 0;
token = strtok(temp, " ");
strcat(wordlist[row-1], token);
printf("%s\n", wordlist[row-1]);
lengthcounter = strlen(token);
while(token != NULL)
{
token = strtok(NULL, " ");
wordlength = strlen(token);
/*lengthcounter += wordlength;*/
}
printf("The lengthcounter is %d\n", lengthcounter);
}
free(wordlist);
fclose(fp);
return 0;
}
while(token != NULL)
{
token = strtok(NULL, " ");
wordlength = strlen(token);
/*lengthcounter += wordlength;*/
}
What happens in the last iteration of the loop when token is NULL? You pass it to strlen anyway.
Also, this is almost certainly wrong:
wordlist[i] = (char*)malloc(char_max*sizeof(char*));
You're allocating space for pointers, not characters. So why sizeof(char*)? Also, don't cast the return value of malloc. This is C, not C++.
Does anyone know why my program doesn't read from my delimited file? I thought it would print everything from my delimited file after the program ran through my printPropertyListing() method at the bottom but instead it gives me the error message warning "warning: comparison between pointer and integer". It's telling me the error is on the beginning line of my for loop in the main method. Any solutions please?
Here is what my delimited file looks like:
123 Cherry Tree Drive#330#Condo#2#1#275900#Toronto#
14 Leaside Lane#N/A#House#4#2#445500#Brampton#
2478 Waterfront Avenue#N/A#House#5#3#899900#Mississauga#
7 Lucky Lane#1206#Condo#3#2#310000#Toronto#
51 West Street#32#Townhouse#4#2#450000#Brampton#
193 Crystal Road#1519#Condo#1#1#250750#Toronto#
3914 Tangerine Terrace#N/A#House#3#1#427750#Mississauga#
10 Redding Road#N/A#House#4#2#512350#Toronto#
76 Old School Avenue#227#Townhouse#3#2#475000#Toronto#
90 Brookhaven Terrace#N/A#House#4#2#512750#Brampton#
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char buildingType[10];
int numBedrooms;
int numBathrooms;
}Propertylisting;
typedef struct {
Propertylisting propertylisting;
char address[100];
char unitNum [10];
char city [50];
int listPrice;
} Listing;
void parseListings(FILE *in, Listing listing[], int arraySize);
void printPropertyListing(Listing l);
int main()
{
Listing listing[10];
FILE *fp = fopen("PropertyListings.txt", "r");
if (fp == NULL)
{
printf("Could not open file!");
exit(1);
}
else
{
parseListings(fp, listing, 10);
if (listing == 0)
{
printf("No Property data found.");
exit(1);
}
printf("\nNumber of listings in file: %d\n\n", listing);
int i;
for (i = 0; i < listing; i++)
{
printPropertyListing(listing[i]);
printf("\n");
}
fclose(fp);
}
return 0;
}
void parseListings(FILE *in, Listing listing[], int arraySize)
{
// Holds the current index of the Listing array
int n = 0;
// Set value as empty string
char line[256];
// A token pointer that the strtok() function returns
char *token;
char *delimiter = "#";
while (!feof(in)&& n > arraySize)
{
fgets(line, 256, in);
// Read the address
token = strtok(line, delimiter);
strcpy(listing[n].address, token);
// Read the unitNum
token = strtok(NULL, delimiter);
strcpy(listing[n].unitNum, token);
// Read the building typede
token = strtok(NULL, delimiter);
strcpy(listing[n].propertylisting.buildingType, token);
token = strtok(NULL, delimiter);
int numBedrooms = strtol(token, NULL, 10);
listing[n].propertylisting.numBedrooms = numBedrooms;
token = strtok(NULL, delimiter);
int numBathrooms = strtol(token, NULL, 10);
listing[n].propertylisting.numBathrooms = numBathrooms;
token = strtok(NULL, delimiter);
int listPrice = strtol(token, NULL, 10);
listing[n].listPrice = listPrice;
token = strtok(NULL, delimiter);
strcpy(listing[n].city, token);
n++;
}
return n;
}
void printPropertyListing(Listing l)
{
printf("%s %s %s\n%s %d %d %d\n\n",
l.address,
l.unitNum,
l.city,
l.propertylisting.buildingType,
l.propertylisting.numBedrooms,
l.propertylisting.numBathrooms,
l.listPrice);
}
The problem is in your for loop:
for (i = 0; i < listing; i++)
i is of type int and listing is of type Listing [10];
As pointed out by others, your listing variable is an array (which is actually a pointer to the start of a block of memory being used as an array). This means you are attempting to compare a pointer to an int, which does not make sense.
It looks like you are trying to compare to the size of the array, and since your parseListings function already returns the number of listings it has parsed, you can instead do the following:
int numListings = parseListings(fp, listing, 10);
if (numListings == 0) {
printf("No Property data found.");
exit(1);
}
printf("\nNumber of listings in file: %d\n\n", numListings);
int i;
for (i = 0; i < numListings; i++) {
printPropertyListing(listing[i]);
printf("\n");
}
You will note that I changed a few other locations where you were also using the listing variable, but I suspect you had wanted to check against the number of listings.
In addition to this, there is the points which Jens made about other bugs in your program, which would make this the perfect time to learn about the while 1: ... break; paradigm.
while (n < arraySize) {
fgets(line, 256, in);
if(feof(in)) {
break;
}
Credit to other people for pointing out all of these bugs; I have just attempted to formulate all of their responses into a single coherent guide to things you should consider for improving this code specifically and all of your code in general.
Edit: additionally, the return type of parseListing should be changed to int in order to match the fact that you return n;