Strtok() problems when I call a function within the loop - c

The program prints all the outputs from the file I expect it to if I comment out the second line however if I re-add it the tokens reach null earlier and only 2 words from the file are printed any problems I'm missing?
printf("%s\n",texttoken);
fprintf(resultptr,"%s ",filterer(redwords,lowercase(texttoken)));
The rest of the code is below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(){
char *filterer(char* redwords, char* word);
char *lowercase(char *word);
FILE *redptr;
FILE *textptr;
FILE *resultptr;
char *redwords = malloc(20);
char *text = malloc(255);
char *texttoken;
char *temp;
redptr = fopen("redfile.txt", "r");
textptr = fopen("textfile.txt", "r");
resultptr = fopen("result.txt", "w");
fgets(redwords,20,redptr);
redwords = lowercase(redwords);
fgets(text,255,textptr);
texttoken = strtok(text, " ");
while(texttoken != NULL){
printf("%s\n",texttoken);
fprintf(resultptr,"%s ",filterer(redwords,lowercase(texttoken)));
texttoken = strtok(NULL, " ");
}
}
char *filterer(char *redwords, char *word){
int match = 0;
char *token;
token = strtok(redwords, ",");
while(token != NULL) {
if(strcmp(word,token)==0){
match = 1;
}
token = strtok(NULL, ",");
}
if(match == 1){
int i;
int len = strlen(word);
char modified[len+1];
modified[len] = NULL;
for(i=0; i<len; i++){
modified[i] = '*';
}
return modified;
}
return word;
}
char *lowercase(char *word){
int i;
for(i=0; i<=strlen(word); i++){
if(word[i]>=65&&word[i]<=90)
word[i]=word[i]+32;
}
return word;
}

At least these problems:
Return of invalid pointer
return modified; returns a pointer to a local array. Local arrays become invalid when the function closes.
char modified[len+1];
modified[len] = NULL;
for(i=0; i<len; i++){
modified[i] = '*';
}
return modified; // Bad
Save time: Enable all warnings
Example: warning: function returns address of local variable [-Wreturn-local-addr]
Nested use of strtok()
Both this loop and filterer() call strtok(). That nested use is no good. Only one strtok() should be active at a time.
while(texttoken != NULL){
printf("%s\n",texttoken);
fprintf(resultptr,"%s ",filterer(redwords,lowercase(texttoken)));
texttoken = strtok(NULL, " ");
}
Since filterer() is only looking for a ',', look to strchr() as a replacement.

Related

How to read from the file and write it in the structure? I have a little trouble with my code

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');

Passing back C struct with a char pointer array included fails

I'm struggling with this split function based on C. After returning the struct by reference from the strSplit() function the token handle seems wrong. The variable sd->tokens is the right address, but I cannot get the tokens. But they are correct because inside the function I can get it.
How can I resolve this and what is the reason for this behavior. All remaining variables in the struct are ok.
#include <stdio.h>
#include <string.h>
struct splitResult {
char *source;
long lSource;
int result;
char **tokens;
};
typedef struct splitResult splitResultStruct;
splitResultStruct * strSplit(char *source, char *delimiter);
int main(int argc, const char * argv[]) {
char *source = "part1.part2.part3";
splitResultStruct *sd;
sd = strSplit(source, ".");
printf("%d tokens found\n", sd->result);
for(int i=0; i<sd->result; i++) {
printf("%s\n", sd->tokens[i]);
}
return 0;
}
splitResultStruct * strSplit(char *source, char *delimiter) {
// Defines the result struct
splitResultStruct sData, *sDataPtr;
sDataPtr = &sData;
sData.source = source;
// Gets the length of source string
sData.lSource = strlen(source);
// Don't split if empty string is given
if(sData.lSource == 0) {
sData.result = -1;
return sDataPtr;
}
// Allocate memory according teh size of source string
char data[sData.lSource];
// Copy the source into the allocated memory
strcpy(data,source);
// Just count the tokens
char *token = strtok(data, delimiter);
int tc = 0;
while (token != NULL)
{
token = strtok(NULL, delimiter);
tc++;
}
if(tc == 0) {
sData.result = -1;
return sDataPtr;
}
// Defines an array of char pointer with the dimension of the number of tokens
sData.result = tc;
char *tokens[tc];
// Resets the token engine
strcpy(data,source);
// Strip out the first token found
token = strtok(data, delimiter);
tokens[0] = token;
tc = 0;
while (token != NULL)
{
// Strip out one token and store them into the token array
token = strtok(NULL, delimiter);
tc++;
tokens[tc] = token;
}
sData.tokens = tokens;
for(int i=0; i<sData.result; i++) {
printf("%s\n", sData.tokens[i]);
}
return sDataPtr;
}
Remember, never return a pointer to local variable.
Local variables are destoryed when the function returns.
Try:
sDataPtr = malloc(sizeof(splitResultStruct));
Or:
static splitResultStruct sData;
splitResultStruct* sDataPtr;
Ok, guys, got it regarding the struct memory. Changed the code to this version, so the struct will be declared in main and a pointer is passed. The functions returns nothing but changes the struct itself. But the tokens remains empty. Not a clue...
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct splitResult {
char *source;
long lSource;
int result;
long tSize;
char **tokens;
};
typedef struct splitResult splitResultStruct;
void strSplit(splitResultStruct *, char *source, char *delimiter);
int main(int argc, const char * argv[]) {
char *source = "part1.part2.part3";
splitResultStruct sd;
strSplit(&sd, source, ".");
printf("%d tokens found\n", sd.result);
for(int i=0; i<sd.result; i++) {
printf("%s\n", sd.tokens[i]);
}
return 0;
}
void strSplit(splitResultStruct *sData, char *source, char *delimiter) {
sData->source = source;
// Gets the length of source string
sData->lSource = strlen(source);
// Don't split if empty string is given
if(sData->lSource == 0) {
sData->result = -1;
}
// Allocate memory according teh size of source string
char data[sData->lSource];
// Copy the source into the allocated memory
strcpy(data,source);
// Just count the tokens
char *token = strtok(data, delimiter);
int tc = 0;
while (token != NULL)
{
token = strtok(NULL, delimiter);
tc++;
}
if(tc == 0) {
sData->result = -1;
}
// Defines an array of char pointer with the dimension of the number of tokens
sData->result = tc;
char *tokens[tc];
// Resets the token engine
strcpy(data,source);
// Strip out the first token found
token = strtok(data, delimiter);
tokens[0] = token;
tc = 0;
while (token != NULL)
{
// Strip out one token and store them into the token array
token = strtok(NULL, delimiter);
tc++;
tokens[tc] = token;
}
sData->tokens = tokens;
for(int i=0; i<sData->result; i++) {
printf("%s\n", sData->tokens[i]);
}
}
Result:
Part1
Part2
Part3
3 tokens found
(null)
(null)
(null)
Program ended with exit code: 0

