I am writing a software in C. For that purpose I use lex. I wrote a piece of code in C to create a symbol table and manage it. So, whenever lex finds a new symbol, it puts it in a symbol table. Problem is, when I try to print all results from symbol table, I get output I didn't expect.
If, for example, the input file was:
int main(){}
the output should be:
int
main
(
)
{
}
but the output is:
int main(){}
main(){}
(){}
...
and so on.
The function used for printing is something like this
void print_entries(struct symtab *start) {
struct symtab *s = start;
while(s != NULL) {
printf("%s\n", s->name);
s = s->next;
}
}
Here is the code for adding new symbols:
void add_entry(char* name, int type, struct symtab *start)
{
struct symtab *new;
new = malloc(sizeof(struct symtab));
last_entry(start)->next = new;
new->name = name;
new->type = type;
new->next = NULL;
}
Any ideas?
You need to copy the symbol names into the symbol table entries. If for some peculiar reason your system does not have strdup() already, then use:
#include <string.h>
#include <stdlib.h>
char *strdup(const char *str)
{
size_t len = strlen(str) + 1;
char *dup = malloc(len);
if (dup != 0)
memmove(dup, str, len);
return dup;
}
(In this context, I could use memcpy() safely; I use memmove() because it always works and memcpy() does not. And I use memmove() because I know exactly how long the string is so the copy doesn't need to test each character for nullness as it goes.)
With strdup() on hand:
void add_entry(char* name, int type, struct symtab *start)
{
struct symtab *sym;
sym = malloc(sizeof(struct symtab));
last_entry(start)->next = sym;
sym->name = strdup(name);
sym->type = type;
sym->next = NULL;
}
Note that this still omits the error checking from the two memory allocations, which is not a good habit to get into. I've revised it to use sym rather than new because the latter is a C++ keyword and I avoid using those as identifiers, even in C code.
Related
I'm trying to make an Linked List that essentially holds a string (rather than a character array). I keep getting segmentation fault (core dumped) and I'm not sure where/how I'm allocating memory wrong
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct mystring
{
char letter;
int size;
int isHead;
struct mystring*next;
};
struct mystring * create_empty_string(int size)
{
struct mystring * string = malloc(sizeof(struct mystring));
string->size = size;
string->isHead = 0;
return string
}
struct mystring * make_string(struct mystring * list,char * string)
{
for(int i = 0 ; i < strlen(string) ; i++)
{
list->letter= string[i];
list = list->next;
}
return list;
}
void printList(struct mystring* list) {
//start from the beginning
while(list->letter != '\0') {
printf("(%c) ",list->letter);
list = list->next;
}
}
int main()
{
struct mystring * string = create_empty_string(10);
string = make_string(string, "hey");
printList(string);
}
When letter is defined as char letter; and your compiler allows you to do string->letter = malloc(sizeof(char)); without complaining, this means that you are trying to compile without the slightest bit of warnings enabled. You are not going to go very far like that. Figure out how to enable all warnings on your compiler, then perhaps work on the warnings a bit to disable the really annoying ones, and from that moment on your compiler will be helping you to avoid doing such nonsensical things as assigning the result of malloc() to a char.
As noted, your create_empty_string() function is poorly constructed. I suggest building the linked list one node at a time by feeding individual characters into a function called append_to_string() or similar, which will create a new node and link it to the previously constructed list (or become the list itself if it's the first node).
I have an assignment to do for my Data Structures class and I'm in a little bit of trouble. I have some structures, namely:
typedef struct {
char *materie;
int ore_curs;
int ore_lab;
int credit;
int teme;
} TMaterie;
typedef struct {
char *nume;
float medie;
char grupa[6]; // 324CB + NULL
int varsta;
} TStudent;
typedef struct {
void *key;
void *value;
int frequency;
} Pair;
typedef struct celulag {
void *info;
struct celulag *urm;
} TCelulaG, *TLG, **ALG;
The last one is a generic list structure that will accept in the info any kind of structure. The thing is that I need to convert it to the structure pair so that it will point out to a key (that will be either a char or an int) and a value (that will be of the type TMaterie or TStudent). I need to make functions that allocate that accordingly and I have managed to do this:
TLG aloca_string_materie(char *key, TMaterie value){
TLG cel = (TLG) malloc(sizeof(TCelulaG));
if(!cel)
return NULL;
cel->info = (Pair*)malloc(sizeof(Pair));
if( !cel->info){
free(cel);
return NULL;
}
cel->urm = NULL;
((Pair*)cel->info)->value = (TMaterie*)malloc(sizeof(TMaterie));
((Pair*)cel->info)->key = (char*)malloc(50*sizeof(char));
((Pair*)cel->info)->frequency = 0;
((Pair*)cel->info)->key = key;
((TMaterie*)(Pair*)cel->info)->materie = value.materie;
((TMaterie*)(Pair*)cel->info)->ore_curs = value.ore_curs;
((TMaterie*)(Pair*)cel->info)->ore_lab = value.ore_lab;
((TMaterie*)(Pair*)cel->info)->credit = value.credit;
((TMaterie*)(Pair*)cel->info)->teme = value.teme;
return cel;
}
The problem that I am facing is that when I try to print out the key, namely
(((Pair*)cel->info)->key)
it gives me the same value as
((TMaterie*)(Pair*)cel->info)->materie
and I have no idea why.
Can someone please tell me what I'm doing wrong?
You have two main problems
((Pair*)cel->info)->value = (TMaterie*)malloc(sizeof(TMaterie));
[...]
((TMaterie*)(Pair*)cel->info)->materie = value.materie;
TMaterie member into Cel->info is value, so
((TMaterie*)(Pair*)cel->info)->materie
must be
((TMaterie*)((Pair*)cel->info)->value)->materie
Moreover using
((Pair*)cel->info)->key = (char*)malloc(50*sizeof(char));
[...]
((Pair*)cel->info)->key = key;
You are overwriting memory mallocated for key.
If, as I guess, key is a string, just use strcpy
((Pair*)cel->info)->key = (char*)malloc(50*sizeof(char));
[...]
strcpy(((Pair*)cel->info)->key, key);
The problem is you are overwriting the pointer value instead of writing to the buffer it points to. You are doing the following:
((Pair*)cel->info)->key = malloc(...);
((Pair*)cel->info)->key = key;
In the second line you asign the pointer whatever is passed in the key argument, so you are not using the memory you have allocated above and it is being leaked.
What you probably want is to copy the contents pointed by the key argument, you can use the strcpy function. Do something like:
((Pair*)cel->info)->key = malloc(...);
strcpy(((Pair*)cel->info)->key, key);
So I'm trying to learn C right now, and I have some basic struct questions I'd like to clear up:
Basically, everything centers around this snippet of code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME_LEN 127
typedef struct {
char name[MAX_NAME_LEN + 1];
unsigned long sid;
} Student;
/* return the name of student s */
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct
return s->name; // returns the 'name' member of a Student struct
}
/* set the name of student s
If name is too long, cut off characters after the maximum number of characters allowed.
*/
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct | 'name' is a pointer to the first element of a char array (repres. a string)
char temp;
int i;
for (i = 0, temp = &name; temp != '\0'; temp++, i++) {
*((s->name) + i) = temp;
}
/* return the SID of student s */
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct
return s->sid;
}
/* set the SID of student s */
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID
s->sid = sid;
}
I've commented up the code in an attempt to solidify my understanding of pointers; I hope they're all accurate.
Also, I have another method,
Student* makeAndrew(void) {
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return &s;
}
which I'm sure is wrong in some way... I also think my setName is implemented incorrectly.
Any pointers? (no pun intended)
This is very wrong. If you insist on not using strcpy do something like this (not tested)
int iStringLength = strlen(name);
for (i = 0; i < iStringLength; i++) {
s->name[i] = name[i];
}
but make sure that the length is not longer than your array size.
This is also wrong
Student* makeAndrew(void) {
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return &s;
}
because the s object is destroyed when the function exits - it is local to the function scope and yet you return a pointer to it. So if you try to access the struct using this pointer it will not be valid as the instance no longer exists. If you want to do this you should dynamically allocate it using malloc . Alternatively do not return a pointer at all and use the alternative option of #Andrew .
In your "another method" you are locally declaring Student s, which will dynamically allocate space (usually on the stack) and you are returning that address on completion.
However, that stack-space will be released on the return, so there is no guarantee that the data is uncorrupted - in fact the likelyhood is that it will be!
Declare Student s in the call to your method, and pass the pointer to makeAndrew:
void makeAndrew(Student *s) {
setName( s, "Andrew");
setStudentID( s, 12345678);
}
...
Student s;
makeAndrew( &s );
...
Your function makeAndrew returns pointer to a local variable. It is only valid before the scope ends, so as soon as the function finishes, it will change when the memory gets overwritten - i. e. almost instantly. You would have to allocate it dynamically (using Student *s = new Student;, or if you really want to stick to pure C, Student *s = malloc (sizeof Student );, and then free it outside the function after it is not needed to avoid memory leak.
Or do it as Andrew suggested, it's less error-prone.
I would change the makeAndrew() function to just return a struct, not a pointer to a struct to correct the error with respect to returning a pointer to a temporary variable:
Student makeAndrew(void)
{
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return s;
}
Student aStudent = makeAndrew();
Your setName does have an error with respect to temp, which should be a char *, since you are incrementing it in your loop to point to another character in the input c-string. I think it was missing the null termination as well. And as you mention in your comment, there should be a check for overflow of the name char array in Student:
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |
// 'name' is a pointer to the first element of a char array (repres. a string)
const char *temp;
int i;
for (i = 0, temp = name; *temp != '\0' && i <= MAX_NAME_LEN; temp++, i++)
{
*((s->name) + i) = *temp;
}
s->name[i] = '\0';
}
You can use strncpy to simplify setName:
void setName2(Student *s,const char *name)
{
#include <string.h>
strncpy(s->name, name,MAX_NAME_LEN);
s->name[MAX_NAME_LEN] = '\0';
}
Im trying to read into a linked list from a textfile. The text file has the title of the book, author and year separated by ":". each book is on a separate line. the textfile entries look like this:
Absalom, Absalom!:William Faulkner:1936
After Many a Summer Dies the Swan:Aldous Huxley:1939
Ah, Wilderness!:Eugene O'Neill:1933
i'm rewriting it from scratch. comments would be appreciated.
#include <stdlib.h>
#include <stdio.h>
struct BookNode
{
char linebuffer[128];
char delim[]=":";
char * Title[50];
char * Author[50];
char * Year[5];
struct BookNode *next;
// char *token = NULL;
};
int main(void)
{
static const char booklist[]= "booklist.txt";
FILE *fr=fopen("booklist.txt", "r");
if ( fr != NULL)
{
char Title[50];
char Author[50];
char Year[5]
struct BookNode Booknode;
while (fgets(linebuffer,128, fr) != NULL &&
sscanf(line, "%49s %49s %4s",
&BookNode.Title, BookNode.Author, BookNode.Year)==3)
{
printf("%50s %50s %5s",
BookNode.Title, BookNode.Author, BookNode.Year);
}
}
There are multiple problems in your code right now.
The first one (I kid you not) is with code formatting and indentation. Your pasted sample didn't have a regular format or indentation to speak of. It's more difficult to follow code flow even in short samples such as this. Always indent your code, and pick a coding style (there are several) and stick to it.
Regarding code flow, the first problem is in error checking. Namely, you check for fopen return status, but do not take sufficient action should opening a file fail.
The second problem is a conceptual one. You don't seem to realise that an array of N characters can only hold a string with a lenght of N-1. Therefore, char[4] is hardly ever a suitable format for storing years as strings.
Now that those issues have been dealed with, here are the actual flaws that would prevent your code from working in any case:
1) The fgets function will read up until it either fills your buffer or reaches an end-of-line or an end-of-file character. Yet you still call fgets thrice to try and read a single-line entry in your file. It's unlikely what you want to do. You have to re-think the contents of your loop.
2) Your "main" loop condition is likely to be flawed. This is a very common misunderstanding of the use of feof & co. Assuming your data file contains a newline at the end (and it would only be regular for it to do so), your loop will execute one time too many.
It's better to structure your line reading loops like this:
while (fgets(buffer, BUF_SIZE, stdin)) { /* parse buffer */ }
3) You have elementary problems with memory management in your code: namely, the function addEntry fails to allocate memory to store your records. Instead, all entries in your linked list will end up pointing to the same shared buffer you allocate in your main function.
There are several ways to fix this. One is to use several calls to malloc for each member of your BookNode structs (title, author, and year). Another, perhaps preferable method is to use variable-size structs, like this:
struct BookNode {
char *title;
char *author;
char *year;
struct BookNode *next;
char buffer[]; // this shorthand requires C99
};
For each struct BookNode you allocate enough storage after them, so that you can copy there the contents of your shared buffer. title, author, and year then point to this appended storage. This way you won't end up overwriting the contents of other BookNodes in the next iteration of your loop. And you only need one free to free an entire node.
I probably didn't list all the problems in your code here. Perhaps instead of another rewrite, you should first try to tackle a smaller subproblem such as reading a single entry from stdin and building up from there?
addEntry should allocate memory for title, author and year.
Also, doing fgets three times would read 3 lines. You need one fgets per loop, and split the result to different parts (e.g. using strtok_r).
What you do is save a pointer to a static buffer. When reading the next line, this buffer is overwritten with new data.
Note that if you allocated data, you must eventually free it. The entry's destructor will need to free.
example of strtok
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char line[] = "Absalom, Absalom!:William Faulkner:1936\n";
char *p;
char * Title;
char * Author;
char * Year;
p = strtok(line, ":");
Title = strdup(p);
Author = strdup(strtok(NULL, ":"));
Year = strdup(strtok(NULL, ": \n"));
printf("\"%s\",\"%s\",\"%s\"\n", Title, Author, Year);
free(Title);
free(Author);
free(Year);
}
//result:"Absalom, Absalom!","William Faulkner","1936"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct BookNode {
char * Title;
char * Author;
char * Year;
struct BookNode * next;
} * head;
void addEntry(char * T, char * A, char * Y);
void display();
int numEntries();
//void writeBookData(struct BookNode * selection);
void free_book(struct BookNode *bnp){
if(bnp == NULL) return;
free(bnp->Title);
free(bnp->Author);
free(bnp->Year);
free_book(bnp->next);
free(bnp);
}
int main() {
FILE * fpointer;
fpointer=fopen("booklist.txt","r");
if(fpointer == NULL){
printf("Booklist could not be opened.\n");
exit(EXIT_FAILURE);
}
char Title[50+1];
char Author[50+1];
char Year[4+1];
head = NULL;
while (EOF!=fscanf(fpointer, "%50[^:]%*c%50[^:]%*c%4[^\n]%*c", Title, Author, Year)){
//note:The input number of characters is limited (Eg50), it (because minutes in excess of the limit is used in the following items) there must be large enough.
addEntry(Title, Author, Year);
}
fclose(fpointer);
int entryCount = numEntries();
printf("There are %d entries in this Book list\n", entryCount);
display();
free_book(head);
return 0;
}
void addEntry(char * T, char * A, char * Y){
struct BookNode * tempNode, * iterator;
tempNode = (struct BookNode *)malloc(sizeof(struct BookNode));
tempNode->Title = (char *)malloc(strlen(T)+1);
strcpy(tempNode->Title, T);
tempNode->Author = (char *)malloc(strlen(A)+1);
strcpy(tempNode->Author, A);
tempNode->Year = (char *)malloc(strlen(Y)+1);
strcpy(tempNode->Year, Y);
tempNode->next = NULL;
iterator = head;
if (head == NULL){
head = tempNode;
} else {
while(iterator->next != NULL){
iterator = iterator->next;
}
iterator->next = tempNode;
}
}
int numEntries(){
if(head == NULL)
return 0;
else{
int count;
struct BookNode *iterator;
for(count=0, iterator=head; iterator!=NULL; iterator = iterator->next, ++count)
;
return count;
}
}
void display(){
if(head == NULL)
return ;
else{
struct BookNode *iterator;
for(iterator=head; iterator!=NULL; iterator = iterator->next)
fprintf(stdout, "%s:%s:%s\n", iterator->Title, iterator->Author, iterator->Year);
}
}
I am a new C user have problems with pointers.
The function add_word(*word_to_add) should take a c string and add it to the appropriate word_node linked list. However, subsequent additions seem to be overwriting the word element of all nodes in the hash table. I think this is happening because I am setting each nodes word element to be a pointer to word_to_add rather than copying the value of word_to_add.
#define HASH_TABLE_SIZE 10
static char **word_list;
struct word_node {
char* word;
struct word_node *next;
};
static struct word_node *word_hash_table[HASH_TABLE_SIZE];
static int hash(char *word) {
int ascii_char;
int key;
key = 0;
while (*word != '\0') {
ascii_char = tolower(*word);
key += ascii_char;
word++;
}
key %= HASH_TABLE_SIZE;
return key;
}
void ws_add_word(char *word_to_add)
{
int word_position;
word_position = hash(word_to_add);
if (word_hash_table[word_position] == NULL)
{
struct word_node* p;
p = malloc(sizeof(struct word_node));;
p->word = word_to_add;
p->next = NULL;
word_hash_table[word_position] = p;
++num_words;
} else {
struct word_node* p;
p = word_hash_table[word_position];
while (p->next != NULL)
{
p = p->next;
}
struct word_node* q;
q = malloc(sizeof(struct word_node));
q->word = word_to_add;
q->next = NULL;
p->next = q;
++num_words;
}
I think your code is ok as is. If you are having problems, it may be in how you are calling the function. For example, here is a quick & dirty sample:
#include <stdio.h>
#include <stdlib.h>
int num_words;
/* paste sample code here */
#define HASH_TABLE_SIZE 10
// rest of code
void ws_add_word(char *word_to_add)
{
// function code
}
/* end of sample code */
int main (void)
{
char a[] = "Hello";
char b[] = "Helkp"; // chosen to have the same hash result
ws_add_word((char *)&a);
ws_add_word((char *)&b);
}
I compiled with gcc -g and ran through gdb. Doing so and stepping through ws_add_word and examining the contents of word_hash_table seems to do what you want. If it still doesn't work, you should give an example of how you are calling ws_add_word.
Also, if you simply change p->word = word_to_add with strcpy(p->word,word_to_add), you will probably get a seg fault because p->word has not been set to anything meaningful yet. You need to p->word = (char *)malloc(N) where N is big enough, and then strcpy, if that's what you really want to do. Whether you want to or not depends on whether the memory location pointed to by char *word_to_add will be valid the next time you need to use it.
You cannot just equate two strings or character pointers like:
char* p1, p2;
p1=p2; // THIS IS INVALID
In your code you have done this mistake two times:--
p->word = word_to_add;
and
q->word = word_to_add;
This says that you are making p->word point to word_to_add which is a pointer.It will just start referring to the same object but not copy the string which you expect.
It won't copy the contents of word_to_add to q->word, which you are assuming to be done.
You need to copy the strings using any string copy function like: strcpy, strncpy or memcpy.
replace p->word = word_to_add with
strcpy(p->word,word_to_add);
and similarly
replace q->word = word_to_add with
strcpy(q->word,word_to_add);
--
Kr. Alok
Looks good to me, except for line 10 in ws_add_word.
Change
q->word = word_to_add;
to
p->word = word_to_add;
The node's char pointer 'word' seems to point to the original string rather than holding a copy of its own. This is fine as long as the original string doesn't change. For example:
//Assume word_to_add is "String 1"
p->word = word_to_add;
//Now change word_to_add to "String 2"
//After this p->word would be "String 2"
I don't know if that was the intended behavior. You might want to allocate memory for every 'word' pointer in the node structure and copy the word_to_add string.