C memory allocation for linked list - c

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

Related

Why am I getting a segmentation fault when I try to assign an element from an array to a same type value in my data structure in C?

I'm writing a program that is supposed to assign characters from a buffer into a hash-table. I ran valgrind on my program and it signals to a particular line (tmp->word = buffer[i];) and keeps telling me there is a segmentation fault there.
I tried hardcoding the problem line to (tmp->word = 'c';) but the compiler rejected that implementation. I checked to see if the buffer array was initialized, which it was. The program compiles when the problem line is changed to (tmp->word = buffer[i];) but that leads back to a segmentation fault. I have also tried printing the character field in my data structure after I assign it, but the segmentation fault occurs before that can happen. This is what I've written so far. Any help would be greatly appreciated.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
struct node* next;
char word;
}
node;
void unload(node* current);
int main(void)
{
node* table[26];
char buffer[5] = "Hello";
printf("%s\n", buffer);
int index = tolower(buffer[0]) - 'a';
node* tmp = table[index];
for(int i = 0, n = strlen(buffer); i < n - 1; tmp = tmp->next)
{
tmp->word = buffer[i];
printf("%c\n", tmp->word);
i++;
}
//follows word that was input
index = tolower(buffer[0]) - 'a';
for(int j = 0; j < 1; j++)
{
tmp = table[index]->next;
unload(tmp);
}
}
void unload(node* current)
{
if (current->next != NULL)
{
unload(current->next);
}
free(current);
}
As was mentioned before in the comments and answer, my array of pointers wasn't initialized. This was a part of the main problem I had which was experiencing a segmentation fault when I tried to assign table[i]->word and table[i]->next a value. No memory was allocated for the nodes in the table so I went and did that which fixed most the problems! Something I learned, however, is that I could not assign a string to table[i]->word which is an array of characters in my now less buggy program, and instead had to use strcpy to read a string into that memory space (please correct me if I'm wrong on that). Thank you all for your help and advice, it was really useful! Posted below is the version of my program that actually works save for a conditional that I need to implement thanks to your guys' help! Again, thank you very much!
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cs50.h>
#define LENGTH 45
#define CAPACITY 26
typedef struct node
{
struct node* next;
char word[LENGTH + 1];
}
node;
int hash(char* current);
void unload(node* current);
int main(void)
{
//const unsigned int N = 26;
node* table[CAPACITY];
for(int i = 0; i < CAPACITY; i++)
{
table[i] = malloc(sizeof(node)); // this was table[i]->next before. I didn't allocate memory for this node and then tried to defrefernce to a field in a node I though existed
if(table[i] == NULL)
{
printf("Could not allocate memory for hashtable node");
for(int j = 0; j < CAPACITY; j++)
{
unload(table[i]);
}
return 1;
}
table[i]->next = NULL; //just reinitializing the value here so that its not a garbage value
//table[i]->word = "NULL";
}
int q = 0;
while(q < 3) //ths will be chnaged so that we're reading from a file into a buffer and that get_string is gone, hash() stays tho
{
char* name = get_string("Here: ");
int index = hash(name);
if(table[index]->next == NULL)
{
node* cursor = malloc(sizeof(node)); //I'm not executing this if the hash code is the same
table[index]->next = cursor;
strcpy(cursor->word, name); //for some reason you can't just assign a value to an element in an array in a data structure, seems that you need to read the data you want to assign into the location of the element
//cursor->word = name;
cursor->next = NULL;
printf("%s\n", cursor->word);
}
q++;
}
for(int i = 0; i < CAPACITY; i++)
{
unload(table[i]); //wonder why I don't need to do table[i]->next? does this not free the hash table after the first iteration?
// the answer to above is because we are only freeing the node which is that element in the array, not the array itself
}
strcpy(table[6]->word, "Zebra");
printf("%lu\n", sizeof(table[6]));
printf("%s\n", table[6]->word);
/*for(int i = 0; i < CAPACITY; i++)
{
unload(table[i]); //only problem here is that it will eventually free the hash table itself after the first linked list
}*/
}
int hash(char* current)
{
int index = tolower(current[0]) - 'a';
return index;
}
void unload(node* current)
{
if (current->next != NULL)
{
unload(current->next);
}
free(current);
}
As is the comments the main problem is an array of uninitialized pointers. As "intuitive way" while you are coding you may think the once you typed node* table[26]; as int type variables, this will be set to NULL automatically as a pattern behavior or something.But it points to a random location in memory when you declare it. It could be pointing into the system stack, or the global variables, or into the program's code space, or into the operating system.
So, you must give them something to point to and in this case is a NULL. You can do it like this node* table[26] = {NULL};. Another point is when you type char buffer[5] = "Hello";. The char buffer[5] essentially is a pointer pointing to a memory address that the system saves so you can put your string. The memory is saved in blocks so when you type char buffer[1] for example you "jump" to the second part of the entire block which represents the string.
When you do char buffer[5] = "Hello"; " it's sounds like " you are trying to make the Hello string fit in the last piece of the block. To fix this just type char buffer[6] = {"Hello"};(Because you need n+1 of size, you have to include the \0 character). And it will fit properly. Now i think you can figure out how to do the rest.

