Program Hangs when printing contents of array in loop - c

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;
}

Related

How to change one string to another with different sizes

I have a task to do. I have to work with strings. I will show you the input and output, because I think that will be clear what the task is.
Input: "aaa bbuvvvvo"
Output: "a$3 b$2uv$4o"
If there is the same symbols, I have to leave that symbol and then put dollar sign '$' and an integer of how many same signs was there. I am stuck on the spot, where I have to change string without losing any information.
I will leave my code here, it might help.
#include <stdio.h>
#include <string.h>
#define CAPACITY 255
#define MAX_NUMBER 10
void Output(char readFile[], char outputFile[], char string[]);
void changeString(char string[], char newString[]);
int main() {
char readFile[CAPACITY];
char outputFile[CAPACITY];
char string[CAPACITY];
// Input file's name
printf("Iveskite teksto failo varda: ");
scanf("%s", &readFile);
// Output file's name
printf("Iveskite teksto faila i kuri bus isvedamas atsakymas: ");
scanf("%s", &outputFile);
Output(readFile, outputFile, string);
return 0;
}
// Scanning file
void Output(char readFile[], char outputFile[], char string[])
{
char newString[CAPACITY];
FILE *input, *output;
input = fopen(readFile, "r");
while(fscanf(input, "%s", string) != EOF)
{
changeString(string, newString);
printf("%s\n", newString);
}
}
// Changing string to wanted string
void changeString(char string[], char newString[])
{
char number[MAX_NUMBER];
int symbols = 0;
int j;
for(int i = 0; string[i] != '\0'; ++i)
{
int temp = i;
newString[i] = string[i];
if(newString[i] == string[i + 1])
{
j = i;
while(string[j] == string[i])
{
++symbols;
++j;
}
// Changing int to char
sprintf(number, "%d", symbols);
newString[i + 1] = '$';
i += 2;
newString[i] = number[0];
symbols = 0;
}
}
}
I have tried to do that with function called changeString, but I get the wrong output all the time. Also the input I am getting is from .txt file.
EDIT: When I compiling this program right now, I get a$3 b$2v$4vo that output.
For starters this declaration in main
char string[CAPACITY];
does not make sense.
You should declare variables in scopes where they are used.
The variable string is used in the function Output where it is should be declared.
The function changeString should be declared like
void changeString( const char string[], char newString[]);
because the source string is not changed within the function.
Your function has several bugs.
For example it does not build a string in the array newString because it does not append the stored sequence in the array with the terminating zero character '\0'.
Secondly this increasing of the variable i
i += 2;
in general is invalid. You need to add to the variable i the number of repeated characters in the source string.
Or the number of repeated characters change greater than or equal to 10. In this case this statement
newString[i] = number[0];
will not produce correct result.
The function can be defined the following way as shown in the demonstration program below.
#include <stdio.h>
#define CAPACITY 255
void changeString( const char string[], char newString[] )
{
while ( *string )
{
*newString++ = *string;
size_t n = 1;
while (*++string == *( newString - 1 ) ) ++n;
if (n != 1)
{
*newString++ = '$';
int count = sprintf( newString, "%zu", n );
newString += count;
}
}
*newString = '\0';
}
int main( void )
{
char string[CAPACITY] = "aaa bbuvvvvo";
char newString[CAPACITY];
changeString( string, newString );
puts( newString );
}
The program output is
a$3 b$2uv$4o

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

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.

Extracting the first two words in a sentence in C without pointers

I am getting used to writing eBPF code as of now and want to avoid using pointers in my BPF text due to how difficult it is to get a correct output out of it. Using strtok() seems to be out of the question due to all of the example codes requiring pointers. I also want to expand it to CSV files in the future since this is a means of practice for me. I was able to find another user's code here but it gives me an error with the BCC terminal due to the one pointer.
char str[256];
bpf_probe_read_user(&str, sizeof(str), (void *)PT_REGS_RC(ctx));
char token[] = strtok(str, ",");
char input[] ="first second third forth";
char delimiter[] = " ";
char firstWord, *secondWord, *remainder, *context;
int inputLength = strlen(input);
char *inputCopy = (char*) calloc(inputLength + 1, sizeof(char));
strncpy(inputCopy, input, inputLength);
str = strtok_r (inputCopy, delimiter, &context);
secondWord = strtok_r (NULL, delimiter, &context);
remainder = context;
getchar();
free(inputCopy);
Pointers are powerful, and you wont be able to avoid them for very long. The time you invest in learning them is definitively worth it.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
Extracts the word with the index "n" in the string "str".
Words are delimited by a blank space or the end of the string.
}*/
char *getWord(char *str, int n)
{
int words = 0;
int length = 0;
int beginIndex = 0;
int endIndex = 0;
char currentchar;
while ((currentchar = str[endIndex++]) != '\0')
{
if (currentchar == ' ')
{
if (n == words)
break;
if (length > 0)
words++;
length = 0;
beginIndex = endIndex;
continue;
}
length++;
}
if (n == words)
{
char *result = malloc(sizeof(char) * length + 1);
if (result == NULL)
{
printf("Error while allocating memory!\n");
exit(1);
}
memcpy(result, str + beginIndex, length);
result[length] = '\0';
return result;
}else
return NULL;
}
You can easily use the function:
int main(int argc, char *argv[])
{
char string[] = "Pointers are cool!";
char *word = getWord(string, 2);
printf("The third word is: '%s'\n", word);
free(word); //Don't forget to de-allocate the memory!
return 0;
}

