I have a unique case where I'm trying to store a 4096 character string in a struct member. However, I'm mallocing the usually amount of memory for a shorter string, but am still getting a valgrind error:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct List {
char * name;
int grade;
struct List * next;
};
int main(void) {
struct List * newList;
char * bigString;
int i;
bigString = malloc(sizeof(char)* 4096);
for (i=0; i<4096; i++)
bigString[i] = 'a';
newList = malloc(sizeof(struct List));
newList->next = NULL;
newList->name = malloc(strlen(bigString)+1);
free(bigString);
free(newList->name);
free(newList);
return 0;
}
the line:
newList->name = malloc(strlen(bigString)+1);
Returns an error Invalid read of size 1
But wait a second, I'm mallocing the lenght of the string, plus 1 for the null terminator, what's going on here?
In fact I even tried this:
newList->name = malloc(sizeof(char) * strlen(bigString) +1);
And heck I even tried to null terminate the string after the malloc call:
newList->name[strlen(bigString)] = '\0';
To no avail..
I'm actually beyond confused as to what I've done wrong here. Any ideas?
bigString itself is not null-terminated, so strlen(bigString) results in trying to read past the end of the space allocated for bigString.
You forgot to add a \0 at the end of BigString.
Related
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.
I have a struct called Person, that contains two attributes - first and last name.
After successfully dynamic allocation of memory for a variable of Person type, giving values to the attributes I would like to free the memory, but I keep getting a runtime error (the program window just crashes)
this it the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char firstName[15];
char lastName[15];
} Person;
void main(){
int len = 0;
char firstName[]="danny", lastName[]="johnes";
Person *temp = (Person*)malloc(sizeof(Person));
if (temp == NULL)
return;
len = strlen(firstName);
temp->firstName[len] = (char*)malloc(sizeof(char)*(len));
if (temp->firstName == NULL)
return;
strcpy(temp->firstName, firstName);
len = strlen(lastName);
temp->lastName[len] = (char*)malloc(sizeof(char)*(len));
if (temp->firstName == NULL)
return;
strcpy(temp->lastName, lastName);
freePerson(temp);
system("pause");
return;
}
This is the function I use to free the memory:
void freePerson(Person* ps) {
if (ps != NULL) {
free(ps->firstName);
free(ps->lastName);
free(ps);
}
}
All I want the code to do - is to store the name in a dynamically allocated structure, and free it.
Later on, I plan to replace the hard-coded names with values inputed from file.
Any ideas about the error? Thank you.
You have already space allocated for firstName, so you have to copy the name within the size constraits (15 bytes). You can do this best with snprintf like this:
snprintf(temp->firstName, sizeof(temp->firstName), "%s", firstName);
Same goes for lastName. Mind that both might be truncated if the length exceeds the size of the field.
The other option is to allocate the fields dynamically. Then your struct members should be pointers, not char arrays:
typedef struct {
char *firstName;
char *lastName;
} Person;
You can then allocate and assign the names like this:
temp->firstName = strdup(firstName); // (same for lastName)
But mind that you have to free these fields seperately if you want to free the whole item.
If you don't want to specify a maximum size for the names in the structure, you need to declare them as pointers, not arrays.
typedef struct {
char *firstName;
char *lastName;
} Person;
Then you should assign the result of malloc() to the member, without indexing it. You also need to add 1 to strlen(firstName), to make space for the null terminator.
temp->firstName = malloc(strlen(firstName)+1);
if (temp->firstName == NULL) {
return;
}
strcpy(temp->firstName, firstName);
This is how I would write this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FIRSTNAME_MAXLEN 15
#define LASTNAME_MAXLEN 15
typedef struct
{
char firstName[FIRSTNAME_MAXLEN+1];
char lastName[LASTNAME_MAXLEN+1];
} person_t;
void freePerson(person_t *ps) {
if (ps) {
free(ps); ps=NULL;
}
}
int main(){
const char *firstName="danny";
const char *lastName="johnes";
person_t *temp = calloc(1, sizeof(person_t));
if (!temp) return 1;
strncpy(temp->firstName, firstName, FIRSTNAME_MAXLEN);
strncpy(temp->lastName, lastName, LASTNAME_MAXLEN);
printf("test: firstname: %s\n", temp->firstName);
printf("test: lastname: %s\n", temp->lastName);
freePerson(temp);
return 0;
}
You allocate enough room on the heap and cleanup things with calloc(), then you copy your string with strncpy() limiting to the bytes reserved and avoiding buffer overflow. At the end you need to free() the memory returned by calloc().
Since you allocated char firstName[] and char lastName[] inside your struct you don't need to reserve other memory with malloc() for those members, and you also don't need to free() them.
At least 5 issues:
To duplicate a string, insure allocation includes enough room for the characters including the null character.
Otherwise the strcpy() writes outside the allocation which is undefined behavior (UB).
len = strlen(firstName);
// temp->firstName[len] = (char*)malloc(sizeof(char)*(len ));
temp->firstName = (char*)malloc(sizeof(char)*(len + 1));
// + 1
...
strcpy(temp->firstName, firstName);
Same for lastName.
Also assign to the pointer, not the char. #Barmar
Person members are arrays. For dynamic allocation, they should be pointers. #NthDeveloper
typedef struct {
// char firstName[15];
// char lastName[15];
char *firstName;
char *lastName;
} Person;
2nd test is wrong
// if (temp->firstName == NULL)
if (temp->lastName == NULL)
int vs. size_t.
int len = 0; assumes the string length fits in a int. Although this is exceedingly common, the type returned from strlen() is size_t. That unsigned type is right-sized for array indexing and sizing - not too wide, not too narrow. Not a key issue in this learner code.
// int len = 0;
size_t len = 0;
Tip: cast not needed. Allocate to the referenced object, not the type. Easier to code right, review and maintain.
// Person *temp = (Person*)malloc(sizeof(Person));
Person *temp = malloc(sizeof *temp);
// temp->firstName[len] = (char*)malloc(sizeof(char)*(len + 1));
temp->firstName = malloc(sizeof *(temp->firstName) * (len + 1));
Tip: Although not C standard, many platforms provide strdup() to allocated and copy strings. Sample strdup() code.
temp->firstName = strdup(firstName);
Tip: Likely the most valuable one: A good compiler with warnings well enabled should have warned about temp->firstName[len] = (char*)malloc(sizeof(char)*(len)); as it is a questionable type mis-match in the assignment. These warnings save you and us all time. Insure your next compilation has all warning enabled.
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’m studying flexible array members. I've written the code below based on a 2 line example in the book I'm studying from. The code compiles with gcc -Wall with no errors and also executes without error.
However I don’t know what the (n) at the end of this malloc call is for. I assume if I'm storing a string the the flexible array, I'm supposed to call strlen() on the string and use the returned value for (n). The code seems to work no matter what value I assign to (n) and even works when there is no (n).
struct vstring *str = malloc(sizeof(struct vstring) + n);
Is the value needed or not?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct vstring{
int len;
char chars[]; /* c99 flexible array member to store a variable string */
};
int main()
{
char input_str[20];
int n = 0; /* what should n be it doesn’t seem to matter what value I put in here */
struct vstring * array[4]; /* array of pointers to structures */
int i = 0;
while ( i < 4 )
{
printf("enter string :");
scanf("%s",input_str);
struct vstring *str = malloc(sizeof(struct vstring) + n );
strcpy(str->chars,input_str);
str->len = strlen(input_str);
array[i] = str;
i++;
}
for ( i = 0 ; i < 4 ; i++) {
printf("array[%d]->chars = %s len = %d\n", n, array[i]->chars, array[i]->len);
}
return 0;
}
Yes, you need to allocate enough memory to store your string. So n on your case should be
strlen(input_str)+1.
What you are doing is writing into unallocated memory and invoking undefined behaviour. The code might work, but it is wrong.
You also have a typo(?) in your malloc call. It should be
struct vstring *str = malloc( sizeof(struct vstring) + n );
And don't forget that inputting more than 19 characters with the scanf call will also cause undefined behaviour as you will write out of bounds of your array. You could avoid that with %19s as the conversion specification. You should also check that the scanf() was successful.
I'm trying to assign input to a number of structures with an array of pointers, pointing to each allocated structure. I've been attempting to fill one structure and printing it, but keep getting errors and can't find out why. Any ideas?
Thanks for the help.
/* Structure declaration */
struct personCatalog {
char name[50];
char address[50];
char cityState[50];
char zipCode[7];
} ;
//function to fill structures
void getPerson (struct personCatalog *ArrayOfPointers[]);
int main(int argc, const char * argv[])
{
struct personCatalog *pointerArray[51];
getPerson(pointerArray);
}
void getPerson (struct personCatalog *ArrayOfPointers[]){
struct personCatalog *tempPointer;
char stringCollector[512];
int maxNumberOfPeople = 51;
int num = 0;
while ((gets(stringCollector) != NULL) && (num < maxNumberOfPeople)) {
tempPointer = (struct personCatalog *) malloc(sizeof(struct personCatalog));
strcpy(tempPointer->name, stringCollector);
gets(tempPointer->address);
gets(tempPointer->cityState);
gets(tempPointer->zipCode);
ArrayOfPointers[num] = tempPointer;
num++;
printf("%s", ArrayOfPointers[num]->name);
printf("%s", ArrayOfPointers[num]->address);
printf("%s", ArrayOfPointers[num]->cityState);
printf("%s", ArrayOfPointers[num]->zipCode);
}
ArrayOfPointers[num] = '\0';
}
Corrected it a little bit, try it out, but more work to do....
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Structure declaration */
struct personCatalog {
char name[50];
char address[50];
char cityState[50];
char zipCode[7];
} ;
const int maxNumberOfPeople = 3; // was 51;
//function to fill structures
void getPerson (struct personCatalog *ArrayOfPointers[]);
int main(int argc, const char * argv[]) {
struct personCatalog *pointerArray[maxNumberOfPeople];
getPerson(pointerArray);
}
void getPerson (struct personCatalog *ArrayOfPointers[]){
struct personCatalog *tempPointer;
char stringCollector[512];
int num = 0;
while ((num < maxNumberOfPeople) && (gets(stringCollector) != 0) ) {
tempPointer = (struct personCatalog *) malloc(sizeof(struct personCatalog));
strcpy(tempPointer->name, stringCollector);
gets(tempPointer->address);
gets(tempPointer->cityState);
gets(tempPointer->zipCode);
ArrayOfPointers[num] = tempPointer;
printf("name %s\n", ArrayOfPointers[num]->name);
printf("address %s\n", ArrayOfPointers[num]->address);
printf("cityState %s\n", ArrayOfPointers[num]->cityState);
printf("zipCode %s\n", ArrayOfPointers[num]->zipCode);
num++;
}
//ArrayOfPointers[num] = '\0'; this crashed at end of array
}
Interestingly enough the code works for me with the necessary includes added:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
However, this only holds for reasonable input - the code has a bit of room for improvement, but more on that later on.
The reason you don't see any output is that you are incrementing the index num after you assign the data to the struct, but before you print it - i.e. in the loop you are always dereferencing not yet assigned poiter, in other words garbage. It is only a question of time, when you try to dereference a null pointer (or anything not in your process' memory and segfault.
Now for the flaws:
malloc() always comes with two things: a check for return value and a corresponding free()! The free() is missing, but I understand that there are/will be some other parts of code that could take care of that once the data is not needed any-more. However, you are not checking whether it doesn't return NULL (i.e. failed to allocate memory). That would bring your program down immediately (SEGFAULT due to null pointer dereference).
gets() - I suggest reading the manpage for this function (if you are on Windows, look it up on the internet) - it doesn't guarantee any limits for reading data, hence you can easily overflow your buffer. Use fgets() instead. An alternative might be scanf() with width specifier to %s.
strcpy() - the same as for gets(). Use strncpy() instead, unless you are dead-sure that it won't smash your data. Moreover, you are copying char stringCollector[512] into char personCatalog.name[50] - don't do that. It's inconsistent and if you base your bounds checks on the size of of the former, you are bound to have problems (rather sooner than later).
Last but not the least: an off-by-one error (it really is sometimes hard to get this right).
struct personCatalog *pointerArray[51];
...
int maxNumberOfPeople = 51;
if (num < maxNumberOfPeople)) {
...
num++;
...
}
ArrayOfPointers[num] = '\0'
In the worst case, you are going to write behind ArrayOfPointers (to ArrayOfPointers[51] to be specific).
Use macros and decide whether you want to NULL-terminate the array:
#define MAXPEOPLE 50
struct personCatalog *pointerArray[MAXPEOPLE+1]; /* +1 for the NULL terminator */
if (num < MAXPEOPLE)) ...