Using pointers for string manipulation in c

Here I'm taking a sentence a checking if it is a palindrome or not.I'm doing this in the process of learning stacks.
Is there a way i can use pointers instead of char array 'sent' so that the number of input characters need not be constrained to 20 in the following code?
The code is working fine, but should there be any improvements in terms of performance or anything else?
is there anything important about pointers i should remember while using stacks, like initializing it to NULL?
Thanks
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node
{
char data;
struct node *link;
}StackNode;
void insertData(StackNode **);
void push(StackNode **, char);
void checkData(StackNode **);
bool pop(StackNode **,char *);
char sent[20] = "";
void main()
{
StackNode *stackTop;
stackTop = NULL;
insertData(&stackTop);
checkData(&stackTop);
printf("\n");
return;
}
void insertData(StackNode **stackTop)
{
char c;
int len;
printf("Enter the Sentence\n");
while( ( ( c = getchar() ) != '\n'))
{
if( ( ( c>='a' &&c<='z') || (c>='A' && c<='Z')))
{
if((c>='A' && c<='Z'))
{
int rem;
rem = c-'A';
c='a' + rem;
}
push(stackTop,c);
len = strlen(sent);
sent[len++]=c;
sent[len]='\0';
}
}
printf("Letters are %s\n\n",sent);
}
void push(StackNode **stackTop,char c)
{
StackNode *pNew;
pNew = (StackNode*) malloc(sizeof(StackNode));
if(!pNew)
{
printf("Error 100:Out of memory\n");
exit(100);
}
pNew->data = c;
pNew->link = *stackTop;
*stackTop = pNew;
}
void checkData(StackNode **stackTop)
{
char c;
int i=0;
while(pop(stackTop,&c))
{
if( c !=sent[i++])
{
printf("Not palindrome");
return;
}
}
printf("Palindrome");
}
bool pop(StackNode **stackTop,char *c)
{
StackNode *pNew;
pNew = *stackTop;
if(pNew == NULL)
return false;
*c = pNew->data;
*stackTop = pNew->link;
printf("char poped %c\n",*c);
free(pNew);
return true;
}
As far as I know, there is no way to have an "infinite array" or an array with no limitations. However, if you use malloc you can produce a section of memory large enough that you won't need to worry about the limitations as much. I see that later on in the code you have used malloc, so I assume you know how it works. However, I would use something like this;
char * sent = malloc(sizeof(char) * 100);
if(sent == NULL){
printf("OUT OF MEMORY!");
return 1;
}
Where 100 is the buffer size you wish to have. I have used a size up to 10000 and had no problems at runtime, so that may be what you need.
In C, arrays are really pointers to statically allocated memory. It is pretty straightforward to create a pointer to an array, or any element in an array. For example, suppose we have you array char sent[20]. If we wanted to create a pointer that pointed to the exact same memory as sent, we can declare char *sentP = sent. We can now replace any use of sent with sentP. We can even create a pointer to the middle of sent: char *sentMidP = sent + 9. Now, sentMidP[0] is the same as sent[9] and sentMidP[-9] is the same as sent[0].
However, unlike sent, we can change where sentP and sentMidP point (think of sent as a constant pointer char * const, which you can't change). Thus, if you had another array char sent2[100]'. You can set the value ofsentPtosent2. What's cool about this is that you can do it *at runtime*, which effectively means that you can change the size ofsentP` depending on the size of your input.
However, there is no need to limit yourself to statically allocated input. C provides the malloc function (see here) to allocate memory at runtime. Thus, if you don't know the size of your sentence at compile time, but you will know it at runtime (say in a variable called sentenceLength), you can allocate `sentP' like the following.
char *sentP = malloc(sizeof(char) * (sentenceLength + 1)); // Plus one for the NUL termination byte in C strings
if (sentP == NULL) {
fprintf(stderr, "No more memory :(");
exit(EXIT_FAILURE);
}
Note how we now have to handle out-of-memory errors. In general, dynamic allocation introduces more overhead, because there is a possibility that we run out of memory, a requirement that we ensure we only access what was allocated, and a need to release the memory with free once we're done.
When you're done with the sentP pointer, be sure to free it with:
free(sentP);
That's it! You can use the sentP pointer we made in your code, and everything should work great. Good luck!

C Dynamically creating array of structs which include variable sized 2d array [duplicate]

I know how to create an array of structs but with a predefined size. However is there a way to create a dynamic array of structs such that the array could get bigger?
For example:
typedef struct
{
char *str;
} words;
main()
{
words x[100]; // I do not want to use this, I want to dynamic increase the size of the array as data comes in.
}
Is this possible?
I've researched this: words* array = (words*)malloc(sizeof(words) * 100);
I want to get rid of the 100 and store the data as it comes in. Thus if 76 fields of data comes in, I want to store 76 and not 100. I'm assuming that I don't know how much data is coming into my program. In the struct I defined above I could create the first "index" as:
words* array = (words*)malloc(sizeof(words));
However I want to dynamically add elements to the array after. I hope I described the problem area clearly enough. The major challenge is to dynamically add a second field, at least that is the challenge for the moment.
I've made a little progress however:
typedef struct {
char *str;
} words;
// Allocate first string.
words x = (words) malloc(sizeof(words));
x[0].str = "john";
// Allocate second string.
x=(words*) realloc(x, sizeof(words));
x[1].FirstName = "bob";
// printf second string.
printf("%s", x[1].str); --> This is working, it's printing out bob.
free(x); // Free up memory.
printf("%s", x[1].str); --> Not working since its still printing out BOB even though I freed up memory. What is wrong?
I did some error checking and this is what I found. If after I free up memory for x I add the following:
x=NULL;
then if I try to print x I get an error which is what I want. So is it that the free function is not working, at least on my compiler? I'm using DevC??
Thanks, I understand now due to:
FirstName is a pointer to an array of char which is not being allocated by the malloc, only the pointer is being allocated and after you call free, it doesn't erase the memory, it just marks it as available on the heap to be over written later. – MattSmith
Update
I'm trying to modularize and put the creation of my array of structs in a function but nothing seems to work. I'm trying something very simple and I don't know what else to do. It's along the same lines as before, just another function, loaddata that is loading the data and outside the method I need to do some printing. How can I make it work? My code is as follows:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words *, int *);
main()
{
words *x;
int num;
LoadData(&x, &num);
printf("%s %s", x[0].str1, x[0].str2);
printf("%s %s", x[1].str1, x[1].str2);
getch();
}//
void LoadData(words *x, int * num)
{
x = (words*) malloc(sizeof(words));
x[0].str1 = "johnnie\0";
x[0].str2 = "krapson\0";
x = (words*) realloc(x, sizeof(words)*2);
x[1].str1 = "bob\0";
x[1].str2 = "marley\0";
*num=*num+1;
}//
This simple test code is crashing and I have no idea why. Where is the bug?
You've tagged this as C++ as well as C.
If you're using C++ things are a lot easier. The standard template library has a template called vector which allows you to dynamically build up a list of objects.
#include <stdio.h>
#include <vector>
typedef std::vector<char*> words;
int main(int argc, char** argv) {
words myWords;
myWords.push_back("Hello");
myWords.push_back("World");
words::iterator iter;
for (iter = myWords.begin(); iter != myWords.end(); ++iter) {
printf("%s ", *iter);
}
return 0;
}
If you're using C things are a lot harder, yes malloc, realloc and free are the tools to help you. You might want to consider using a linked list data structure instead. These are generally easier to grow but don't facilitate random access as easily.
#include <stdio.h>
#include <stdlib.h>
typedef struct s_words {
char* str;
struct s_words* next;
} words;
words* create_words(char* word) {
words* newWords = malloc(sizeof(words));
if (NULL != newWords){
newWords->str = word;
newWords->next = NULL;
}
return newWords;
}
void delete_words(words* oldWords) {
if (NULL != oldWords->next) {
delete_words(oldWords->next);
}
free(oldWords);
}
words* add_word(words* wordList, char* word) {
words* newWords = create_words(word);
if (NULL != newWords) {
newWords->next = wordList;
}
return newWords;
}
int main(int argc, char** argv) {
words* myWords = create_words("Hello");
myWords = add_word(myWords, "World");
words* iter;
for (iter = myWords; NULL != iter; iter = iter->next) {
printf("%s ", iter->str);
}
delete_words(myWords);
return 0;
}
Yikes, sorry for the worlds longest answer. So WRT to the "don't want to use a linked list comment":
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char** words;
size_t nWords;
size_t size;
size_t block_size;
} word_list;
word_list* create_word_list(size_t block_size) {
word_list* pWordList = malloc(sizeof(word_list));
if (NULL != pWordList) {
pWordList->nWords = 0;
pWordList->size = block_size;
pWordList->block_size = block_size;
pWordList->words = malloc(sizeof(char*)*block_size);
if (NULL == pWordList->words) {
free(pWordList);
return NULL;
}
}
return pWordList;
}
void delete_word_list(word_list* pWordList) {
free(pWordList->words);
free(pWordList);
}
int add_word_to_word_list(word_list* pWordList, char* word) {
size_t nWords = pWordList->nWords;
if (nWords >= pWordList->size) {
size_t newSize = pWordList->size + pWordList->block_size;
void* newWords = realloc(pWordList->words, sizeof(char*)*newSize);
if (NULL == newWords) {
return 0;
} else {
pWordList->size = newSize;
pWordList->words = (char**)newWords;
}
}
pWordList->words[nWords] = word;
++pWordList->nWords;
return 1;
}
char** word_list_start(word_list* pWordList) {
return pWordList->words;
}
char** word_list_end(word_list* pWordList) {
return &pWordList->words[pWordList->nWords];
}
int main(int argc, char** argv) {
word_list* myWords = create_word_list(2);
add_word_to_word_list(myWords, "Hello");
add_word_to_word_list(myWords, "World");
add_word_to_word_list(myWords, "Goodbye");
char** iter;
for (iter = word_list_start(myWords); iter != word_list_end(myWords); ++iter) {
printf("%s ", *iter);
}
delete_word_list(myWords);
return 0;
}
If you want to dynamically allocate arrays, you can use malloc from stdlib.h.
If you want to allocate an array of 100 elements using your words struct, try the following:
words* array = (words*)malloc(sizeof(words) * 100);
The size of the memory that you want to allocate is passed into malloc and then it will return a pointer of type void (void*). In most cases you'll probably want to cast it to the pointer type you desire, which in this case is words*.
The sizeof keyword is used here to find out the size of the words struct, then that size is multiplied by the number of elements you want to allocate.
Once you are done, be sure to use free() to free up the heap memory you used in order to prevent memory leaks:
free(array);
If you want to change the size of the allocated array, you can try to use realloc as others have mentioned, but keep in mind that if you do many reallocs you may end up fragmenting the memory. If you want to dynamically resize the array in order to keep a low memory footprint for your program, it may be better to not do too many reallocs.
This looks like an academic exercise which unfortunately makes it harder since you can't use C++. Basically you have to manage some of the overhead for the allocation and keep track how much memory has been allocated if you need to resize it later. This is where the C++ standard library shines.
For your example, the following code allocates the memory and later resizes it:
// initial size
int count = 100;
words *testWords = (words*) malloc(count * sizeof(words));
// resize the array
count = 76;
testWords = (words*) realloc(testWords, count* sizeof(words));
Keep in mind, in your example you are just allocating a pointer to a char and you still need to allocate the string itself and more importantly to free it at the end. So this code allocates 100 pointers to char and then resizes it to 76, but does not allocate the strings themselves.
I have a suspicion that you actually want to allocate the number of characters in a string which is very similar to the above, but change word to char.
EDIT: Also keep in mind it makes a lot of sense to create functions to perform common tasks and enforce consistency so you don't copy code everywhere. For example, you might have a) allocate the struct, b) assign values to the struct, and c) free the struct. So you might have:
// Allocate a words struct
words* CreateWords(int size);
// Assign a value
void AssignWord(word* dest, char* str);
// Clear a words structs (and possibly internal storage)
void FreeWords(words* w);
EDIT: As far as resizing the structs, it is identical to resizing the char array. However the difference is if you make the struct array bigger, you should probably initialize the new array items to NULL. Likewise, if you make the struct array smaller, you need to cleanup before removing the items -- that is free items that have been allocated (and only the allocated items) before you resize the struct array. This is the primary reason I suggested creating helper functions to help manage this.
// Resize words (must know original and new size if shrinking
// if you need to free internal storage first)
void ResizeWords(words* w, size_t oldsize, size_t newsize);
In C++, use a vector. It's like an array but you can easily add and remove elements and it will take care of allocating and deallocating memory for you.
I know the title of the question says C, but you tagged your question with C and C++...
Another option for you is a linked list. You'll need to analyze how your program will use the data structure, if you don't need random access it could be faster than reallocating.
Your code in the last update should not compile, much less run. You're passing &x to LoadData. &x has the type of **words, but LoadData expects words* . Of course it crashes when you call realloc on a pointer that's pointing into stack.
The way to fix it is to change LoadData to accept words** . Thi sway, you can actually modify the pointer in main(). For example, realloc call would look like
*x = (words*) realloc(*x, sizeof(words)*2);
It's the same principlae as in "num" being int* rather than int.
Besides this, you need to really figure out how the strings in words ere stored. Assigning a const string to char * (as in str2 = "marley\0") is permitted, but it's rarely the right solution, even in C.
Another point: non need to have "marley\0" unless you really need two 0s at the end of string. Compiler adds 0 tho the end of every string literal.
For the test code: if you want to modify a pointer in a function, you should pass a "pointer to pointer" to the function. Corrected code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words**, int*);
main()
{
words **x;
int num;
LoadData(x, &num);
printf("%s %s\n", (*x[0]).str1, (*x[0]).str2);
printf("%s %s\n", (*x[1]).str1, (*x[1]).str2);
}
void LoadData(words **x, int *num)
{
*x = (words*) malloc(sizeof(words));
(*x[0]).str1 = "johnnie\0";
(*x[0]).str2 = "krapson\0";
*x = (words*) realloc(*x, sizeof(words) * 2);
(*x[1]).str1 = "bob\0";
(*x[1]).str2 = "marley\0";
*num = *num + 1;
}
Every coder need to simplify their code to make it easily understood....even for beginners.
So array of structures using dynamically is easy, if you understand the concepts.
// Dynamically sized array of structures
#include <stdio.h>
#include <stdlib.h>
struct book
{
char name[20];
int p;
}; //Declaring book structure
int main ()
{
int n, i;
struct book *b; // Initializing pointer to a structure
scanf ("%d\n", &n);
b = (struct book *) calloc (n, sizeof (struct book)); //Creating memory for array of structures dynamically
for (i = 0; i < n; i++)
{
scanf ("%s %d\n", (b + i)->name, &(b + i)->p); //Getting values for array of structures (no error check)
}
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
scanf ("%d\n", &n); //Get array size to re-allocate
b = (struct book *) realloc (b, n * sizeof (struct book)); //change the size of an array using realloc function
printf ("\n");
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
return 0;
}
If you want to grow the array dynamically, you should use malloc() to dynamically allocate some fixed amount of memory, and then use realloc() whenever you run out. A common technique is to use an exponential growth function such that you allocate some small fixed amount and then make the array grow by duplicating the allocated amount.
Some example code would be:
size = 64; i = 0;
x = malloc(sizeof(words)*size); /* enough space for 64 words */
while (read_words()) {
if (++i > size) {
size *= 2;
x = realloc(sizeof(words) * size);
}
}
/* done with x */
free(x);
Here is how I would do it in C++
size_t size = 500;
char* dynamicAllocatedString = new char[ size ];
Use same principal for any struct or c++ class.

