This program is crashing. Please tell me what's wrong with it. When I use an array instead of a pointer like Name[12] in the structure it doesn't crash. I guess there is some problem in dynamic memory allocation. Help please.
#include <stdio.h>
struct struct_tag
{
int number;
char *Name;
} struct_name;
main()
{
struct_name.number = 34;
char *Name = (char *) malloc(sizeof(char));
strcpy(struct_name.Name,"A");
printf("%d", struct_name.number);
}
You're allocating a single character:
char *Name = (char *) malloc(sizeof(char));
And then never using that memory for anything. You meant to allocate memory for struct_name.Name, undoubtedly. But even if you had done so, you're then filling it with two characters ('a' and '\0'):
strcpy(struct_name.Name,"A");
which will cause an entirely different bug.
You want to say:
struct_name.Name = malloc( 2 );
Since (a) you shouldn't cast the result of malloc() and (b) sizeof(char) is always 1 and (c) you need room for the 0 at the end of your string.
For errors:
You are allocating memeory for *Name however you are not allocating
memory for struct_name.Name. So first thing is you need to allocate memory for struct_name.Name
As you already know that you'll be storing "A" in
struct_name.Name you should allocate memory for 2 char.("A" is string i.e 'A' and '\0')
For warnings:
If you want to use strcpy function include string.h in your code.
Also if you are using malloc include stdlib.h in your code.
Try this fixed code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct struct_tag
{
int number;
char *Name;
}struct_name;
int main()
{
struct_name.number = 34;
struct_name.Name = malloc(sizeof(char)*2); // As you will store "A"
strcpy(struct_name.Name,"A");
printf("%d \t", struct_name.number);
printf("%s \n", struct_name.Name);
return 0;
}
first look code carefully.
char *Name = (char *) malloc(sizeof(char));
strcpy(struct_name.Name,"A");
Hare for what you allocated memory (char *Name) and in which you copied string(struct_name.Name)?
here you not allocate memory for struct_name.Name. Also you have allocate memory for one character and you tried to copy two characters.('A' and '\0').
It should be
struct_name.Name = malloc(2);
Related
First of all Thanks for visiting my question... :)
I am interested in competitive programming, so I daily do some amount of problem-solving, however, I only know C language at a decent level, and I often face problems while dynamically allocating something as usual, especially for strings and 2D arrays.
But I somehow manage to find ways (thanks to StackOverflow), for example, I wanted to create a function that scans string dynamically until the user enters space or new line, so I came up with the solution below and it works perfectly:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// scanf("%[^\n]%*c", str);
char *create_string(char *ptr)
{
ptr = (char *)malloc(0 * sizeof(char));
unsigned int size = 0;
char c = 0;
while (1)
{
scanf("%c", &c);
if (c == 32 || c == 10)
{
break;
}
size++;
ptr = (char *)realloc(ptr, size * sizeof(char));
ptr[size - 1] = c;
}
ptr = (char *)realloc(ptr, (size + 1) * sizeof(char));
ptr[size] = '\0';
return ptr;
}
int main()
{
char *str;
str = create_string(str);
printf("%s", str);
printf("\n%lu", strlen(str));
return 0;
}
And now for curiosity purposes, I want to know how can I do this same thing using the void function?, something like:
char *str;
create_string(&str);
should start storing everything in the dynamic memory which is pointed by str.
Also, please if you have more knowledge to show in DMA for 2D array, then please show me it, feel free to give examples with different problems.
And also How can I stop scanning the string (which was allocated dynamically) with specific string ending? for example, scanning(any kind of scanning, i.e. int, bool, custom structures etc...) should stop if user enters string "STOP", Please feel free to give pictorial examples.
Because I am sure that this question is burning like a fire in beginner's and intermediate C programmers' minds.
As C passes arguments by value, to return something via an out parameter, you need to pass in a pointer to it. So to return a char * it would:
void create_string(char **s) {
*s = malloc(42);
}
Here is your refactored code. I changed the following:
Eliminate return value of update caller.
Initialize *ptr = malloc(1) for the trailing '\0'. It eliminates an unnecessary and implementation defined malloc(0). This also eliminates the (*ptr)[size] = ... which looks wrong as the last index is expected to be size - 1. Alternatively initialize it to NULL.
Use character constants instead of magic values (32, 10).
sizeof(char) is defined as 1 so leave it out.
Reduced scope of variable c.
free() memory allocated.
(cosmetic) Use size_t size instead of unsigned int size.
(cosmetic) Avoid the noise of casting casting void *.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void create_string(char **ptr) {
*ptr = malloc(1);
size_t size = 1;
for(;;) {
char c;
scanf("%c", &c);
if (c == ' ' || c == '\n') break;
(*ptr)[size-1] = c;
size++;
*ptr = realloc(*ptr, size);
}
(*ptr)[size-1] = '\0';
}
int main() {
char *str;
create_string(&str);
printf("%s\n", str);
printf("%zu\n", strlen(str));
free(str);
}
I didn't fix these issue:
Check return value of malloc(), realloc().
v = realloc(v, ...) is unsafe and will leak memory if realloc() fails. You need to do char *tmp = realloc(v,...); if(!tmp) { // err }; v = tmp;.
Check return value of scanf() otherwise you may be operating on uninitialized data.
Use scanf("%s", ..) instead of for(;;) { scanf("%c", ...). It's more efficient to allocate a chunk at a time instead of per byte.
If user enters ctrl-d (EOF) the program will go into an infinite loop.
It's good idea to separate i/o from logic (i.e. let caller do the scanf(). That way create_string() is much more reusable.
We have pointers inside a struct, do we need to initialize the pointers inside the struct?
I have tried the code below, include this sentence below or not, the code all run well.
(Could some experts give help here? and I read some code, and found seems sometimes initialized, sometimes not, so confused and search/ask here.)
The answer in this link seems not mentioned initialize this pointer inside struct. initializing-a-member-of-a-structure-with-pointers-c
#include "stdio.h"
#include "stdlib.h"
struct part{
int num;
char *name;
};
int main()
{
struct part *p = (struct part*)malloc(sizeof(struct part));
//Include this or not, this code all run well
p->name = (char*)malloc(sizeof(char));
p->num = 1;
p->name = "ss";
printf("%d, %s\n", p->num, p->name);
return 0;
}
No, you should not do that, you are creating a memory leak, because you allocate memory and then forget the pointer value and don't free it.
To remove the memory leak:
p->name = malloc(1); //sizeof char is 1 by definition, and cast not needed
free(p->name);
p->name = "ss";
However, if you look at that, it should be clear that allocating 1 byte of memory, then immediately freeing it, is pointless.
Perhaps you want a copy of the string?
const char *initdata = "ss";
p->name = malloc(strlen(initdata)+1);
strcpy(p->name, initdata);
// Remember to free this at some point
Alternatively, you could use initialize with the string literal, but then you should have const char pointer because string literals are read-only:
struct part{
int num;
const char *name;
};
Can someone explain me why this doesn't work? It appears that the program stops at sprintf(t->tuple[0], "abc"); and I don't know why. Really need help.
int testRemoveMeio(){
int result, i;
struct list_t *list = list_create();
char *tdata[3] = {" ", "2014", "Fixe!"};
struct tuple_t *t = tuple_create2(3, tdata);
struct tuple_t *tdups[4];
struct entry_t *entries[4];
sprintf(t->tuple[0], "abc");
tdups[0] = tuple_dup(t);
entries[0] = entry_create(tdups[0]);
list_add(list, entries[0]);
//extra code similar to above
return 0;
}
Edit:
struct tuple_t {
int tuple_dimension;
char **tuple;
};
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = tuple;
return t;
}
Edited to add another example from the comments:
#include <stdio.h>
#include <string.h>
int main(void)
{
char * s = "ABC";
printf("%s\n",s);
sprintf(s,"DEF");
printf("%s\n",s);
return 0;
}
I pasted the code from your comment into the question. Both that and your original code are failing for the same reason, I think: you're modifying string literals.
It's sad but true that in C, string literals like "hello world" are illegal to modify, yet are assignable to char* without const and without a cast. This makes it easy to screw up, because modifying such a string is undefined behavior, because it may reside in read-only memory in your program.
To fix it, try this:
char tdata[3][6] = {" ", "2014", "Fixe!"};
Or in your second example:
char s[] = "ABC";
This way you are allocating an actual character array with writable storage. But please, always use snprintf() and never sprintf() because the latter is prone to buffer overruns which can crash your program or worse.
You second example is wrong. You should use snprintf(3) (there is no reason to use sprintf in 2014; it is old and dangerous, since it may give a buffer overflow) on some array of char like this:
#include <stdio.h>
int main(void) {
char buf[64];
snprintf(buf, sizeof(buf), "here %s", "ABC");
printf("%s\n",buf);
return 0;
}
You could have used some dynamically allocated memory zone (but then, you should know its size), e.g.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t siz=32;
char* ptr = malloc(siz);
if (!ptr) { perror("malloc"); exit(EXIT_FAILURE); };
snprintf(ptr, siz, "here %s and two is %d", "ABC", 2);
printf("%s\n", ptr);
free (ptr);
return 0;
}
You might use asprintf(3) if your system gives it (e.g. on Linux) like
#define _GNU_SOURCE
#include <stdio.h>
int main (void) {
char* ptrzone = NULL;
asprintf(&ptrzone, "and here %s and one is %d", "ABC", 1);
printf("%s\n", ptrzone);
free (ptrzone), ptrzone = NULL;
}
In serious programs, you often should use the result of snprintf.
Read the documentation of all the functions you are using, so also: perror(3), exit(3), malloc(3), free(3)
You absolutely should read more about C dynamic memory allocation
You should compile with all warnings and debug info (gcc -Wall -g) and learn to use the debugger (gdb) and the memory leak detector valgrind
Some important information is missing as the definition to struct tuple_t and the definition of function tuple_create2. If the error occurs on sprintf(t->tuple[0], "abc") then either t->tuple and/or t->tuple[0] is not correctly initialized/allocated. This former should be an array of at least 1 for the example (but more probably 3 if we look at tdata) strings and the latter to a string buffer (array of char). Check you or provide us the tuple_create2 function.
The way you use sprintf to copy a string is dangerous. On your example this works but if the string to copy contains the '%' character, bad things can happen (% is the character used to specify a format in printf/scanf family of functions. If you want to stay with sprinf use sprintf(t->tuple[0], "%s", "abc") but the simpler is strcpy(t->tuple[0], "abc")
Since you have now added the definition of tuple_create2, I try to answer.
In C, it is up to you to manage the memory. What do you expect from tuple_create2 ?. Your code allocates the space for the "header" (i.e. a struct tuple containing the dimension and an array of strings) and fills it with tuple. The result is a new object which points to the same memory for the data (i.e. the array of strings). This is OK except if you want to modify this array (which seems to be the case). There are 2 things: the array itself (each entry is a pointer to an array of chars - do you want to modify the pointers ?) and the strings (the content of the array of chars). There are several possibilities for this but this depends on you. For instance the function could allocate its own array of pointers and initialize with the existing data:
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = (char **) malloc(sizeof(char *) * tuple_dim);
for(i = 0; i < tuple_dim; i++) // could be replaced by a memcpy
t->tuple[0] = tuple[0];
return t;
}
Then you have to be aware that we copied only pointers. So when you want to modify an element either you simply copy the pointer :
t->tuple[0] = "abc";
or you allocate a new string if you thing it can be modified and you don't want this. I give you an example with "abc" but this is not relevant because "abc" is a constant string which will not be modified. Anyway here is the code (note the use of stdrup which duplicates the string doing a malloc)
t->tuple[0] = strdup("abc");
I have a program that accepts a char input using argv from the command line. I copy the input argv[1] using strcpy to a pointer called structptr(it goes to structptr->words from struct) where memory has been allocated. I then copy character by character from the memory that the pointer structptr points to another pointer called words that points to memory that has been allocated. After i've copied one character i print that element [c] to make sure that it has been copied correctly(which it has). I then finish copying all of the characters and return the result to a char pointer but for some reason it is blank/null. After each copying of the characters i checked if the previous elements were correct but they don't show up anymore([c-2], [c-1], [c]). Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct StructHolder {
char *words;
};
typedef struct StructHolder Holder;
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
int main(int argc, char **argv){
Holder *structptr=malloc(sizeof(Holder));
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
char *charptr;
charptr=(GetCharacters(structptr));
printf("%s\n", charptr);
return 0;
At first I thought this was the problem:
char *words=malloc(sizeof(char)) is allocating 1 byte (sizeof 1 char). You probably meant char *words = malloc(strlen(ptr->words)+1); - You probably want to null check the ptr and it's member just to be safe.
Then I saw the realloc. Your realloc is always 1 char short. When i = 0 you allocate 1 byte then hit the loop, increment i and put a char 1 past the end of the realloced array (at index 1)
Also your strcpy in main is has not allocated any memory in the holder.
In these two lines,
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
need to add one to the size to hold the nul-terminator. strlen(argv[1]) should be strlen(argv[1])+1.
I think the same thing is happening in the loop, and it should be larger by 1. And sizeof(char) is always 1 by definition, so:
...
words=realloc(words,i+2);
}
words=realloc(words,i+2); // one more time to make room for the '\0'
words[strlen(ptr->words)]='\0';
FYI: Your description talks about structptr but your code uses struct StructHolder and Holder.
This code is a disaster:
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
It should be:
char *GetCharacters(const Holder *ptr)
{
char *words = malloc(strlen(ptr->words) + 1);
if (words != 0)
strcpy(words, ptr->words);
return words;
}
Or even:
char *GetCharacters(const Holder *ptr)
{
return strdup(ptr->words);
}
And all of those accept that passing the structure type makes sense; there's no obvious reason why you don't just pass the const char *words instead.
Dissecting the 'disaster' (and ignoring the argument type):
char *GetCharacters(Holder *ptr){
int i=0;
OK so far, though you're not going to change the structure so it could be a const Holder *ptr argument.
char *words=malloc(sizeof(char));
Allocating one byte is expensive — more costly than calling strlen(). This is not a good start, though of itself, it is not wrong. You do not, however, check that the memory allocation succeeded. That is a mistake.
for(i;i<strlen(ptr->words);i++){
The i; first term is plain weird. You could write for (i = 0; ... (and possibly omit the initializer in the definition of i, or you could write for (int i = 0; ....
Using strlen() repeatedly in a loop like that is bad news too. You should be using:
int len = strlen(ptr->words);
for (i = 0; i < len; i++)
Next:
words[i]=ptr->words[i];
This assignment is not a problem.
words=realloc(words,sizeof(char)+i);
This realloc() assignment is a problem. If you get back a null pointer, you've lost the only reference to the previously allocated memory. You need, therefore, to save the return value separately, test it, and only assign if successful:
void *space = realloc(words, i + 2); // When i = 0, allocate 2 bytes.
if (space == 0)
break;
words = space;
This would be better/safer. It isn't completely clean; it might be better to replace break; with { free(words); return 0; } to do an early exit. But this whole business of allocating one byte at a time is not the right way to do it. You should work out how much space to allocate, then allocate it all at once.
}
words[strlen(ptr->words)]='\0';
You could avoid recalculating the length by using i instead of strlen(ptr->words). This would have the side benefit of being correct if the if (space == 0) break; was executed.
return words;
}
The rest of this function is OK.
I haven't spent time analyzing main(); it is not, however, problem-free.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 1;
char* test[8];
sprintf(test[0],"%d",num);
printf("%s\n",test[0]);
}
char *test[8] is an array of 8 char *, or pointers to strings, and since you don't specify, they're all set to garbage values. So sprintf is trying to write data to who-knows-where.
You should use char test[8] instead, which allocates an array of 8 char, and then sprintf(test, "%d", num);.
UPDATE: If you want to use char * pointers, you should allocate space:
char *test = malloc(8 /* see note below */);
sprintf(test, "%d", num);
If you want to use an array of char * pointers, it works the same:
char *test[8]; // 8 pointers to strings
test[0] = malloc(8); // allocate memory for the first pointer
sprintf(test[0], "%d", num);
Keep in mind you would have to call malloc for each of test[0] through test[7] individually.
Also, as mentioned in the comments, if your compiler supports it you should use snprintf(). It's like sprintf but it takes an extra parameter which is the size of the buffer:
snprintf(test, 8, "%d", num);
and guarantees not to use more space than you allow it. It's safer, and if you need to, snprintf returns the amount of space it actually wanted, so if you gave it too little room you can realloc and try again.
Note: some will say this should be malloc(8 * sizeof(char)) (or sizeof *test). They are wrong (in my objectively-correct opinion; note the sarcasm)! sizeof(char) is guaranteed to be 1, so this multiplication is unnecessary.
Some advocate the usage of TYPE *p = malloc(x * sizeof *p) so that if TYPE changes, you'll only need to change it in one place, and sizeof *p will adapt. I am one of these people, but in my opinion you will rarely need to upgrade a char * to another type. Since so many functions use char * and would need to be changed in such an upgrade, I'm not worried about making malloc lines more flexible.
sprintf() does not allocate space for the string; you must do that yourself beforehand.
Look at your warnings:
test.c: In function ‘main’:
test.c:8: warning: ‘test[0]’ is used uninitialized in this function
You allocate an array of 8 pointers, but use one without initializing it. You must call malloc and store the result in test[0] before you can write to the memory pointed to by test[0]. You free it at the end.
A useful function, present in GNU and BSD, is asprintf, which will call malloc for you to allocate enough memory for the formatted string:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int num = 1;
char* test[8];
asprintf(&test[0],"%d",num);
printf("%s\n",test[0]);
free(test[0]);
return 0;
}
(Note that you pass the address of your pointer to asprintf — since your pointer is test[0], its address is &test[0].)
You did allocate space but you you are passing the wrong thing. Try this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 1;
char test[8];
sprintf(test,"%d",num);
printf("%s\n",test);
}
int main()
{
char *str[5];
sprintf(str[0], "%d",55);
printf("%s\n",str[0]);
return 0;
}
This will be work. But, if you specify variable instead of integer constant value show the segmentation fault will be occur. This error will be happened at the time of sprintf function execution. Because user space memory access.