C: Strange behaviour with strtok()

I'm doing an exercice where I need to split a string into an array of strings. The number of delimiters is checked before (the code snippet posted is a stripped down version however it doesn't work too), then the string is transformed into lowercase and it gets split into 4 parts separated by the delimiter "-". Here's the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX_USERNAME_LENGHT 256
#define NUMBER_OF_ELEMENTS 4
void StringToArrayOfStrings(char *string, char **string_array, char *delimiter);
void LowerString(char * string, int string_lenght);
int main() {
char string[MAX_USERNAME_LENGHT] = "Joseph-Lucy-Mike-Nick"; //Test string
char *string_array[NUMBER_OF_ELEMENTS]; //We need four elements
char delimiter[] = "-";
int counter = 0;
//LowerString(string, strlen(string));
//printf("%s", string);
StringToArrayOfStrings(string, string_array, delimiter);
//Print each element of the string array
for (counter = 0; counter < NUMBER_OF_ELEMENTS; counter++) {
printf("\n%s\n", string_array[counter]);
}
return 0;
}
void LowerString(char * string, int string_lenght) {
unsigned short int counter;
for (counter = 0; counter < string_lenght; counter++) {
string[counter] = tolower(string[counter]);
}
}
void StringToArrayOfStrings(char *string, char **string_array, char *delimiter) {
unsigned short int counter;
char *token;
token = strtok(string, delimiter);
while(token != NULL) {
string_array[counter++] = token;
token = strtok(NULL, delimiter);
}
}
I've been scratching my head for the past 2 hours and I wasn't able to fix it. This programs works only if the string is not printed or/and transformed in lowercase. The program crashes when entering the loop in StringToArrayOfStrings. Where's the problem?
Thanks.

Why does strtok return the wrong number of tokens?

I've been solving an Advent of Code problem in C, and I've hit something I don't understand. My C is very rusty, and I know this isn't a great example of C code. I have stripped the program down to the smallest section that demonstrates the behaviour that confuses me.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ae_load_file_to_memory(const char *filename, char **result)
{
int size = 0;
FILE *f = fopen(filename, "rb");
if (f == NULL)
{
*result = NULL;
return -1;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
*result = (char *)malloc(sizeof(char) * (size + 1));
if (size != fread(*result, sizeof(char), size, f))
{
free(*result);
return -2;
}
fclose(f);
(*result)[size] = 0;
return size;
}
int main(void)
{
const char delim = '\n';
int fill_index = 0;
char *token = NULL;
char *content = NULL;
ae_load_file_to_memory("input.txt", &content);
token = strtok(content, &delim);
while (token != NULL)
{
fill_index++;
token = strtok(NULL, &delim);
}
printf("Fill index %d\n", fill_index);
}
This code reads a file from disk, and then splits it into tokens using the newline as the delimiter. The final printf returns the correct number of tokens, 1044.
However, if I change the start of the main method to move the declaration of fill_index:
int main(void)
{
int fill_index = 0;
const char delim = '\n';
...now strtok returns 1050 tokens, which is wrong. That's the only difference between the two files. I'm running on Mac OS X Sierra, gcc --version reports that its Apple LLVM version 9.0.0 (clang-900.0.38).
I'm sure I'm stomping on memory somewhere, and the first version only works by coincidence. However, I've got no idea why moving that declaration makes such a difference. Can anyone explain what's going on?
You didn't use the delim properly. It would be const char delim[] = "\n"; (Null terminated char array not a single character).
Earlier you were invoking undefined behavior by passing the wrong parameter.
From standard ยง7.24.5.8
char *strtok(char * restrict s1,const char * restrict s2);
And some example
static char str[] = "?a???b,,,#c";
char *t;
t = strtok(str, "?"); // t points to the token "a"
t = strtok(NULL, ","); // t points to the token "??b"
t = strtok(NULL, "#,"); // t points to the token "c"
t = strtok(NULL, "?"); // t is a null pointer

Resources