String linked list in C

I am new to linked list in C and the problem I have is that I am trying to make a linked list of Strings, but when I try to print that list it prints first char from two different strings. I think I am messing some pointers. Any help please?
Here is my code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
typedef struct _song{char *songTitle; char *songAuthor; char *songNote; struct _song *next;}SONG;
int songCount =4;
char SongTitle[songCount];
char AuthorName[songCount];
char SongNotes[songCount];
char songTitle0[21] = "19 problems";
char songArtist0[21]="JayZ";
char songNotes0[81]="JiggaWhoJiggaWhat";
SongTitle[0]=*songTitle0;//points at string songTitle0
AuthorName[0]=*songArtist0;
SongNotes[0]=*songNotes0;
char songTitle1[21] = "Cig Poppa";
char songArtist1[21]="Biggie Smalls";
char songNotes1[81]="I Luv it When you call me big poppa";
SongTitle[1]=*songTitle1;
AuthorName[1]=*songArtist1;
SongNotes[1]=*songNotes1;
SONG *CurrentSong, *header, *tail;
int tempCount=0;
header = NULL;
for(tempCount=0;tempCount<songCount;tempCount++)
{
CurrentSong = malloc(sizeof(struct _song));
CurrentSong->songTitle= &SongTitle[tempCount];
CurrentSong->songAuthor=&AuthorName[tempCount];
CurrentSong->songNote=&SongNotes[tempCount];
if(header == NULL)
{
header=CurrentSong;//head points to first thing in memory
}
else
{
tail->next=CurrentSong;
}
tail = CurrentSong;//always the last thing in the list
tail->next=NULL;//the next pointer is null always
}
tempCount =0;
for(CurrentSong=header; CurrentSong!=NULL; CurrentSong=CurrentSong->next)
{
printf("\n%d: ", tempCount);
printf("Title: %s ",CurrentSong->songTitle);
printf("Author: %s ",CurrentSong->songAuthor);
tempCount++;
}
return 0;
}
That's not how you're supposed to use linked lists.
It's
typedef struct list {
void *data;
struct list *next;
}
SONG *s = (SONG *)songList->data;
Likewise, for cloning strings, you need to use strdup.
E.g.
s->songTitle = strdup(SongTitle);
s->songAuthor = strdup(AuthorName);
s->songNote = strdup(SongNotes);
Don't forget to free the strings once you're done with them.
SongTitle[0]=*songTitle0;//points at string songTitle0
The comment is not true. You're copying the first character songTitle0 into the first position of SongTitle.
Your setup far too complex. You'll want to just assign songTitle0, without any * or &, to the songTitle element of the list's first link; both are of type char*, so that's just a pointer copy. Skip the SongTitle, AuthorName and SongNotes variables, they serve no purpose.
The three variables SongTitle, AuthorName and SongNotes are array of char, not array of string. You need to change their declaration to:
char* SongTitle[songCount];
char* AuthorName[songCount];
char* SongNotes[songCount];
Then, you need to update them like that:
SongTitle[0] = songTitle0;//points at string songTitle0
AuthorName[0] = songArtist0;
SongNotes[0] = songNotes0;
And when you store them in the linked list:
CurrentSong = malloc(sizeof(struct _song));
CurrentSong->songTitle = SongTitle[tempCount];
CurrentSong->songAuthor = AuthorName[tempCount];
CurrentSong->songNote = SongNotes[tempCount];

