This is my struct:
typedef struct Person {
char* name;
int age;
float height;
float weight;
char** hobbies;
}person;
I tried to fill the name but it just ain't working.
void main(){
person Asaf;
char buffer[50];
int length;
puts("Please enter the name of the student");
gets(buffer);
length = strlen(buffer);
Asaf.name = realloc(buffer, length);
}
I just can't figure the problem...
I guess it has something to do with the realloc function.
please help!! :P
You are trying to realloc (which operates on the heap) an array that is allocated on the stack, which is a no-no. What you want instead is something like:
Asaf.name = strdup(buffer); /* POSIX: allocates a string copy of buffer on the heap */
Or, more standardly:
Asaf.name = (char*) malloc(strlen(buffer) + 1); /* TODO: should check allocations for NULL return */
strcpy(Asaf.name, buffer);
Also, you should use fgets() rather than gets(). gets() is inherently dangerous and should never be used because it doesn't do any bounds checking on the array to which it writes.
fgets(buffer, sizeof(buffer), stdin);
This function returns a pointer to the newly allocated memory, or NULL if the request fails.
so as realloc operates on heap here getting pointer to the memory allocation in heap area to a pointer guy sitting in stack can cause some problems buddy.
so maybe undefined behavior can be the answer for the output you are getting.
About how using realloc, all the didactic examples include this-
Use realloc:
1>Check if it's NULL.In this case use perror and exit the program
2>If it's not NULL use the memory allocated
3>Free the memory when you don't need it anymore.
possible duplicate of:How to use realloc in a function in C
Related
typedef struct node{
char *name;
//etc...
}N
If i had char *string got from stdin and i wanted to pass it to N, i could do easily N->name=string, or it would be bettere to use strcpy?
which is more correct? which is more efficient? why?
You want to use a buffer to read your input from stdin. But if you don't make a copy, your string will be lost at the next read iteration. If you are going to allocate memory, and if you don't know the size of the string you receive, you should use a function like strdup instead of strcpy.
node->name = strdup(string_to_copy);
if (node->name == NULL)
printf("My allocation has failed!\n");
The allocated memory will have to be freed afterward. If the allocation fails, you will have a message (you should always check the success of your memory allocation).
If you don't want to allocate memory and if you know that the size of your input will never be higher than say, 100, you could get away with something like this:
typedef struct node{
char name[100];
//etc...
}N
In that case you could use the following. Note that strcpy is a dangerous function that should be used with extra-care:
strncpy(node->name, buffer, 100);
strcpy(node->name, buffer);
EDIT:
Here is a way to free your memory properly:
if (node->name != NULL)
{
free(node->name);
node->name = NULL;
}
This construction will free your memory and helps preventing double-free.
Answering "the result is the same, but what's the difference?" (from comment)
Starting from:
N *node = malloc(sizeof(N));
char input_from_stdin[80];
If we do
strcpy(node->name, input_from_stdin);
we invoke undefined behavior, but it might appear to work.
If we do
node->name = input_from_stdin;
than node->name only contains its expected value until input_from_stdin is reused, which is typically when the next line is read form input.
If we do
node->name = malloc(strlen(input_from_stdin) + 1);
strcpy(node->name, input_from_stdin);
we make a copy of the input that lives until we free it; but we must remember to free node->name before freeing node.
We can also do
typedef struct node{
char name[MAXSIZE];
//etc...
}N;
and then expect
strncpy(node->name, input_from_stdin, MAXSIZE-1)[MAXSIZE-1] = 0;
to work.
Some poeple do
strncpy(node->name, input_from_stdin, MAXSIZE);
which is valid but getting it back out again is touchier. This is rarely seen out of fixed-width records on disk now. We don't like MAXSIZE much anymore and prefer everything stretchy.
Here is my code:
int main() {
typedef struct {
int recordCount;
char *firstName;
char *secondName;
char *id;
char *email;
}student;
student *students = malloc(sizeof(*students));
int i = 0;
while (students[i].firstName[0] != '.'){
students[i].firstName = (char *)malloc(sizeof(char*));
scanf("%s", students[i].firstName);
i++;
students = realloc(students, sizeof(students) * (i + 1));
}
}
When I run it through a for loop it works, I'm pretty sure it's just something silly going on with my while loop.
malloc returns a block of uninitialized memory. So students[i].firstName is an uninitialized pointer which you attempt to dereference. Reading and dereferencing an uninitialized pointer invokes undefined behavior, which in this case manifests as a crash.
When you do allocate space for the firstName member, you only allocate sizeof(char*) bytes for it which is the size of a pointer, not necessarily the length of a string you would want to read.
Create a buffer to read strings into that's big enough for what you might need, then use strdup to create a copy to assign to the relevant pointer.
student *students = NULL;
int i = 0;
char str[100];
scanf("%99s", str);
while (str[0] != '.'){
students = realloc(students, sizeof(*students) * (i+1));
students[i].firstName = strdup(str);
i++;
scanf("%99s", str);
}
For a start,
students[i].firstName = (char *)malloc(sizeof(char*));
allocates enough space for a character pointer, typically four or eight bytes.
While there are some names that will fit in that (such as Pax or Bob), the vast majority probably won't.
You need to allocate enough space for the largest name (and string terminator), such as with:
#define MAX_NAME_LEN 100
students[i].firstName = malloc(MAX_NAME_LEN + 1);
There are plenty of issues in your code.
When you are using malloc, you actually specify the data type and not the pointer type which is I believe is not your intent here. If you are specifying a pointer type with sizeof, the pointer will point to a memory location having the size of the pointer. This is not what you want in this case.
After the line student *students = malloc ... . The students will point to a memory location which will hold zero values in firstName. You need to use malloc for these. Since you are not doing this you are getting a segmentation fault because you are dereferencing an invalid pointer (pointing to location 0). You are trying to access it first and using malloc afterwards.
If you
student *students = malloc(sizeof(*students));
you are allocating size of one pointer. What you want to do is instead
student *students = malloc(sizeof(students));
and for the same reason, students[i].firstName = (char *)malloc(sizeof(char*)) quite surely do not have enough memory for your name as well, try malloc(sizeof(char)*100) or so.
I just began starting to code in C and having a lot of difficulties with an assignment. I'm suppose to use malloc and free to create a record database using structures. The structures will act as my database. I need to be able to add and delete records. I also cant use arrays for my structures but can use arrays anywhere else in the code. The teacher gave me an idea on how to lay out the code but I don't understand how to save my inputs to add it to a record. Any help??
I have a lot of my code commented out to trouble shoot. also the the two printf statements on the bottom of main are there for troubleshooting. I can get it to print out first name but soon as I add last name, I get a seg fault. I believe I'm not allocating memory for this to happen but don't fully understand this stuff yet.. PLEASE HELP! Thanks!!!!
The problem lies in "library" variable of type "struct record" initialization or actually the lack of it:
struct record library; //this will hold info for user input
fName and lName members are uninitialized pointers to char. Allocate memory for your buffers and initialize those pointers to point to those buffers. Uninitialized pointers simply point to "some" memory location. When you put data into that location anything can happen! Alternatively provide fixed size buffers in place of those pointers like:
struct record {
char fName[100];
char lName[100];
};
That should work as the first step. Next is to use the malloc/free as your assignment says. Revert struct record back to the original format and use malloc to reserve memory for your buffers before passing them to any function or otherwise using them; like so
#define BUFSIZE (100)
library.fName = malloc(BUFSIZE);
library.lName = malloc(BUFSIZE);
After memory reservation you may use them but don't pass more than BUFSIZE number of characters to those buffers.
After you are done with your buffers free the allocated memory:
free(library.fName);
free(library.lName);
After freeing the buffers you may not use them anymore.
Also don't use gets(). It doesn't provide any protection for buffer overflows as the maximum buffer size is not passed as a parameter to gets(). It has been deprecated and will be removed from the forthcoming standard C1X as unsafe.
Because you are reading data into uninitialized pointers:
printf ("Please enter your first name:\n");
gets(library.fName);
printf ("Please enter your last name:\n");
gets(library.lName);
Allocate memory using malloc and use them and free() them once you are done. If you don't need pointers, you can use arrays in your struct.
Please don't gets() as it can't prevent buffer overflow. Use fgets() instead.
int main() should be int main(void) or int main(int argc, char *argv[]) or its equivalent.
None of your struct members have memory allocated to them. For ease, first define them as
char fName[10];
char lName[10];
etc,
Once you are comfortable with this, then try memory allocation. (IOW, one concept at a time)
The problem you have having is that you are not actually allocating any memory to store the input. Let's start with your struct:
struct record{
char * fName;
char * lName;
};
In memory this struct is just two char pointers. The struct itself is 8 bytes long. The pointers aren't initialized to anything, so they have random values. When you use them as pointers, you will point to a random location in memory.
If you want to actually store the first and last names in your struct, then you could create the struct like this:
static const int MaxNameLength = 255;
struct record{
char fName[MaxNameLength + 1];
char lName[MaxNameLength + 1];
};
Alternately you could use the struct the way that you wrote it, but allocate memory for the buffers and update the pointers. If you did that you would need to do this:
static const int MaxNameLength = 255;
struct Record library;
library.fName = (char *)malloc(MaxNameLength + 1);
library.lName = (char *)malloc(MaxNameLength + 1);
Both these methods are valid, but the advantage to the first method is that you would not need to clean up memory yourself. When the struct goes out of scope all the memory is freed. If you malloc the memory yourself, then you also need to free it.
struct record{
char * fName;
char * lName;
//char * sAddress;
//char * city;
//char * state;
//int * zip;
};
In your structure you are using char * fname
but you input method was not correct you have to do malloc for that
But for a newbie in C
keep fname and lname as char array like
struct record{
char fName[100];
char lName[100];
//char * sAddress;
//char * city;
//char * state;
//int * zip;
};
Now your above code works fine ..
fName and lName are pointers, in general you have to allocate memory to each pointers and free memory for each pointer too. If you read or write on a pointer which is unassigned memory segmentation fault will occur,
You can create an array like name[20] and use gets function. Allocate memory to lName and fName like malloc(strlen(name)). Later on free in the end. Try to malloc and free in main function as it can create problem (you will learn later on pass by value and pass by refernce issues)
As in subject of this topic. I have a simple function:
char *to_str(int x)
{
char *s = malloc(6);
if (s == NULL) {
error("malloc");
}
snprintf(s, sizeof(s), "%d", x);
return s;
}
which is allocating memory in its body, and returning such value. How should I handle memory deallocation? What would be the best approach?
How should I handle memory deallocation?
Carefully. And definitely better than you do currently.
What would be the best approach?
The best approach is to free() the memory when you don't need it anymore:
char *str = to_str(1337);
// do stuff with `str'
free(str);
Also, that sizeof() is wrong. It gives you the size of a pointer, not the size of the buffer. You need to keep track of it yourself.
The calling code needs to free the memory using free():
void f(int x)
{
char *s = to_str(x);
// ...
free(s);
}
(By the way, you have a bug: in to_str, sizeof(s) is the size of a pointer, not the length of the string that s points to.)
The first of all, sizeof() is an operator that gives you a length in bytes of type (type of variable) in brackets. Thus instead of actual length of the allocated memory block, you are getting a size of the pointer s, that in common not what you expect.
The second, when you allocating the memory, you should understand the moment when it is not actually used and to make free() on it.
Also, I am not sure that 5 symbols + terminating 0 is an enough length of the string, as in case of the garbage in the x the string will be much longer, so you can corrupt the memory.
The best is not to allocate memory inside function:
char* to_str(char *buffer, size_t buffer_size, int x);
this way you don't have to care about deallocation inside the function and everything is on the caller side.
If you want to create function with the signature you have in the question, you cannot use that in anything like printf("%s", to_str(x)), because this would be a memory leak. You have to make char *str = to_str(x); printf("%s", str); free(str); which is not nice...
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char *s;
printf("enter the string : ");
scanf("%s", s);
printf("you entered %s\n", s);
return 0;
}
When I provide small inputs of length up to 17 characters (for example "aaaaaaaaaaaaaaaaa") the program works perfectly fine but on providing inputs of larger lengths, it gives me a runtime error saying "main.c has stopped working unexpectedly".
Is there some problem with my compiler (codeblocks) or my pc (windows 7)? Or is it somehow related to the input buffer of C?
It's undefined behaviour as the pointer is uninitialized. There's no problem with your compiler but your code has problem :)
Make s point to valid memory before storing data in there.
To manage buffer overflow, you can specify the length in the format specifier:
scanf("%255s", s); // If s holds a memory of 256 bytes
// '255' should be modified as per the memory allocated.
GNU C supports an non-standard extension with which you don't have to allocate memory as allocation is done if %as is specified but a pointer to pointer should be passed:
#include<stdio.h>
#include<stdlib.h>
int main() {
char *s,*p;
s = malloc(256);
scanf("%255s", s); // Don't read more than 255 chars
printf("%s", s);
// No need to malloc `p` here
scanf("%as", &p); // GNU C library supports this type of allocate and store.
printf("%s", p);
free(s);
free(p);
return 0;
}
the char pointer is not initialized, you should dynamiclly allocate memory to it,
char *s = malloc(sizeof(char) * N);
where N is the maximum string size you can read, And its not safe to use scanf
without specifying the maximum length for the input string, use it like this,
scanf("%Ns",s);
where N same as that for malloc.
You are not allocating any memory to the character array so first try to get memory by calling malloc() or calloc(). then try to use it.
s = malloc(sizeof(char) * YOUR_ARRAY_SIZE);
...do your work...
free(s);
You need to allocate enough memory for buffer where your pointer will point to:
s = malloc(sizeof(char) * BUF_LEN);
and then free this memory if you do not need it anymore:
free(s);
You're not allocating memory for your string, and thus, you're trying to write in a non-authorized memory address. Here
char *s;
You're just declaring a pointer. You're not specifying how much memory to reserve for your string. You can statically declare this like:
char s[100];
which will reserve 100 characters. If you go beyond 100, it will still crash as you mentionned for the same reason again.
The problem is with your code .. you never allocate memory for the char *. Since, there is no memory allocated(with malloc()) big enough to hold the string, this becomes an undefined behavior..
You must allocate memory for s and then use scanf()(I prefer fgets())
#include"stdio.h"
#include"malloc.h"
int main(){
char *str;
str=(char*)malloc(sizeof(char)*30);
printf("\nENTER THE STRING : ");
fgets(str,30,stdin);
printf("\nSTRING IS : %s",str);
return 0;
}
The code in C to read a character pointer
#include<stdio.h>
#include<stdlib.h>
void main()
{
char* str1;//a character pointer is created
str1 = (char*)malloc(sizeof(char)*100);//allocating memory to pointer
scanf("%[^\n]s",str1);//hence the memory is allocated now we can store the characters in allocated memory space
printf("%s",str1);
free(str1);//free the memory allocated to the pointer
}
I was getting this problem. I tried this code below and it worked:
char *text;
scanf("%s", *&text);
I dont know how it worked. I just felt like doing it.