Program Hangs when printing contents of array in loop

Hi, i am using the MinGW C Compiler with Code::Blocks and my code hangs when trying to print the contents of an array (well it is a custom data type).
For a quick summary: the program is taking the contents of a txt file and splits
the string up into individual words using a custom data type called a stringArray (the name explains itself). It then should print each word of the file to the user.
The problem is, it hangs and gives me the usual "[PROGRAM NAME HERE] is not responding." After pressing cancel it gives me this result:
Process returned -1073741819 (0xC0000005) execution time : 3.861 s
Press any key to continue.
I am a sort of beginner.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct stringArray
{
char *string;
}stringArray;
const char delim[2] = " ";
int string_to_array(char *filecontents)
{
char *token;
token = strtok(filecontents, delim);
int i;
int dirtyContentsLength;
stringArray newContents[100];
for(i = 0; i < 100; i++)
{
newContents[i].string = "";
}
i = 0;
while (token != NULL)
{
newContents[i].string = token;
i++;
token = strtok(NULL, delim);
}
return newContents;
}
int open_file(char filename[30])
{
char *file_contents;
long input_file_size;
FILE *input_file = fopen(filename, "rb");
fseek(input_file, 0, SEEK_END);
input_file_size = ftell(input_file);
rewind(input_file);
file_contents = malloc(input_file_size * (sizeof(char)));
fread(file_contents, sizeof(char), input_file_size, input_file);
fclose(input_file);
return file_contents;
}
int lex(char filecontents[30])
{
char *tok = "";
int state = 0;
char *string = "";
}
int main(int argc, char *argv[] )
{
const char *cleanContents;
char *messyContents;
char input[30];
printf("What is the filename? ");
scanf("%s", input);
messyContents = open_file(input);
cleanContents = string_to_array(messyContents);
int contentsLength = sizeof(cleanContents) / sizeof(cleanContents[0]);
int i;
for(i = 0; i < contentsLength; i++)
{
printf("%s\n", cleanContents[i]);
}
printf("Done");
return 0;
}
You have multiple problems with your code:
string_to_array() is declared to return an int, but in reality it is returning a stringArray
Same with open_file() function, Declared to return an int, but actually returning a char*
string_to_array is returning an element that was declared locally. This means that once the function is returned, that memory is no longer valid, but it has passed it on to the caller.
Your structure name is misleading. A char* is a character array (a string). Thus the name charArray would be more appropriate. For the structure to be a string array it has to be a char**, ie an array of character arrays (array of strings)
Int the printf() in the main() function you are not passing the string (thus a compilation warning is generated)
You are not initializing memory to all 0. This is ideal as otherwise the memory will contain random data which will be interpreted as a string untill the first null terminator (\0 encountered)
The following code is a modified working version of what you are trying to achieve with comments about each change:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct stringArray
{
char *string;
}stringArray;
const char delim[2] = " ";
// Now string_to_array takes the memory location to write output to as a first parameter so that the
// memory will reside in the callers scope (refer to problem 3 above)
// Additionally return type was now set to void (refer to problem 1)
void string_to_array(stringArray newContents[100], char *filecontents)
{
char *token;
token = strtok(filecontents, delim);
int i;
int dirtyContentsLength;
for(i = 0; i < 100; i++)
{
newContents[i].string = "";
}
i = 0;
while (token != NULL)
{
newContents[i].string = token;
i++;
token = strtok(NULL, delim);
}
// return now was removed. result written directly in memory passed as parameter by the caller.
}
// open_file changed to return a char* (refer to problem 2)
char* open_file(char filename[30])
{
char *file_contents;
long input_file_size;
FILE *input_file = fopen(filename, "rb");
fseek(input_file, 0, SEEK_END);
input_file_size = ftell(input_file);
rewind(input_file);
file_contents = malloc(input_file_size * (sizeof(char)));
fread(file_contents, sizeof(char), input_file_size, input_file);
fclose(input_file);
return file_contents;
}
int lex(char filecontents[30])
{
char *tok = "";
int state = 0;
char *string = "";
}
int main(int argc, char *argv[] )
{
stringArray cleanContents[100];
// Initializing memory to all 0s (refer to problem 6)
memset(cleanContents, 0 ,sizeof(cleanContents));
char *messyContents;
char input[30];
printf("What is the filename? ");
scanf("%s", input);
messyContents = open_file(input);
string_to_array(cleanContents, messyContents);
int contentsLength = sizeof(cleanContents) / sizeof(cleanContents[0]);
int i;
for(i = 0; i < contentsLength; i++)
{
// Checking that at least one character is present in the string before printing it...
if (cleanContents[i].string[0])
{
// Printing the string within the 'stringArray'. (refer to problem 5)
printf("%s\n", cleanContents[i].string);
}
}
printf("Done\n");
return 0;
}