Array of strings in C

I'm trying to create a structure storing strings and I'm getting an error incompatible types when I try and insert as string into the array. This my first time working with a program in C. Could somebody help spot my problem.
This is my implementation of list.c
struct list *init_list(int num) {
struct list *p;
p = malloc(LISTSZ(num));
if(p == NULL)
return(NULL);
p->maxsz = num;
p->sz = 0;
return(p);
}
void debug_list(struct list *p) {
int i;
fprintf(stderr, "\nDynamic List\n\n");
fprintf(stderr, " sz = %d\n", p->sz);
fprintf(stderr, " maxsz = %d\n", p->maxsz);
for(i = 0; i < p->maxsz; i++)
fprintf(stderr," %s\n", (p->item[i]));
}
void prt_list(struct list *p) {
int i;
for(i = 0; i < p->sz; i++)
printf("%s\n", (p->item[i]));
}
int ins_list(char *data, struct list **p) {
struct list *q;
if((*p)->sz == (*p)->maxsz) {
q = realloc(*p, LISTSZ((*p)->maxsz + INCRSZ)); // Problem?
if(q == NULL)
return(-1);
q->maxsz += INCRSZ;
*p = q;
}
(*p)->item[(*p)->sz] = data; // incompatible types in assignment
(*p)->sz ++;
return(0);
}
This is my implementation of list.h
struct list {
int sz;
int maxsz;
char item[][1024]; // Problem?
};
#define INITSZ 5
#define INCRSZ 5
#define LISTSZ(n) ((size_t)(sizeof(struct list) + ((n)-1)*sizeof(char[1024]))) // Problem?
struct list *init_list(int num);
int ins_list(char *data, struct list **p);
void prt_list(struct list *p);
void debug_list(struct list *p);
You have an array of char, yet you're trying to put a char * into it.
I would guess that strncpy will do what you want. Alternatively, declare item as an array of char *.
struct list {
int sz;
int maxsz;
char *item[1024];
};
There more differences between C and C++ than it's commonly admit.
For your error the reason is simple you are trying to assign a pointer (char*) at sz wich is an int.
This kind of assignment generate the incompatible type warning.
Second thing you can't do (a least as far as i know) a partially dynamic array as you do it. In your case you should use at least a malloc and the type of item should be char**. However there is a trick to use only one malloc to create a 2D array.
For the realloc nothing hit me ... What is the compilation error ?
However your code doesn't looks like C code :/
You might need to rebuild it form scratch, because you are here making confusion between lists and 2D arrays ...
I can write some examples of codes if you want but you should probably find a C basics tutorial on google.
Good luke :)
At this line:
(*p)->item[(*p)->sz] = data; // incompatible types in assignment
(*p)->item[(*p)->sz] is an array of 1024 char - you can't assign to arrays with = (arrays are "non-modifiable lvalues").
You just need to do a copy. For a length-safe string copy, I prefer to use strncat():
(*p)->item[(*p)->sz][0] = '\0'; /* Truncate existing string to empty */
strncat((*p)->item[(*p)->sz], data, (sizeof (*p)->item[(*p)->sz]) - 1);

Resources