I am trying to run this code on my local machine, but I am receiving the following errors:
ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings] error in my Terminal
File is not compatible with the version of Windows you're running. Check your computer's system information and then contact the software publisher.
These erros are blocking me compiling the code, I am using C | Visual Studio Code | Windows 10 and MSY2 Ming64w to compile my code - can you help me solve this?
my.functions.h
#ifndef HW1
#define HW1
#include <stdio.h>
int str_length(char*);
void str_copy(char* src, char* dest);
int str_find(char* src, char* dest);
int get_unnamed_argument(int index, int argc, char **argv, char *result);
int get_named_argument(int index, int argc, char **argv, char *result);
#endif
my_fuctions.c
#include <stdio.h>
#include "my_functions.h"
int str_length(char* string) {
int c = 0;
for (c = 0; string[c] != '\0'; c++);
return c;
}
void str_copy(char* d, char* source)
{
int i;
for (i = 0; source[i] != '\0'; i++)
{
d[i] = source[i];
}
d[i] = '\0';
}
int str_find(char* needle, char* haystack)
{
int c,x;
for(c = 0; c < str_length(haystack); c++){
if (needle[0] == haystack[c]){
int count = 0;
for(x = 0; x < str_length(needle); x++){
if(needle[x] == haystack[c+x]){
count++;
}
}
if (count == str_length(needle)){
return c;
}
}
}
return -1;
}
int get_unnamed_argument(int index, int argc, char **argv, char *result) {
int c;
for (c = 0;c <= index;c++) {
if (index > argc - 1) {
return -1;
}
else if (str_find("=",argv[c]) != -1) {
index++;
}
else if (str_find("--",argv[c]) != -1) {
return -1;
}
else if (c == index) {
str_copy(result,argv[c]);
return str_length(argv[c]);
}
}
return -1;
}
int get_named_argument(int index, int argc, char **argv, char *result) {
int c;
for (c = 0; c <= index; c++) {
if (index > argc - 1) {
return -1;
}
else if (str_find("=",argv[c]) == -1) {
index++;
}
else if (str_find("--",argv[c]) != -1) {
return -1;
}
else if (c == index) {
str_copy(result, argv[c]);
return str_length(argv[c]);
}
}
return -1;
}
main.c
#include <stdio.h>
#include "my_functions.c"
#include "my_functions.h"
int main(int argc, char **argv) {
char t[1];
int counter;
scanf("%s %i", t, &counter);
if (str_length(t) == 1 && str_find("n", t) != -1)
{
if (counter <= 0)
{
counter = argc;
}
int c;
for (c = 0; c < counter; c++)
{
char result[255];
int arg_len = get_named_argument(c, argc, argv, result);
if (arg_len == -1)
{
return 0;
}
printf("%s\n", result);
}
} else if (str_length(t) == 1 && str_find("u", t) != -1)
{
if (counter <= 0)
{
counter = argc;
}
int c;
for (c = 0; c < counter; c++)
{
char result[255];
int arg_len = get_unnamed_argument(c, argc, argv, result);
if (arg_len == -1)
{
return 0;
}
printf("%s\n", result);
}
} else {
if (counter <= 0)
{
counter = argc;
}
int c;
for (c = 0; c < counter; c++) {
if (str_find("--", argv[c]) != -1)
{
return 0;
}
printf("%s\n", argv[c]);
}
}
return 0;
}
Related
can you help me with the size of the digits, for example, when I enter 01234, then everything works as it should, but it shouldn’t, the limit of digits should be within four.When I enter some four-digit number, everything works as it should work. But when some five-digit, six-digit or even more, then everything works as if it should be, but it should not work like that. And when I enter numbers that are less than four-digit, for example 123 , then it gives an error and it's good. But when I enter numbers that are more than four digits, it does not give an error and works as if it should be so.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
typedef struct s_mastermind {
int my_attempt;
char* my_code;
} my_mastermind;
my_mastermind* settings_function(my_mastermind* mastermind, int argc, char** argv);
int checking_for_correctness_num(char* _string);
int wrong_input(int progress,char* num_code);
my_mastermind* my_function();
int check_function(char* string);
char* input_function();
int mis_placed_pieces(char* bit, char* num_code);
int well_placed_pieces(char* bit, char* num_code);
int code_checker(char* bit, char* num_code);
char* size_of_function(char* strye);
char* my_strcpy(char* num1, char* num2) {
for(int i = 0; num2[i] != 0; i++) {
num1[i] = num2[i];
}
return num1;
}
int my_strlen(char* num1) {
return (*num1) ? my_strlen(++num1) + 1 : 0;
}
my_mastermind* my_function() {
my_mastermind* num = malloc(sizeof(my_mastermind));
num->my_code = malloc(5);
num->my_code[4] = '\0';
my_strcpy(num->my_code, "");
num->my_attempt = 10;
return num;
}
my_mastermind* settings_function(my_mastermind* mastermind, int argc, char** argv) {
char* bit;
for(int i = 0; i < argc;) {
if (my_strlen(argv[i]) == 2 && argv[i][0] == '-') {
if(argv[i][1] == 'c') {
char* num_code = argv[i + 1];
if(wrong_input(argc,num_code) != 0) {
break;
}
my_strcpy(mastermind->my_code, num_code);
}else if(argv[i][1] == 't') {
if(checking_for_correctness_num(argv[i + 1]) == 0) {
mastermind->my_attempt = check_function(argv[i + 1]);
}
} else {
printf("WRONG FLAG RESTART THE GAME!!!\n");
}
}
i += 1;
}
return mastermind;
}
int wrong_input(int progress,char* num_code) {
// if(my_strlen(num_code) != 4) {
// printf("Code bigger than 4\n");
// }
if(checking_for_correctness_num(num_code) == 1) {
printf("Wrong input!\n> ");
fflush(stdout);
char* code = input_function();
char* variable = size_of_function(code);
free(code);
int results = 1;
if(wrong_input(progress,variable) == 0) {
results = code_checker(num_code, variable);
}
free(variable);
return results;
}
return 0;
}
int checking_for_correctness_num(char* _string) {
for(int i = 0; _string[i] != '\0'; i++) {
if(!(_string[i] >= '0' && _string[i] <= '9')) {
return 1;
}
}
return 0;
}
int check_function(char* string) {
int check_num = 0;
for(int i = 0; string[i] != '\0'; i++) {
check_num = check_num * 10 + (string[i] - '0');
}
return check_num;
}
char* input_function() {
char* getting = malloc(101);
getting[100] = '\0';
read(0, getting, 100);
fflush(stdout);
return getting;
}
int game_progress(int progress, char* bit) {
printf("Round: %d\n> ", progress);
fflush(stdout);
char* code = input_function();
char* variable = size_of_function(code);
free(code);
int results = 1;
if(wrong_input(progress,variable) == 0) {
results = code_checker(bit, variable);
}
free(variable);
return results;
}
void game_action(my_mastermind* mastermind) {
int current_try = 0;
for (;current_try < mastermind->my_attempt;) {
int results = game_progress(current_try, mastermind->my_code);
current_try += 1;
if(results == 0) {
printf("Congratz! You did it!\n");
break;
}
}
}
int code_checker(char* bit, char* num_code) {
int good_w = well_placed_pieces(bit, num_code);
int not_good_m = mis_placed_pieces(bit, num_code);
if(good_w == 3 || good_w == 2 || good_w == 1 || not_good_m == 3 || not_good_m == 2 || not_good_m == 1){
printf("Well placed pieces: %d\nMisplaced pieces: %d\n---\n", good_w,not_good_m);
}
if(good_w == 4) {
return 0;
} else {
return 1;
}
}
int well_placed_pieces(char* bit, char* num_code) {
int number = 0;
for(int i = 0; i < 4; i++) {
if (bit[i] == num_code[i]) {
number += 1;
}
}
return number;
}
int mis_placed_pieces(char* bit, char* num_code) {
int number = 0;
int i = 0;
int j = 0;
while(i < 4) {
i++;
if (bit[i] == num_code[i]) {
number += 1;
}
}
return number;
}
char* size_of_function(char* strye) {
char* new_string = malloc(5);
new_string[4] = '\0';
for(int i = 0; i < 4;i++){
new_string[i] = strye[i];
}
return new_string;
}
int main(int argc, char** argv) {
printf("Will you find the secret code?\n---\n");
my_mastermind* mastermind = my_function();
settings_function(mastermind, argc, argv);
game_action(mastermind);
free(mastermind);
return 0;
}
The problem is that you size_of_function assumes the input string is exactly 4 character long, not counting the '\0'. You should either check if the input string and return a error via a NULL pointer, or fully copy the string and check later.
Returning a NULL pointer require the least modification. You can do it by checking the input string size first :
char* size_of_function(char* strye) {
if(my_strlen(strye) != 4)
return NULL;
char* new_string = malloc(5);
new_string[4] = '\0';
for(int i = 0; i < 4;i++){
new_string[i] = strye[i];
}
if (strye[4] == '\r' || strye[4] == '\n' || strye[4] == '\0')
return new_string;
free(new_string);
return NULL;
}
Then, in wrong_input(), check if num_code is NULL :
int wrong_input(int progress,char* num_code) {
if(num_code == NULL || checking_for_correctness_num(num_code) == 1) {
printf("Wrong input!\n> ");
fflush(stdout);
char* code = input_function();
char* variable = size_of_function(code);
free(code);
int results = 1;
if(wrong_input(progress,variable) == 0) {
results = code_checker(num_code, variable);
}
free(variable);
return results;
}
return 0;
}
It is critical to check if num_code is NULL before calling checking_for_correctness_num(). In C the || operator evaluates the left operand first and skip the second operand evaluation if the first one is true. This way we can ensure that we never pass a NULL pointer to checking_for_correctness_num().
wrong_input() is called recursively and allocates memory without freeing it before calling itself. This can eat up memory fast and is generality considered to be bad practice.
Also, you've implemented my_strlen() as a recursive function, which isn't necessary. Using a loop is better :
int my_strlen(char* num1) {
int index = 0;
while(num1[index++]); //Note that 'index' is post-incremented
return index - 1; //Subtract one to account for the last post increment
}
I hope you can help me I worked on this code. The code works like this
user inputs a string for example "hey john, how are you john?
the program erases signs like "'?' , ',' '!' " etc.
the program writes a string after erasing the signs : "hey john how are you john?"
and the code outputs the frequency of each word:
hey : 1
john: 2
how : 1
are : 1
you : 1
but my code counts sometimes wrong. For example when I type "bye bye bye hello hello hello"
the output is :
bye : 3
hello : 1
My code does the john example right, but the bye bye... example wrong.
How do I have to change my code? Thank you
#include <stdio.h>
#include <string.h>
char words[80][80];
void clear_string(char *text);
int extract_and_count(char *source, int *count);
void clearArray(char array[]);
int indexInWords(char string[]);
void print(int countOfWords, int count[]);
int equals(char *string1, char *string2);
int main() {
char string[80];
int count[80];
printf("please enter your text: ");
scanf("%[^\n]s", string);
clear_string(string);
printf("%s\n", string);
int countOfWords = extract_and_count(string, count);
print(countOfWords, count);
return 0;
}
void clear_string(char *text){
int i = 0;
for(;i < strlen(text);++i){
if( text[i] == '.' || text[i] == ',' || text[i] == '!' || text[i] == '?'){
int k = i + 1;
for(; k < strlen(text);++k){
text[k-1] = text[k];
}
k = strlen(text) - 1;
text[k] = ' ';
}
}
}
int extract_and_count(char *source, int *count){
int wordCounter = 0;
char string[80];
int i = 0, k = 0;
clearArray(string);
for(; i < strlen(source);++i, ++k){
if(source[i] != ' '){
string[k] = source[i];
}else{
if(string[0] == '\0'){
break;
}
int index = indexInWords(string);
if(index == -1){
strcpy(words[wordCounter], string);
count[wordCounter] = 1;
wordCounter++;
}else{
count[index] += 1;
}
clearArray(string);
k = -1;
}
}
return wordCounter;
}
void clearArray(char array[]){
memset(array,0,strlen(array));
//array[0] = '\0';
}
int indexInWords(char string[]){
int i = 0;
for(;i < 80;++i){
if(equals(words[i], string) == 0){
return i;
}
}
return -1;
}
void print(int countOfWords, int count[]){
for(int i = 0;i < countOfWords; ++i){
printf("%s : %d\n",words[i], count[i]);
}
}
int equals(char string1[], char string2[]){
return strcmp(string1, string2);
}
The most significant problem I found was in extract_and_count() -- it doesn't count the last word as it only counts words followed by space. The bandaid is to check if string has anything in it after the loop, and if so, process it. Below is my rework for that fix and general style:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
void clear_string(char *text);
int extract_and_count(char *source, int count[]);
void clearArray(char array[]);
int indexInWords(char string[]);
void print(int countOfWords, int count[]);
bool equals(char *string1, char *string2);
#define BUFFER_SIZE (512)
#define MAX_WORD_COUNT (80)
#define MAX_WORD_SIZE (64)
char words[MAX_WORD_COUNT][MAX_WORD_SIZE];
int main() {
char string[BUFFER_SIZE];
int count[MAX_WORD_COUNT];
printf("Please enter your text: ");
while (fgets(string, BUFFER_SIZE, stdin) == NULL) {
printf("Please (re)enter your text: ");
}
clear_string(string);
int countOfWords = extract_and_count(string, count);
print(countOfWords, count);
return 0;
}
void clear_string(char *text) {
for (int i = 0; i < strlen(text); i++) {
if (text[i] == '.' || text[i] == ',' || text[i] == '!' || text[i] == '?' || text[i] == '\n') {
int length = strlen(text);
for (int k = i + 1; k < length; k++) {
text[k - 1] = text[k];
}
text[length - 1] = '\0';
i--;
}
}
}
int extract_and_count(char *source, int count[]) {
int wordCounter = 0;
char string[MAX_WORD_SIZE] = {'\0'};
for (int i = 0, k = 0; i < strlen(source); i++, k++) {
if (source[i] != ' ') {
string[k] = source[i];
} else {
if (string[0] == '\0') {
break;
}
int index = indexInWords(string);
if (index == -1) {
strcpy(words[wordCounter], string);
count[wordCounter] = 1;
wordCounter++;
} else {
count[index] += 1;
}
clearArray(string);
k = -1;
}
}
if (string[0] != '\0') {
int index = indexInWords(string);
if (index == -1) {
strcpy(words[wordCounter], string);
count[wordCounter] = 1;
wordCounter++;
} else {
count[index] += 1;
}
}
return wordCounter;
}
void clearArray(char array[]) {
memset(array, 0, strlen(array));
}
int indexInWords(char string[]) {
for (int i = 0; i < MAX_WORD_COUNT; i++) {
if (equals(words[i], string)) {
return i;
}
}
return -1;
}
void print(int countOfWords, int count[]) {
for (int i = 0; i < countOfWords; i++) {
printf("%s : %d\n", words[i], count[i]);
}
}
bool equals(char string1[], char string2[]) {
return strcmp(string1, string2) == 0;
}
The next most significant issue I see is you don't keep track of how many entries in words[][] are used, so indexInWords() could easily wander off making comparisons against uninitialized memory.
In extract_and_count you break out of the for-loop when you find 2 spaces. Also you did not check for the last word of source. Changed it to:
int extract_and_count(char *source, int *count){
int wordCounter = 0;
char string[80];
int i = 0, k = 0;
clearArray(string);
for(; i < strlen(source)+1;++i, ++k){
if(source[i] != ' ' && source[i] != 0){
string[k] = source[i];
}else{
if(string[0] != '\0'){
int index = indexInWords(string);
if(index == -1){
strcpy(words[wordCounter], string);
count[wordCounter] = 1;
wordCounter++;
}else{
count[index] += 1;
} }
clearArray(string);
k = -1;
}
}
return wordCounter;
}
My code is not working and it is when I call fgets in the commandSplit function. I figured this out by printing "Am I here" in multiple places and find that the error at fgets it seems. I may be wrong, but I am pretty sure. I get a segmentation fault and I can not figure out why. Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#define MAX_CHARACTERS 512
int Execute(char *a[], int t[], int num) {
int exitShell = 0;
int l = 0;
for (int i = 0; i < num; i++) {
int status;
if (strcmp(a[0], "quit") == 0) {
exitShell = 1;
}
if (t[i] && ((strcmp(a[l], "quit") == 0))) {
exitShell = 1;
}
char *holder[t[i]+1];
for (int j = 0; j < t[i]; j++) {
holder[j] = a[l];
l++;
}
holder[t[i]] = NULL;
pid_t p = fork();
pid_t waiting;
if (p == 0) {
execvp(holder[0], holder);
fprintf(stderr, "Child process could not execvp!\n");
exit(1);
} else {
if (p < 0) {
fprintf(stderr, "Fork FAILED!\n");
} else {
waiting = wait(&status);
printf("Child %d exit with status %d\n", waiting, status);
}
}
for (int g = 0; g < t[i]; g++) {
a[g] = NULL;
}
}
for (int i = 0; i < num; i++) {
t[i] = 0;
}
return exitShell;
}
int commandSplit(char *c, FILE *f, char *a[], int t[]) {
int count = 0;
int emptyfile = 1;
int stat = 0;
int total1 = 0;
char *temp[MAX_CHARACTERS];
if (c != NULL) {
char *readCommands = strtok(c, ";");
while (readCommands != NULL) {
temp[count] = readCommands;
count++;
readCommands = strtok(NULL, ";");
}
for (int i = 0; i < count; i++) {
char *read = strtok(temp[i], " ");
int track1 = 0;
while (read != NULL) {
a[total1] = read;
track1++;
total1++;
read = strtok(NULL, " ");
}
t[i] = track1;
}
stat = Execute(a, t, count);
} else {
char *buildCommands = "";
printf("Am I here???\n");
while ((fgets(buildCommands, MAX_CHARACTERS, f) != NULL) && !stat) {
printf("Am I here???\n");
emptyfile = 0;
commandSplit(buildCommands, NULL, a, t);
stat = Execute(a, t, count);
}
if (emptyfile) {
printf("File is empty!\n");
stat = 1;
}
}
printf("Am I here???\n");
return stat;
}
int main(int argc, char *argv[]) {
int exitProgram = 0;
FILE *fileRead = NULL;
if (argc == 2) {
fileRead = fopen(argv[1], "r");
if (fileRead == NULL) {
printf("No such file exists\n");
exitProgram = 1;
}
}
if (argc > 2) {
printf("Incorrect batch mode call\n");
exitProgram = 1;
}
char *args[MAX_CHARACTERS];
int tracker[MAX_CHARACTERS];
while (!exitProgram) {
if (argc == 1) {
char *commands = (char *)(malloc(MAX_CHARACTERS * sizeof(char)));
printf("tinyshell>");
if (fgets(commands, MAX_CHARACTERS, stdin) == NULL) {
exitProgram = 1;
printf("\n");
}
int len;
len = strlen(commands);
if (len > 0 && commands[len-1] == '\n') {
commands[len-1] = '\0';
}
if (len > MAX_CHARACTERS) {
printf("TOO MANY CHARACTERS - MAX: 512\n");
continue;
}
if (strlen(commands) == 0)
continue;
exitProgram = commandSplit(commands, NULL, args, tracker);
} else {
exitProgram = commandSplit(NULL, fileRead, args, tracker);
}
}
fclose(fileRead);
return 0;
}
As commented #Jean-François Fabre , buildCommands points to insufficient space and potential const space;
char *buildCommands = "";
...
// bad code
while ((fgets(buildCommands, MAX_CHARACTERS, f) != NULL) && !stat) {
Allocate space with an array or malloc()
char buildCommands[MAX_CHARACTERS];
...
while ((fgets(buildCommands, sizeof buildCommands, f) != NULL) && !stat) {
...
}
// or
char *buildCommands = malloc(MAX_CHARACTERS);
assert(buildCommands);
...
while ((fgets(buildCommands, MAX_CHARACTERS, f) != NULL) && !stat) {
...
}
...
free(buildCommands);
I am trying to fix my last problem and still, I cannot figure out how to solve it. My task was to write a program which sort numbers, but: our tutor gives us some extra points for program dealing with numbers like: 000054667 (in fact 54667) and 345_845 (in fact 345845). The first problem is already solved but I have no idea how to handle with the second one. Hence, my question is: do you have any tips/clue, which might help me? I am also sending my code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define NUMBER_CHUNK 13
char* getNumber(FILE* fp)
{
int length, c;
int current=0;
char *number;
number=(char*)malloc(sizeof(char)*NUMBER_CHUNK);
if(!number)
{
printf("Error while alocating memory!\n");
return NULL;
}
length=NUMBER_CHUNK;
while(!isspace(c=fgetc(fp)) && !feof(fp))
{
if(isdigit(c))
{
number[current]=c;
current++;
if(current>=length)
{
length+=NUMBER_CHUNK;
if((number=((char*)realloc(number,sizeof(char*)*length)))==NULL)
{
free(number);
return NULL;
}
}
}
else
{
return NULL;
}
}
number[current]='\0';
return number;
}
int compare( const void *str1, const void *str2)
{
int value;
char* curr1;
char* curr2;
curr1=*(char**)str1;
curr2=*(char**)str2;
while(*curr1=='0') curr1++;
while(*curr2=='0') curr2++;
if(strlen(curr1) < strlen(curr2)) return -1;
if(strlen(curr1) > strlen(curr2)) return 1;
value=strcmp(curr1, curr2);
return value;
}
int main(int argc, char** argv)
{
FILE* fp;
char** tab;
int i=0;
int lines=0;
int length=10;
if(argc!=2)
{
printf("Incorrent syntax! Use ./name_of_program input_file\n");
return 1;
}
if(!(fp=fopen(argv[1],"r")))
{
printf("Could not open the file! Please try again!\n");
return 2;
}
tab = (char**)malloc(length*(sizeof(char*)));
if(!tab)
{
printf("Could not allocate memory! Terminating...\n");
free(tab);
return 3;
}
while(!feof(fp))
{
tab[i]=getNumber(fp);
if(i>=length)
{
length+=10;
if((tab=((char**)realloc(tab,sizeof(char*)*length)))==NULL)
{
free(tab);
return 5;
}
}
if(tab[i]==NULL)
{
printf("Incorrect character in the infile! Terminating\n");
free(tab);
return 4;
}
if(*tab[i]=='\0')
{
free(tab[i]);
i--;
}
i++;
lines++;
lines=i;
}
printf("\nBEFORE\n");
for(i=0;i<lines;i++)
{
printf("%s\n",tab[i]);
}
qsort(tab, lines, sizeof(char*), &compare);
printf("\nAFTER\n");
for(i=0;i<lines;i++)
{
printf("%s\n",tab[i]);
free(tab[i]);
}
free(tab);
fclose(fp);
return 0;
}
Thank you for any help ;)
Change string accumulation and your compare routine.
String accumulation:
if(isdigit(c) || (c == '_'))
Compare. This is a bit lengthy to incorporate ignoring _ for value ratings. But it is not limited to numbers that fit in any int range.
int compare(const void *str1, const void *str2) {
const char* curr1 = *(const char**) str1;
const char* curr2 = *(const char**) str2;
// Remove leading zeros
while ((*curr1 == '0') || (*curr1 == '_'))
curr1++;
while ((*curr2 == '0') || (*curr2 == '_'))
curr2++;
int value = 0;
size_t len1 = 0;
size_t len2 = 0;
while (*curr1 || *curr2) {
while (*curr1 == '_')
curr1++;
while (*curr2 == '_')
curr2++;
// If a difference has not been found yet ...
if (value == 0) {
value = *curr1 - *curr2;
}
if (*curr1) {
curr1++;
len1++;
}
if (*curr2) {
curr2++;
len2++;
}
}
// If significant digits in string1 more than string2 ...
if (len1 != len2) {
return (len1 > len2) ? 1 : -1;
}
return value;
}
Just keep parsing the string until you get an underscore, and with parsing also convert each character into the respective number and keep adding it to a new number according to it's place value (In a nutshell i'm speaking of an algorithm to convert string to numbers). and if you encounter an underscore, just use
continue;
If you want to retain the string representation for your "numbers" but compare them according to their numerical value, don't compare them as strings inside your compare function.
Inside compare parse each arguments (str1 and str2) and convert them to numbers skipping leading zeros and underscores. Once you have two numbers (say num1 and num2) just return num1 - num2.
Instead of storing a bunch of strings, you would be better off converting the numbers to ints by stripping out any non-digit characters and calling atoi on the results. You can store those numbers directly in the array. The compare function then becomes much simpler.
chux THX. You're brilliant! I wish I would be as good as you in programming.
I am sending my whole (fixed, working) source code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define NUMBER_CHUNK 13
char* getNumber(FILE* fp)
{
int length;
int current = 0;
int c;
char *number, *number2;
number = (char*)malloc(sizeof(char)*NUMBER_CHUNK);
if(!number)
{
printf("Error while allocating memory!\n");
return NULL;
}
length = NUMBER_CHUNK;
while(!isspace(c = fgetc(fp)) && !feof(fp))
{
if(isdigit(c) || c == '_')
{
number[current] = c;
current++;
if(current >= length)
{
length+=NUMBER_CHUNK;
number2 = (char*)realloc(number,length*sizeof(char*));
if(number2 == NULL)
{
free(number2);
return NULL;
}
else number2 = number;
}
}
else
{
return NULL;
}
}
number[current] = '\0';
return number;
}
int compare(const void *str1, const void *str2)
{
char* curr1;
char* curr2;
curr1=*(char**)str1;
curr2=*(char**)str2;
while(*curr1=='0' || *curr1=='_') curr1++;
while(*curr2=='0' || *curr2=='_') curr2++;
int value = 0;
size_t len1 = 0;
size_t len2 = 0;
while(*curr1 || *curr2)
{
while(*curr1 == '_')
curr1++;
while(*curr2 == '_')
curr2++;
if(value == 0)
{
value = *curr1 - *curr2;
}
if(*curr1)
{
curr1++;
len1++;
}
if(*curr2)
{
curr2++;
len2++;
}
}
if(len1 != len2)
{
return (len1 > len2) ? 1 : -1;
}
return value;
}
int main(int argc, char** argv)
{
FILE* fp;
char** tab;
int i = 0;
int lines = 0;
int length = 10;
if(argc != 2)
{
printf("Incorrent syntax! Use ./name_of_program input_file\n");
return 1;
}
if(!(fp = fopen(argv[1],"r")))
{
printf("Could not open the file! Please try again!\n");
return 2;
}
tab = (char**)malloc(length*(sizeof(char*)));
if(!tab)
{
printf("Could not allocate memory!\n");
free(tab);
return 3;
}
while(!feof(fp))
{
tab[i] = getNumber(fp);
if(i >= length)
{
length += 10;
tab = (char**)realloc(tab,sizeof(char*));
if(tab == NULL)
{
free(tab);
return 5;
}
}
if(tab[i] == NULL)
{
printf("Incorrect character in the infile! Terminating\n");
free(tab);
return 4;
}
if(*tab[i] == '\0')
{
free(tab[i]);
i--;
}
i++;
lines = i;
}
printf("\nBEFORE\n");
for(i = 0 ; i < lines; i++)
{
printf("%s\n", tab[i]);
}
qsort(tab, lines, sizeof(char*), compare);
printf("\nAFTER\n");
for(i = 0; i < lines; i++)
{
printf("%s\n",tab[i]);
free(tab[i]);
}
printf("\n");
free(tab);
fclose(fp);
return 0;
}
in the following code when ran will produce a Segmentation Fault, due to a FILE* being passed to fclose which contains no address (NULL).
I'm wondering why this is happening, the FILE* isn't being used what so over.
The FILE* is named urandom and is passed to fclose in the main function.
Thanks
#include <stdio.h>
#include <stdlib.h>
struct property
{
char *name;
unsigned int value;
unsigned int owner;
unsigned int type;
};
struct player
{
unsigned int id;
unsigned int money;
unsigned int position;
};
int rollDice(FILE *);
int amountOfLines(FILE *);
int createArrayOfPtrs(int ,void ***);
int makeArryOfPropertyPtrs(int ,struct property **);
int FillArryPropertyData(struct property **,int ,FILE *);
int splitBuffer(char *,unsigned int *,char **);
int bufferPropertyFile(FILE *,char **,int );
i nt fillPropertyStruct(struct property *,unsigned int ,char *);
int main(void)
{
int linesInPropertyFile = 0;
struct property **arrayForProperties = 0;
//Open /dev/urandom for rollDice
FILE *urandom = fopen("/dev/urandom","rb");
FILE *propertyFile = fopen("/home/jordan/Documents/Programming/Monopoly Project/properties","rb");
if(propertyFile == NULL || urandom == NULL)
{
puts("ERROR: error in opening file(s)");
return 1;
}
linesInPropertyFile = amountOfLines(propertyFile);
//DEBUG
printf("%d is contained within \"linesInPropertyFile\"\n",linesInPropertyFile);
if(createArrayOfPtrs(linesInPropertyFile,(void ***)&arrayForProperties))
{
puts("ERROR: error from createArrayOfPointers()");
return 1;
}
//DEBUG
printf("Outside Pointer: %p\n",arrayForProperties);
if(makeArryOfPropertyPtrs(linesInPropertyFile,arrayForProperties))
{
puts("ERROR: error from createArrayOfPointersForProperties()");
return 1;
}
if(FillArryPropertyData(arrayForProperties,linesInPropertyFile,propertyFile))
{
puts("ERROR: error from FillArryPropertyData()");
}
//Close FILE stream for /dev/urandom
fclose(urandom);
fclose(propertyFile);
return 0;
}
int FillArryPropertyData(struct property **array,int amntOfProperties,FILE *fp)
{
int bufferUsed = 100;
int i = 0;
int returnValue = 0;
int returnValue2 = 0;
unsigned int money = 0;
char *name;
char *buffer;
rewind(fp);
while(returnValue == 0)
{
buffer = malloc(bufferUsed);
returnValue = bufferPropertyFile(fp,&buffer,bufferUsed);
if(returnValue && returnValue != -1)
{
puts("ERROR: error from bufferPropertyFile()");
return -1;
}
if(returnValue == -1)
{
break;
}
if(buffer[0] != '\0')
{
returnValue2 = splitBuffer(buffer,&money,&name);
}
if(returnValue2)
{
puts("ERROR: error in splitBuffer()");
return 1;
}
if(fillPropertyStruct(array[i],money,name))
{
puts("ERROR: error in fillPropertyStruct()");
return 1;
}
money = 0;
i++;
}
free(buffer);
return 0;
}
int fillPropertyStruct(struct property *array,unsigned int money,char *name)
{
int nameSize = 100;
int i = 0;
array->name = malloc(nameSize);
array->value = money;
while(1)
{
if(i >= nameSize)
{
void *tmp = realloc(array->name,nameSize * 2);
nameSize *= 2;
if(tmp)
{
array->name = tmp;
}
else
{
return -1;
}
}
if(name[i] == '\0')
{
break;
}
array->name[i] = name[i];
i++;
}
array->name[i] = '\0';
return 0;
}
int splitBuffer(char *buffer,unsigned int *money,char **name)
{
int i = 0;
int j = 1;
int nameSize = 100;
*name = malloc(nameSize);
while(1)
{
if(buffer[j] != '"')
{
(*name)[j-1] = buffer[j];
}
else
{
i++;
}
j++;
if(i)
{
break;
}
if(j >= nameSize)
{
void *tmp = 0;
tmp = realloc(*name,nameSize * 2);
nameSize = nameSize * 2;
if(tmp != NULL)
{
*name = tmp;
}
else
{
puts("ERROR: error in splitBuffer");
return -1;
}
}
}
name[j-1] = '\0';
while(buffer[j] != '$')
{
if(buffer[j] == '\0')
{
puts("ERROR: error in splitBuffer()");
return -2;
}
j++;
}
j++;
while(buffer[j] != '\0')
{
*money += (buffer[j] - '0');
if(buffer[j+1] != '\0')
{
*money *= 10;
}
j++;
}
printf("BUFFER: %s\n",buffer);
printf("NAME: %s\n",*name);
printf("MONEY: %d\n",*money);
return 0;
}
int bufferPropertyFile(FILE *fp,char **buffer,int i)
{
int j = (i - i);
if(feof(fp))
{
//-1 Returned if EOF detected
return -1;
}
char retr = 0;
while(1)
{
if(j + 1 >= i)
{
void *tmp = realloc(*buffer,i * 2);
if(tmp != NULL)
{
*buffer = tmp;
i = i * 2;
}
else
{
puts("ERROR: error in bufferPropertyFile()");
return -2;
}
}
retr = fgetc(fp);
if(retr == '\n' || feof(fp))
{
break;
}
(*buffer)[j] = retr;
j++;
}
(*buffer)[j] = '\0';
if(**buffer == '\0')
{
return -1;
}
return 0;
}
int rollDice(FILE *fp)
{
int seed = fgetc(fp);
srand(seed);
return (rand() % 6) + 1;
}
int amountOfLines(FILE *file)
{
int i = 0;
int retr = 0;
while(1)
{
retr = fgetc(file);
if(retr == EOF)
{
break;
}
if(retr == '\n' )
{
i++;
}
}
return i;
}
int createArrayOfPtrs(int numberOfPointers,void ***pointer)
{
void *tmp = malloc(numberOfPointers * sizeof (tmp));
if(tmp != NULL)
{
*pointer = tmp;
//DEBUG
printf("Pointer: %p\n",*pointer);
}
else
{
return 1;
}
return 0;
}
int makeArryOfPropertyPtrs(int numberOfPointers,struct property **pointer)
{
int i = 0;
void *tmp;
for(i = 0;i < numberOfPointers;i++)
{
tmp = malloc(sizeof(struct property));
if(tmp == NULL)
{
return 1;
}
pointer[i] = (struct property *)tmp;
}
return 0;
}
here it givest an access violation in splitBuffer on this line:
name[j-1]='\0';
which probably should be
(*name)[j-1]='\0';
indeed that memory is not allocated anywhere, in other words, undefined behaviour, which indeed in your case might overwrite the urandom variable: both urandom and name are allocated on stack so depending on value of j it might write over urandom..
apart from that, there might be more errors, the number and use of pointers/mallocs/reallocs and lack of frees is a bit scary
int createArrayOfPtrs(int ,void ***);
if(createArrayOfPtrs(linesInPropertyFile,(void ***)&arrayForProperties))
This is undefined behaviour, a (void***) is not compatible to a (struct property ***). Why do you even use it here, all the other functions use struct property pointers?
Since the array is located right before the file pointer in the local variables of main, maybe the problem is that the array creation/initialization overwrites urandom?