Struct array in c gives the same value to all values. [C] - arrays

I read words from the file. When I throw them into the structure, it writes the same values.
What is Problem and How can I fix
Ide: VsCode
Compiler: mingw64-gcc-g++
File Content;
{Sam}
{Patrick}
{Philips}
My Code;
struct Sentence
{
char *word;
};
struct Sentence *words[20];
void readFile(const char *path, char *fileName)
{
int wordpointer = 0;
int len = strlen(fileName);
FILE *fp;
if ((fp = fopen((path), "r")) != NULL)
{
char ch = fgetc(fp);
while (ch != EOF)
{
if (ch == '{')
{
int counter = 0;
while (ch != EOF)
{
char word[20];
ch = fgetc(fp);
if (ch == '}')
{
//printf("%s\n",word);
struct Sentence *st = malloc(sizeof(struct Sentence));
st->word = word;
words[wordpointer] = st;
wordpointer++;
break;
}
word[counter++] = ch;
}
}
ch = fgetc(fp);
}
fclose(fp);
}
for (int i = 0; i < wordpointer; i++)
printf("%s\n", words[i]->word);
}
I can get proper output in the printf function in the comment line, but when I print the Struct, all the values ​​as below are the last word in the file.
Output;
Philips
Philips
Philips

In this while loop
while (ch != EOF)
{
char word[20];
//...
all pointers st->word = word; points to the same local variable word
if (ch == '}')
{
//printf("%s\n",word);
struct Sentence *st = malloc(sizeof(struct Sentence));
st->word = word;
words[wordpointer] = st;
wordpointer++;
break;
}
declared like
st->word = word;
So after exiting the while loop the pointers will be invalid.
You need to allocate memory for each string and copy there entered strings. Moreover you need to append them with the terminating zero character '\0'.

Related

malloc() in C returns populated memory

char *string = (char *) malloc(sizeof(char) * sz);
code right before this->void insert_word(word *root, char string1[], int linenumber) { int sz=strlen(string1)<=MAX_WORD_LENGTH?strlen(string1):MAX_WORD_LENGTH; Code block 3 has the entire context
Sometimes malloc() returns a populated memory location while using it.
What bothers me is that this is not random.
(This program consists of taking words from a file and passing them to this function. For THE SAME WORD, the function behaviour(in particular that of malloc()) is different.
For the inputs
string1=0x7fffffffdf10 "lol" root=BST, sz gets a value of 3
The value allocated to string by malloc() is 0x55555555c510 "\340\305UUUU" Why is malloc not pointing to an empty memory location? (This is not random behaviour, it is predictable and repeatable)
Furthermore,this loop runs an infinite amount of time for some reason
while(strcmp(string1,string)!=0)
{
free(string);
string=NULL;
string = (char *) malloc(sizeof(char) * sz);
strncpy(string,string1,sz);
}
MORE RELAVANT CODE
#define MAX_WORD_LENGTH 20
Definition of the structures
typedef struct linkedList
{
int number;
struct linkedList *next;
}list;
typedef struct word_with_count
{
char* string;
list *linenumbers;
struct word_with_count *left;
struct word_with_count *right;
}word;```
[3] ) The function
void insert_word(word *root, char string1[], int linenumber) {
int sz=strlen(string1)<=MAX_WORD_LENGTH?strlen(string1):MAX_WORD_LENGTH;
char *string = (char *) malloc(sizeof(char) * sz);
strncpy(string,string1,sz);
if (root==NULL) {
return;
} else if (strcmp(string, root->string) < 0) {
if (root->left == NULL) {
root->left = createword(string, linenumber);
} else {
insert_word(root->left, string, linenumber);
}
} else if (strcmp(string, root->string) > 0) {
if (root->right == NULL) {
root->right = createword(string, linenumber);
} else {
insert_word(root->right, string, linenumber);
}
} else {
append_list(linenumber, root->linenumbers);
}
free(string);
}
main() which calls this function
int main() {
char path[MAX_PATH_LENGTH];
FILE *fp;
fgets(path, MAX_PATH_LENGTH, stdin);
if (strlen(path) > 0 && path[strlen(path) - 1] == '\n')
path[strlen(path) - 1] = '\0';
fp = fopen(path, "r");
if (fp == NULL) {
printf("File not found\n");
return 0;
}
char ch;
int line_count = 1;
char current_word[MAX_WORD_LENGTH] = "";
word *root = NULL;
while (!feof(fp)) {
ch = fgetc(fp);
//printf("%c", ch);
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
if (ch >= 'A' && ch <= 'Z')
ch = ch - 'A' + 'a';
strncat(current_word, &ch, 1);
} else if (ch == '-') {
continue;
} else {
if (strlen(current_word) > 2) {
if (root == NULL) {
root = createword(current_word, line_count);
} else {
insert_word(root, current_word, line_count);
}
}
memset(current_word, 0, sizeof(current_word));
if (ch == '\n') {
line_count++;
}
}
}
if (strlen(current_word) > 2) {
if (root == NULL) {
root = createword(current_word, line_count);
} else {
insert_word(root, current_word, line_count);
}
}
fclose(fp);
// print_tree(root);
//printf("\n");
//print_tree(root);
int status=delete_low_ocurrence(root, NULL, 3);
if (status == -1)root = NULL;
print_tree(root);
freetree(root);
return 0;
}
5)Auxilary function used by this function
word* createword(char string[], int linenumber)
{
word *newword = (word*)malloc(sizeof(word));
int sz=strlen(string)<=MAX_WORD_LENGTH?strlen(string):MAX_WORD_LENGTH;
newword->string = (char*)malloc(sizeof(char)*sz);
strncpy(newword->string, string,sz);
newword->linenumbers = (list*)malloc(sizeof(list));
newword->linenumbers->number = linenumber;
newword->linenumbers->next = NULL;
newword->left = NULL;
newword->right = NULL;
return newword;
}
Textfile given as input
much2f
much3f
lol
lol
lol
qwertyuiopasdfghjklzxcvbnmqwertyuiop
qwertyuiopasdfghjklzxcvbnmqwertyuiop
qwertyuiopasdfghjklzxcvbnmqwertyuiop
qwertyuiopasdfghjklzxcvbnmqwertyuiop
Why is malloc not pointing to an empty memory location?
Because it can. The content of the allocated memory via malloc() is not specified.
If code needs zeroed out memory, see calloc().
Bad code
strncpy(string,string1,sz) does not result in string being a string as it may lack null character termination. The following (strcmp(string... is then undefined behavior. Instead, do not use strncpy(), use strcpy() and make certain the prior allocation has enough room for the terminating null character.
strncpy(string,string1,sz);
...
} else if (strcmp(string, root->string) < 0) { // bad
Repaired code
word* createword(const char string[], int linenumber) {
word *newword = calloc(1, sizeof *newword);
size_t length = strlen(string);
if (length > MAX_WORD_LENGTH) {
length = MAX_WORD_LENGTH;
}
char *s = malloc(length + 1); // Include room for the \0
list *linenumbers = calloc(1, sizeof *linenumbers);
// Test allocation success
if (newword == NULL || s == NULL || linenumbers == NULL) {
free(newword);
free(s);
free(linenumbers);
return NULL;
}
memcpy(s, string, length); // Only copy the first 'length' characters.
s[length] = 0;
newword->string = s;
newword->linenumbers = linenumbers;
newword->linenumbers->number = linenumber;
newword->linenumbers->next = NULL;
newword->left = NULL;
newword->right = NULL;
return newword;
}
Why is “while ( !feof (file) )” always wrong?
feof(fp) improperly used here. fgetc() returns 257 different values. Do not use char ch.
//char ch;
//...
//while (!feof(fp)) {
// ch = fgetc(fp);
int ch;
...
while ((ch = fgetc(fp)) != EOF) {;
This is quite normal behaviour. 'malloc' just does the memory allocation, it makes no commitment on what's already in that memory location. What you probably need is 'calloc', which clears the memory and then allocates it to your program.

Is it possible to take a token from a file and create a struct with it using malloc in C?

I need to use both malloc and realloc and am confused how to do it.
Assuming that the input file looks something like this:
a *b c
a
*a b *c
and I have structs set up as so:
typedef struct Unit {
bool hasAstericks;
char letter;
} unit;
typedef struct Line {
struct unit clause[4]
} line;
Is it possible to create a struct of type unit from each letter add them to an array in struct Line based off of the line they are on? I've tried using loops but couldn't create structs on the fly with them.
This is what I have tried:
int c;
filename = argv[1];
char *filename;
FILE *fp = fopen(filename, "r");
filename = (char *)malloc(size);
do {
c = fgetc(fp);
inputFile = (char *)realloc(inputFile, size + 1);
inputFile[n] = c;
n++;
size++;
} while (c != EOF);
Your do/ while loop attempts to read the file into a array of char which you reallocate for each additional byte read from he file.
Yet you should test for end-of-file before storing the byte into the array.
Also it might be best to set a null terminator at the end of the array when you are done, so the array should have size + 1 bytes.
Here you code modified and encapsulated in a function to read the file:
char *read_file(const char *filename) {
FILE *fp = fopen(filename, "r");
if (fp == NULL)
return NULL;
size_t size = 0;
char *p = malloc(size + 1);
if (p != NULL) {
int c;
while ((c = getc(fp)) != EOF) {
char *newp = realloc(p, size + 2);
if (newp == NULL) {
free(p);
p = NULL;
break;
}
p = newp;
p[size] = c;
size++;
}
if (p) {
p[size] = '\0'; set a null terminator: make p a C string.
}
}
fclose(fp);
return p;
}

Dynamic array of pointers from user input

I need some help regarding dynamic allocation of arrays of pointers in C. I am trying to create a program that reads a sentence of words from user input, and stores the words in character array strings. I then want to save the pointers char *word to these words in an array of pointers char **wordArray.
Creating a working method for dynamic allocation for the words was easy enough, and it reads character by character from user input. However, trying to adapt this method for the array of pointers was trickier.
The current function char **varArray is obviously flawed, but my thinking was "while the user has input, get words pointers for the array of pointers". It now effectively loops the first word for every char c.
My question is, how do I implement a second layer (char **varArray()) of dynamic memory allocation of my array of pointers? How can the function detect when to call char *word()?
Feedback for the code, style, or other errors are of course appreciated. My level is intermediate beginner.
/*CREATES AND ALLOCATES DYNAMIC VARIABLE ARRAY*/
#include <stdio.h>
#include <stdlib.h>
char **varArray();
char *word();
char **varArray()
{
char **tmp=NULL;
char **wordArray=NULL;
size_t size=0;
char c = EOF;
int words=0;
while(c) {
c=getc(stdin);
if (c == EOF || c == '\n')
c=0;
if (size <= words) {
size+=sizeof(char *);
tmp = realloc(wordArray,size);
if(tmp == NULL) {
free(wordArray);
wordArray=NULL;
printf("Memory allocation failed. Aborted.\n");
break;
}
wordArray=tmp;
}
words++;
wordArray[words]= word();
return wordArray;
}
The method for retrieving ONE word:
/*GETS ONE WORD FROM USER INPUT*/
char *word()
{
char *word=NULL, *tmp=NULL;
size_t size=0;
char c = EOF;
int letters=0;
while(c) { //reads character by character
c=getc(stdin);
if (c == EOF || c == '\n' || c==' ') //remove ' ' to read all input
c =0;
if (size <= letters) { //increase and reallocate memory
size = size + sizeof(char);
tmp = realloc(word,size);
if (tmp==NULL) { //check if allocation failed
free(word);
word=NULL;
printf("Memory allocation failed. Aborted.\n");
break;
}
word= tmp;
}
letters=letters+1;
word[letters]=c;
}
/*ADD SENTINEL CHARACTER*/
letters++;
size += sizeof(char);
word = realloc(word,size);
word[letters]='\n';
return word;
}
Here's the skeleton of the program you want to write.
...
char* currentWord;
char **wordArray=NULL;
while ((currentWord = word()) != NULL) {
.... add current word to word array with realloc...
}
....
char* word() {
int ch;
char* outputWord = NULL;
while ((ch = getch()) != EOF) {
if ( ... ch is a word character ... )
... add ch to output word with realloc ...
else {
char* ret = outputWord;
outputWord = NULL;
return ret;
}
}
return NULL;
}
Note how the two while loops are doing exactly the same thing.
while ((element = getNextElement()) != sentinelValue) {
.... process newly obtained element ....
}
I have now successfully implemented a version of the shell provided by #n.m. However, another problem arose - since word() relies on the sentinel newline character \n to quit, it also fails to read the final word, and does not enter the loop the last, vital time.
I have tried to implement some if-cases, but these of course fail due to the while-condition. Another idea would be to implement some switch case, but I am not sure that would avoid the nastiness of the while loop?
Do note that the code has little error checking to minimise the clutter.
char **wordArray() {
char *currentWord;
char **wordArray=NULL;
size_t size=0;
int i=0;
while((currentWord = word()) != NULL) {
size+=sizeof(char *);
wordArray=(char **) realloc(wordArray,size);
wordArray[i]=currentWord;
printf("Test - Current word: %s\n",currentWord);
i++;
}
return wordArray;
}
The relevant word() function:
char *word() {
char ch;
int i=0;
size_t size=0;
char *returnWord = NULL;
char *outputWord = NULL;
char *tmp = NULL;
while((ch = getc(stdin)) != EOF && ch !='\n') { //&& ch !='\n'
if (ch != ' ' ) { //&& ch !='\n'
size += sizeof(char);
tmp = (char *) realloc(outputWord,size);
outputWord= tmp;
outputWord[i]=ch;
printf("Test1: %c\n",*(outputWord+i));
i++;
} else {
printf("Test2: %s\n",outputWord);
returnWord=outputWord;
outputWord=NULL;
printf("Test3: %s\n",returnWord);
return returnWord;
}
}
return NULL;
}

segmentation fault when accesing into a structure

When I am executing printf command for level->description, the program gives me segmentation fault. I don't know why. Should I use malloc to repair it? The content (only 1 line ending with '\n') of file sokoban.dat is "chicago;addie;story begins here;-----#####-----------|-----##$.#-----------|-----#####-----------"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct {
char *name;
char *description;
char *password;
char *map;
struct level *next;
//char *solution;
} LEVEL;
LEVEL* parse_level(char *line) { //parsing from file into the structure
LEVEL level;
char level_name[50];
char level_password[50];
char level_description[100];
char level_map[200];
int i = 0;
int j = 0;
while (line[i] != ';') { //getting level name
level_name[j] = line[i];
i++;
j++;
}
level_name[j]='\0';
level.name=&level_name[0];
//strcpy(&level.name,level_name);
//printf("%s\n",level.name);
printf("%s\n",level_name);
j = 0;
i++;
while (line[i] != ';') { //getting level password
level_password[j] = line[i];
i++;
j++;
}
level_password[j]='\0';
level.password=&level_password[0];
printf("%s\n",level_password);
j = 0;
i++;
while (line[i] != ';') { //getting level description
level_description[j] = line[i];
i++;
j++;
}
level_description[j]='\0';
level.description=&level_description[0];
printf("%s\n",level_description);
j = 0;
i++;
while (line[i] != '\n') { //getting level map
level_map[j] = line[i];
i++;
j++;
}
level_map[j]='\0';
level.map=&level_map[0];
printf("%s\n",level_map);
j = 0;
level.next=NULL;
LEVEL* levelPointer=&level;
return levelPointer;
}
int main(){
FILE *fp = fopen("sokoban.dat", "r");
if( fp == NULL ){
printf("No such file\n");
return 1;
}
char line[500];
//strcpy(line,"");
char c;
int i=0;
while((c = fgetc(fp)) != '\n'){ //reading from file 1 by 1 character
line[i]=c;
i++;
}
printf("%s\n",line);
LEVEL* level;
level=parse_level(line);
//printf("%s\n",level->description); **//!!! this is where error occur**
printf("%s\n",level->map);
return 0;
}
In the function, parse_level() you take addresses of all the local variables and copy into the struct variable level and return level. All these copy of local addresses and using those objects later after their lifetime make your program illegal and causes undefined behaviour.
You should read about basics of language first and understand concepts such as pointers, arrays, returning values from a function, returning pointers etc before diving deeper.
The ones related to your problems are:
returning a local variable from function in C
Since I can't return a local variable, what's the best way to return a string from a C or C++ function?
Undefined, unspecified and implementation-defined behavior
Undefined behavior and sequence points
The Definitive C Book Guide and List
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct level {
char *name;
char *description;
char *password;
char *map;
struct level *next;
//char *solution;
} LEVEL;
#if 0
char *strdup(const char *str){
size_t len = strlen(str);
char *ret = malloc(len + 1);
if(ret){
memcpy(ret, str, len + 1);
//ret[len] = '\0';
}
return ret;
}
#endif
LEVEL* parse_level(char *line) {
//Returns the allocated memory
LEVEL *level = malloc(sizeof(LEVEL));
char *token;
token=strtok(line, ";");//It cut the string as a separator the ';'.
level->name = strdup(token);//Copy the memory allocated strings cut out.
token=strtok(NULL, ";");//Get next token
level->password = strdup(token);
token=strtok(NULL, ";");
level->description = strdup(token);
token=strtok(NULL, ";");
level->map = strdup(token);
level->next = NULL;
#if DEBUG
printf("debug print : level\n");
printf("%s\n", level->name);
printf("%s\n", level->password);
printf("%s\n", level->description);
printf("%s\n", level->map);
#endif
return level;
}
void LEVEL_free(LEVEL *p){
free(p->name);
free(p->password);
free(p->description);
free(p->map);
free(p);
}
int main(){
FILE *fp = fopen("sokoban.dat", "r");
if( fp == NULL ){
printf("No such file\n");
return 1;
}
char line[500];
char c;
int i=0;
while((c = fgetc(fp)) != '\n'){ //reading from file 1 by 1 character
line[i]=c;
i++;
}
line[i] = '\0';
printf("%s\n",line);
LEVEL* level;
level=parse_level(line);
printf("%s\n",level->description);
printf("%s\n",level->map);
LEVEL_free(level);//free for malloced memory
return 0;
}

C: Linked list word frequency - Standard input

Edit: Fixed duplication error in code.
I attempted to create a word frequency analysis program that reads in from standard input.
I have two questions.
Currently I am using '\n' to indicate when my program should stop reading in input, I need it to read until the user is done typing. Would it be better to use EOF or the null terminator '\0'
This may be a dumb question but I cannot figure out what is wrong with my output it doubles the letters up every time.
Example input: "This is a test test of the program for frequency is a this for for"
Output:
thhiiss 1
iiss 2
aa 2
tteesstt 2
ooff 1
tthhee 1
pprrooggrraamm 1
ffoorr 3
ffrreeqquueennccyy 1
tthhiiss 1
As you can see the count close to correct for each word, but cannot figure out why the letters are duplicating.
Here is the code I have used:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "list.h"
#define MAXWORD 100
//===========================================================================
struct lnode {
struct lnode *next;
struct lnode *counter;
struct lnode *pLast;
struct lnode *prev;
struct lnode *head;
char *word;
int line;
int count;
int freq;
};
struct lnode *start = NULL;
//===========================================================================
struct lnode *createWordCounter(char *str)
{
struct lnode *pCounter = NULL;
pCounter = (struct lnode*)malloc(sizeof(struct lnode));
pCounter->word = (char*)malloc(strlen(str)+1);
strcpy(pCounter->word, str);
pCounter->freq = 1;
pCounter->next = NULL;
return pCounter;
}
//===========================================================================
void addWord(char *str)
{
struct lnode *pCounter = NULL;
struct lnode *pLast = NULL;
if(start == NULL)
{
start = createWordCounter(str);
return;
}
// If the word is in the list, increment its count
pCounter = start;
int temp = pCounter->freq;
while(pCounter != NULL)
{
if(strcmp(str, pCounter->word) == 0)
{
pCounter->freq++;
return;
}
pLast = pCounter;
pCounter = pCounter->next;
}
// Word is not in the list, add it
pLast->next = createWordCounter(str);
}
//===========================================================================
int getNextWord(char *buf, int bufsize) {
char *p = buf;
char ch;
do {
ch = getchar();
if (ch == '\n')
return 0;
} while (!((ch >= 'A' && ch <= 'Z')||( ch >= 'a' && ch <= 'z')));
do {
if (p - buf < bufsize - 1){
if( ch >= 97 && ch <= 122)//making the ch lowercase if needed
*p++ = ch;
else{ch += 32;
*p++ = ch;}
}//End of if
ch = getchar();
} while (((ch >= 'A' && ch <= 'Z')||( ch >= 'a' && ch <= 'z')));
*p = '\0';
return 1;
}
//===========================================================================
void show(struct lnode *pWord)
{
printf("%s %i\n", pWord->word, pWord->freq);
}
//===========================================================================
int main(){
struct lnode *counter = NULL;
int size = 1000;
char buf[MAXWORD];
while(getNextWord(buf, size) != 0 ){
addWord(buf);
}
counter = start;
while(counter != NULL)
{
show(counter);
counter = counter->next;
}
counter = start;
while(counter != NULL)
{
free(counter->word);
start = counter;
counter = counter->next;
free(start);
}
return 0;
}
This is my first time posting so please let me know if I did anything wrong. Any help is appreciated.
Thanks.
Look at this carefully, it is assigning ch twice to *p
if( ch >= 97 && ch <= 122)//making the ch lowercase if needed
*p++ = ch;
else{ch += 32;}
*p++ = ch;
I think the trailing "}" on the else statement is misplaced.
if( ch >= 97 && ch <= 122) { //making the ch lowercase if needed
*p++ = ch;
} else {
ch += 32;
*p++ = ch;
}
Also, your code will be greatly more readable if you learn about the functions
isalpha, islower, isupper, tolower, toupper. man ctype for info.
Would it be better to use EOF or the null terminator '\0' ?
Use EOF because if you press ctl+D getchar() consider input as EOF . You can also use \n or Use an OR logic with \n,EOF
what is wrong with my output it doubles the letters up every time ?
See this below code in function getNextWord()
if( ch >= 97 && ch <= 122)//making the ch lowercase if needed
*p++ = ch;
//this checks if input character is lowercase character, then store it into buffer
else{ch += 32;} // if input character is lowercase character, won't execute else part
*p++ = ch;
// now again you are copying same input character into buffer next location
Modify above part.

Resources