Segmentation Fault with strlen

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++.

Weird seg faults on consecutive calls to the same array

I tried really hard to search for a solution to this but I can't think of good enough keywords.
Currently I'm having troubles grasping the concept behind makeargv and it's usage with triple pointers (I have no idea what ***foo means, it doesn't seem to be as easy of a concept as **foo or *foo). So I made my own:
const char **makeargv(char *string, int *numargs) {
string = string + strspn(string, delims);
char *copy = malloc(strlen(string) + 1);
int i;
strcpy(copy, string);
int numtokens;
if (strtok(copy, delims) != NULL) {
for (numtokens = 1; strtok(NULL, delims) != NULL; numtokens++) {}
}
strcpy(copy, string);
const char *results[numtokens+1];
results[0] = strtok(copy, delims);
for (i = 1; i < numtokens; i++) {
results[i] = strtok(NULL, delims);
}
results[numtokens+1] = NULL;
*numargs = numtokens;
return results;
}
Here's the part at where it breaks:
void parse_file(char* filename) {
char* line = malloc(160*sizeof(char));
FILE* fp = file_open(filename);
int i = 0;
int numargs = 0;
int *pointer = &numargs;
while((line = file_getline(line, fp)) != NULL) {
if (strlen(line) == 1){
continue;
}
const char **args = makeargv(line, pointer);
printf("%s\n", args[0]);
printf("%s\n", args[1]);
/* This prints out args[0], but then args[1] causes a seg fault. Even if I replace
the args[1] with another args[0] it still causes a seg fault */
}
fclose(fp);
free(line);
}
I have a working array of strings. However when I try to print out the strings in the array, I can only print 1 of my choice and then it seg faults for any subsequent calls. lets pretend my array of strings is argv[3] = {"Yes", "no", "maybe"}, if i call argv[0], it will let me call "Yes", but any other calls (even if i call argv[0] again) do not work and cause a segfault. I can call any of the elements in the array, but once i call one the rest cease to work causing segfaults.
Help please? D: This is in C.
const char *results[numtokens+1];
This array "results" is a local variable, it is only available inside of "makeargv".
You'd better use malloc:
results = malloc(numtokens+1)
And I believe there is memory leak in your code.
You will not be able to free the memory for "char *copy"
char *copy = malloc(strlen(string) + 1);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **makeargv(char *string, int *numargs) {
static const char *delims = " \t\n";
string = string + strspn(string, delims);
char *copy = malloc(strlen(string) + 1), *p = copy;
strcpy(copy, string);
int numtokens;
for (numtokens = 0; strtok(p, delims); ++numtokens, p = NULL);
char **results = malloc(sizeof(char*)*(numtokens+1));
strcpy(copy, string);
int i;
p = copy;
for (i = 0; i < numtokens; ++i, p = NULL)
results[i] = strtok(p, delims);
results[i] = NULL;
*numargs = numtokens;
return results;
}
FILE *file_open(char *filename){
FILE *fp = fopen(filename, "r");
if(!fp){
perror("file_open");
exit(1);
}
return fp;
}
void parse_file(char* filename) {
char* line = malloc(160*sizeof(char));
FILE* fp = file_open(filename);
int i = 0, numargs = 0;
while(fgets(line, 160, fp)){
if (*line == '\n')
continue;
char **args = makeargv(line, &numargs);
for(i = 0;i<numargs;++i)
printf("%s\n", args[i]);
printf("\n");
if(args[0])
free(args[0]);
free(args);
}
fclose(fp);
free(line);
}
int main(int argc, char *argv[]){
parse_file(argv[1]);
return 0;
}

Resources