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.
Related
please look at my code below. I was wondering if this the proper way to pass the buffer to a function, fill it, and get it back as a return. Maybe there are some techniques, which I missed as some programmers fill in buffer with zeroes before adding data into it. Apart from that, please do let me know if I have some minor mistakes or issues. Thanks a lot!
#define BUFFER_SIZE 256
void get_data(char *ptr, size_t len)
{
char* temp = (char*)malloc(len * 1);
char sample_data[] = "data";
strcpy(temp, sample_data, sizeof(sample_data));
memcpy_s(ptr, len, temp, len);
free(temp);
}
int main(void)
{
int status = EXIT_SUCCESS;
char* data = (char*)malloc(BUFFER_SIZE * 1);
status = get_data(data, BUFFER_SIZE);
if(status != 0)
return EXIT_FAILURE;
free(data);
return EXIT_SUCCESS;
}
There seems to be quite a few problems.
I guess get_data and fill_data are supposed to be the same function? (But then why is one a void while the other returns status?)
First of all, malloc() can fail and return NULL. Always check the return value of malloc() and ensure the allocation has not failed.
Second, in get_data(), you allocate some memory with char* temp = (char*)malloc(len * 1); and use char *temp to point to it. But then, you effectively throw away that memory and make temp point to the string "fill_data_with_something" instead. In this particular case, the memory allocation within get_data() was completely unnecessary. And the memory that was malloc'd is irrecoverably lost and becomes a memory leak!
Third, you copy 256 bytes from a buffer than contains only "fill_data_with_something" which is definitely smaller than 256. So you are reading beyond the end of the buffer. You should only copy strlen(temp) bytes.
Worst yet, you then try to free() a pointer that is not coming from malloc(). This invokes undefined behaviour.
I implemented an easy list structure where single list elements are defined by the following structure:
struct list_elem {
struct list_elem *next; // ptr to the next element
char *data; // ptr to data
};
Now, I want to do the following:
struct list_elem *elem;
int main() {
elem->data = "some_string";
strcat(elem->data, "another_string");
}
I am worried about an overrun because the man page of strcat states:
The char *strcat(char *dest, const char *src) function appends the src string to the dest string, overwriting the terminating null byte ('\0') at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable; buffer overruns are a favorite avenue for attacking secure programs.
And basically I got no idea how much memory is allocated for my list element.
This statement:
elem->data = "some_string";
makes the data pointer point to string literal "some_string".
And here:
strcat(elem->data, "another_string");
you are trying to copy string literal "another_string" to a pointer which is pointing to another string literal. As per the standard attempting to modify a string literal results in undefined behavior because it may be stored in read-only storage.
You should allocate memory to data, like this:
elem->data = calloc(50, 1); // sizeof (char) is 1
Then copy the "some_string" to it;
strcpy (elem->data, "some_string");
Then concatenate "another_string" to it:
strcat (elem->data, "another_string");
Alternatively, you can use snprintf() also:
snprintf (elem->data, 49, "%s%s", "some_string", "another_string");
EDIT:
Thanks #alk for pointing this.
The elem pointer is not pointing to valid memory.
You should first allocate memory to the struct list_elem pointer elem, like this:
elem = malloc (sizeof (struct list_elem));
if (elem == NULL)
exit(EXIT_FAILURE);
You can search for astrxxx functions(,which are not standard C functions). They dynamically allocates memories while operation.
Github example implementations
astrcat is implemented above.
asprintf is a dynamic version of sprintf.
and more are provided by some GNU compilers
Note: you SHOULD FREE dynamically allocated memories!!
Plus, you should use it like this:
struct list_elem elem; //removed *, as it can cause seg fault if not initialized. you have to initialize by using struct list_elem * elem=malloc(sizeof(struct list_elem)); or something.
int main() {
elem.data = strdup("some_string");//you must free data later
astrcat(&elem.data, "another_string");
//use it
free(elem.data);
}
First, the struct list_elem* elem is initialized as NULL, so it has to be initialized with valid address before -> statements.
You can assign a pointer to the data section to the data, which cannot be modified normally.
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
I have been trying to create a simple program. However, I encountered an error:
gmon.out:too many open files
I am not clear on why it says I have "too many open files". It does not appear I am using files.
#include<stdio.h>
#include<ctype.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
struct position
{
int line;
int place;
struct position *next;
};
struct file
{
struct position *info;
struct file *next;
char *name;
};
struct word
{
char *name;
struct word *right;
struct word *left;
struct file *result;
};
int main()
{
int i;
struct word *d,*c;
char *s="brutus";
printf("%s",s);
c=(struct word*)malloc(sizeof(struct word));
strcpy(c->name,s);
c->left=NULL;
c->right=NULL;
for(i=1;i<=10;i++)
{
d=(struct word*)malloc(sizeof(struct word));
if(d==NULL)
exit(0);
scanf("%s",s);
printf("4");
s=d->name;
printf("%s",d->name);
d->left=NULL;
d->right=NULL;
}
system("pause");
exit(0);
}
What should I do about it?Thank you in advnace for your time!
First off:
gmon.out:too many open files
Means that you're compiling with the -p flag (profiling). gmon.out is the default file-name used by gprof. Just ditch-the-switch, and you won't get that problem anymore.
Of course, not profiling code isn't great, but you'd do well to address a coupe of issues first, before setting about actually profiling your code.
Some of these, quite numerous, issues are:
char *s="brutus";
printf("%s",s);
c=(struct word*)malloc(sizeof(struct word));
strcpy(c->name,s);
List of issues:
char *s should be const char *s, because it points to read-only memory.
Next, Do not cast the return of malloc
Check the return value of functions like malloc, they tell you something
struct wordis a struct of which all members are pointers. After allocating the struct, those pointers are invalid: you need to allocate memory for those members, too
strcpy expects the destination (c->name) to be a valid pointer, as I explained above: this is not the case here
What, then, should this code look like:
const char *s = "brutus";
c = malloc(sizeof *c);
if (c == NULL)
{
fprintf(stderr, "Could not allocate memory for struct word\n");
exit( EXIT_FAILURE );
}
//allocate enough memory to store the string
c->name = malloc(
(strlen(s)+1) * sizeof *c->name
);
//OR same, but shorter, works because the type char is guaranteed by the standard to be 1 byte in size
c->name = malloc(strlen(s)+1);
if (c->name == NULL)
exit( EXIT_FAILURE );//could not allocate mem
c->name[0] = '\0';//set to empty string, now we can use safer functions:
strncat(c->name, s, strlen(s));
After you address these issues, seriously re-think your approach, and ask yourself what it is you're actually trying to do here:
for(i=1;i<=10;i++)
{
d=(struct word*)malloc(sizeof(struct word));
if(d==NULL)
exit(0);
scanf("%s",s);
printf("4");
s=d->name;
}
You're allocating a struct 10 times, each time re-assigning it to d. You never free this memory, though. which is bad practice.
Again: don't cast the return of malloc, but that's the least of your worries.
if (d == NULL)
exit(0);
Ok, now you check the return of malloc. Great. But why on earth are you terminating with 0 (indicative of a successful run). There's a macro for this, too. You could've written:
if (d == NULL)
exit( EXIT_SUCCESS);
Clearly, EXIT_SUCCESS is not what you should communicate.
that const char *s is now being used to store user input. That's not going to work, though, as it points to read-only memory, so forget about the unsafe scanf("%s", s); statement. Use a stack variable, and make sure the input buffer is cleared, or use a safe alternative.
But then you go and do something as absurd as this:
s = d->name;
Again, d->name, like in the case with c, is an invalid pointer. Why assign it to s here? there's no point, no reason... only madness.
Bottom line: Kill this code before it hatches, start again, and please use these tips/recommendations and critiques as a guideline.
I have no idea why you're getting a 'too many open files', but this line:
strcpy(c->name,s)
is writing data to random memory, which could cause all kinds of problems.
You need to malloc() that c->name first.
Also that scanf to s looks suspicious, and d->name is never assigned anything either.
The reason that you're getting 'too many open files' is probably because some memory is getting overwritten in such a way that just happens to trigger that particular error. Welcome to the world of undefined behaviour. IE: If you overwrite random memory, basically anything can happen.
The first bug is in the line
strcpy(c->name,s);
At that point, c->name is an uninitialised pointer so the program will crash if you are lucky.
Reading your comment: You fixed the second bug. The first bug is still unfixed. And there's the third bug in the line
s=d->name;
This string copy will run off through memory, starting at whatever c->name points to until it finds a null terminator.
strcpy(c->name,s);
You have allocated space for c but not for the name pointer in c.
c->name = malloc([some length]);
c->name points somewhere, but you don't know where until you malloc it. That's why you're getting a seemingly random error, because your executing a string copy from an unknown location for an unknown number of bytes and you are clobbering whatever s points to for an unknown number of bytes.
I'm trying to loop through the contents of a stream to dynamically generate nodes in a list, given the contents of each line that I read. I have a struct that I defined below:
struct info {
char *mystring;
char *file;
int line_no;
struct info *next;
};
I use this loop to iterate through the stream:
while(1) {
char t [KMAX];
char* file;
char* line_no;
char* text;
if (fgets(t, KMAX, file_pipe) != NULL) {
file = strtok (t, delimiter);
line_no = strtok(NULL, delimiter);
int line = atoi(line_no);
text = strtok(NULL, delimiter);
add(&head, text, line, file);
}
I know the variables are passed correctly to my add function, because I print them out each time and I can verify it. However, the problem comes when I try to print the list. It just prints the last line of text and file name, but the integer value changes accordingly. My guess is that it has something to do with the array being destoryed and being re-created each time in the same block of memory, so the pointers get changed each time.
I'm not sure what the proper method is to go about fixing this problem. Do I modify my while loop somehow and use char pointers in a difference manner, or should I change my struct somehow to hold the variables, instead of just using pointers? I would appreciate any feedback!
EDIT : Added more code
void add(struct info **x, char * text, int line_no, char * file) {
struct info* current = *x;
struct info* newInfo;
newInfo = malloc(sizeof(struct info));
(*newInfo).next = NULL;
(*newInfo).grepstring = text;
(*newInfo).line_no = line_no;
(*newInfo).file = file;
if (current == NULL) { //indicates the head is null, special case
*x = newInfo;
} else {
//get to the end of the list
while ((*current).next != NULL) {
current = (*current).next;
}
//apends node to the end of the list
(*current).next = newInfo;
}
}
When you say char* text, what you are doing is allocating a char* on the stack. strtok isn't pointing it to some newly allocated memory, it's pointing it into the stack-allocated space of t.
This memory is lost when it falls out of scope, which happens at the bottom of each iteration of the while loop. Any references to its address might point to the correct contents, or nothing, or some other random value after that point - the behavior they exhibit is undefined.
You need the contents of each struct info to survive the loop (and, presumably, continue to survive for the foreseeable future). To do this you must make a heap allocation. In C this is done via the malloc function.
In your add method, say:
char* text_copy = malloc(strlen(text)+1); // +1 for trailing NUL character
strcpy(text_copy, text);
This will create new memory on the heap, having the same contents as the original text.
You should do this for all the contents of the struct info, since at the moment they're all pointers into the stack-allocated t buffer.
You must free the memory again when you are done with it, but it will last until then.
You don't show us what add() does, but apparently it just assigns the results of calling strtok() directly to the members of a struct. You can't do that -- use strdup() (or malloc() and strcpy()) to make a copy of each char * before assigning them to a struct member. The pointers strtok() returns point into that char buffer, and they become invalid with each new loop iteration.
The only buffer you ever created for holding strings was t, which you made at the top of your while loop:
char t [KMAX];
So all of your char * pointers will be pointing somewhere into that buffer, but that's a problem because you change the contents buffer every time you call fgets. After you are done reading the input, the only text you actually have stored in RAM will be the data from the last call to fgets.
You could change the add function so it allocates new buffers and copies the strings to them. There is already a function that does that for you and it is called strdup. Something like this would work (though I have not tested it):
void add(struct info **x, char * text, int line_no, char * file) {
...
newInfo = malloc(sizeof(struct info));
newInfo->next = NULL;
newInfo->grepstring = strdup(text);
newInfo->line_no = line_no;
newInfo->file = strdup(file);
...
}