i use pointer for holding name and research lab property. But when i print the existing Vertex ,when i print the vertex, i cant see so -called attributes properly.
For example though real value of name is "lancelot" , i see it as wrong such as "asdasdasdasd"
struct vertex {
int value;
char*name;
char* researchLab;
struct vertex *next;
struct edge *list;
};
void GRAPHinsertV(Graph G, int value,char*name,char*researchLab) {
//create new Vertex.
Vertex newV = malloc(sizeof newV);
// set value of new variable to which belongs the person.
newV->value = value;
newV->name=name;
newV->researchLab=researchLab;
newV->next = G->head;
newV->list = NULL;
G->head = newV;
G->V++;
}
/***
The method creates new person.
**/
void createNewPerson(Graph G) {
int id;
char name[30];
char researchLab[30];
// get requeired variables.
printf("Enter id of the person to be added.\n");
scanf("%d",&id);
printf("Enter name of the person to be added.\n");
scanf("%s",name);
printf("Enter researc lab of the person to be added\n");
scanf("%s",researchLab);
// insert the people to the social network.
GRAPHinsertV(G,id,name,researchLab);
}
void ListAllPeople(Graph G)
{
Vertex tmp;
Edge list;
for(tmp = G->head;tmp!=NULL;tmp=tmp->next)
{
fprintf(stdout,"V:%d\t%s\t%s\n",tmp->value,tmp->name,tmp->researchLab);
}
system("pause");
}
When you do this:
newV->name=name;
newV->researchLab=researchLab;
You are copying the pointer to the strings name and researchLab. You are not copying the strings themselves. In other words, after this, newV->name and name point to exactly the same location in memory where the name is stored; you have not created a duplicate copy of the data.
Since you then proceed to overwrite the name array in the createNewPerson function, at the end of this function, all of your vertex structs will have their name attribute pointing to the same memory location, which is only storing the last name entered.
Worse, when createNewPerson returns, its local name array goes out of scope, and is re-used for other things. Since your vertex structs are still pointing here for their name attributes, this is how you get garbage.
You need to duplicate the string. A simple way to do it is:
newV->name = strdup(name);
You will need to #include <string.h> to get the strdup library function.
And then you also need to make sure that you call free on the name attribute whenever you are disposing of a vertex structure.
GRAPHinsertV copies the pointer of the name and researchLab strings to the vector structure.
createNewPerson creates a temporary for the name and researchLab strings.
The problem here is, you're pointing to a temporary string which causes undefined behaviour when you access it after createNewPerson returns.
To solve this problem, you can duplicate the strings in GRAPHinsertV using malloc+strcpy, or by using the non-standard strdup.
The name variable you pass to GRAPHinsertV() is allocated on the stack for createNewPerson(), so the pointer points to a local variable. Once the activations records are popped off that value can (and will) be overwritten by subsequent code.
You need to allocate memory on the heap if you are only going to keep a char * in the struct.
Ex. Instead of
char name[30];
you could use
char *name = (char *)malloc(30*sizeof(char));
but keep in mind if you manually allocate it you have to take care of freeing it as well, otherwise it will have a memory leak.
When you assign the char *name pointer, like
newV->name=name;
You're not creating a new string, but making the newV.name member point to the same memory as the char[] array that was passed in. You'll need to malloc() or otherwise allocate a new char[] array in order to obtain separate storage for each structure.
There's a problem here:
Vertex newV = malloc(sizeof newV);
It should be
Vertex *newV = malloc(sizeof(Vertex));
You are allocating memory in the function createNewPerson() that lasts exactly as long as createNewPerson() is executing, and is available for overwriting immediately after it returns. You need to copy the text fields in with something like strdup(newV->name, name), rather than point to the local variables in createNewPerson(). (If your implementation doesn't have strdup(), you can easily define it as:
char * strdup(const char *inp)
{
char * s = malloc(strlen(inp) + 1);
strcpy(s, inp);
return s;
}
In addition, your I/O has potential problems. If you enter my name, "David Thornley", for the name, it'll take "David" as the name and "Thornley" as the lab, since "%s" searches for a whitespace-delimited string. If I enter "Forty-two" for the ID, nothing will be put in id, and "Forty-two" will be used for the name. If I enter a name or lab name over 29 characters, it will overwrite other memory.
I'd suggest using fgets() to get one line of input per answer, then use sscanf() to parse it.
When passing and assigning strings, always make a copy of them. There're no guarantees that the string you received is still in the memory afterwards, since the pointer could have been freed.
Of course, if you are only going to use name inside the function (that's, you're not going to assign it to a variable outside the scope of the function), you don't have to do the copy.
In order to do that, inside GRAPHinsertV, instead of
newV->name=name;
do
if (name != NULL) // Preventing using null pointer
{
newV->name = malloc(strlen(name)+1);
strcpy(newV->name, name);
}
Related
I need to make a program for bakery managment, I've done structures and three pointer arrays that must contain pointers for object of these structures. But i can't make function to add new bakery because it needs dynamic memory allocating. I've tried to do this but it throws Segmentation Fault on realloc. I would be grateful for any advice how to properly reallocate memory for these arrays to add element. Also feel free to make comments about other errors in the code, I'm just learning.
typedef struct BakeryType {
char *name;
} BakeType;
typedef struct Bakerys {
char *name;
BakeType *type;
char *photo;
float weight;
int portions;
float price;
char *description;
} Bakery;
Bakery *bakeryList[0];
BakeType *bakeTypeList[0];
void addBakery() {
Bakery new;
*bakeryList = realloc(*bakeryList, (sizeof(bakeryList)/ sizeof(Bakery))+ 1);//Segmentation Fault
bakeryList[sizeof(bakeryList)/sizeof(Bakery)]=&new;
}
bakeryList is a zero-element array of pointers to Bakery. It has room for zero pointers.
Yet later you set the first element of this array (*bakeryList which is the same as bakeryList[0]) to whatever comes back from realloc. So you're overwriting something, and it probably goes downhill from there.
I think you want bakeryList to just be a pointer to Bakery. That's how dynamically-allocated arrays work in C: you define a pointer to the first element and use pointer math (e.g., bakeryList[5] or *(bakeryList + 5)) to access other elements.
Another issue is your use of sizeof(bakeryList). sizeof is an operator that's evaluated by the compiler. It doesn't change at runtime. sizeof(bakeryList) / sizeof(Bakery) will evaluate to zero because you defined bakeryList as a zero-element array. You need another variable to keep track of how many elements are actually in the array at runtime.
Something like this would work:
int bakeryCount = 0;
Bakery *bakeryList = NULL;
void addBakery() {
// Add one to the array.
bakeryCount++;
bakeryList = realloc(bakeryList, bakeryCount * sizeof (Bakery));
// Create a pointer to the new element at the end of the array.
Bakery *newBakery = bakeryList + bakeryCount - 1;
// Set all the fields. Note that they will probably contain
// garbage so you should set them all.
newBakery->name = ...
}
I have typdef of string in my C program, it looks like that:
#define WRD_LEN 100
typedef char cstring[WRD_LEN];
then at some point I declare dynamic array of this type:
int pcount = 1;
cstring *options = malloc(sizeof(cstring*)*pcount);
I add new strings to this array with use of realloc:
options = realloc(options, sizeof(cstring*)*pcount);
strcpy(options[pcount-1], //some string//);
pcount++;
and then show all entries to user, user choses one of them and that one is passed to another function:
highestof(mode, l, options[btn]);
mode is an integer, l is struct but those are irrelevant now. btn is number (int) of entry chosed by user.
Up to this point everything works just fine, problem shows up inside highestof function:
void highestof(const int mode, List l, const cstring cat) {
List *p = malloc(sizeof(List*));
here is definition of List:
struct W {
//some data
struct W *next;
};
struct List {
struct W *first;
};
So if highestof function is called with options[1], cat variable will get corrupted (it will became a set of few random symbols, like "#^?" or "^K^?") right after malloc is called i.e. before creating dynamic array of List I can use cat as much as I want, but after calling malloc it gets corrupted. Most strange thing about this is that it happens only if variable passed down to this function was in options array under index of 1 (options[btn] where btn = 1) For any other value of btn it works no problem.
I found a workaround for this, I can create a string (char s[100]) before calling malloc, copy cat value into it and use that variable instead, but it's really not resolving initial problem and it really bothers me.
sizeof(cstring*)*pcount is too small. The size calculation is amiss.
Avoid allocation errors. Use this idiom for code that is easier to write correctly, review and maintain.
Notice no type is used.
pointer = malloc(sizeof *pointer * n);
Then code becomes:
// options = malloc(sizeof(cstring*)*pcount);
options = malloc(sizeof *options * pcount);`
cstring* is just a pointer, usually four or eight bytes. sizeof (cstring*) is therefore a small number, usually four or eight.
You are not allocating enough memory for the data, just enough memory to hold pointers to the data.
It is possible to declare a string of the required size using char name[size], however if I want to use char *name, how will I specify the size that I require using malloc()?
I found out that I cannot use char *name = malloc(5*1); within the structure declaration.
I have tried using
struct data
{
int age;
char *name;
};
On running this code and entering the string I encountered Segmentation fault.
How must I specify the size?
You need to specify the size of the pointer, you need to make the pointer to point to a valid memory, that's all. Moreover, it not necessary to use malloc(). You can either
allocate memory to the pointer via allocator functions, malloc() or family
make the pointer point to the address of any other char variable (or array)
To elaborate, you create a variable var of type struct data, and then, make var->name point to a valid chunk of memory.
That said, to use malloc() for allocating required size of memory, you need to supply the required size as the argument to malloc() (in bytes).
let's say you create a variable a of the type struct data
struct data a;
Now allocate memory to the name member of a i.e,
a.name = malloc(size_of_name + 1); //+1 for '\0' character at the end
Now you can use a.name to store and use the string
Don't forget to free the allocated data before terminating the program. for this use free(a.name).
You need to allocate the memory like:
data* r = malloc(sizeof(data));
r->name= malloc(20);
assuming the name can hold 20 chars
You'd need to supply a way to initialize your structure. For example:
void init_data (struct data *p_data) {
if (p_data)
p_data->name = malloc(STR_LEN);
}
And you should couple that with a function to free the memory:
void release_data (struct data *p_data) {
if (p_data)
free(p_data->name);
}
It would than be called whenever you want to use your structure.
struct data d;
init_data(&d);
/* use d */
release_data(&d);
Okay so that wasn't very clear. What I am trying to do is this:
while (//something) {
char * tempuser;
char * users[100];
tempuser = "bobsmith" //I'm not actually doing this. But using a method that does the same thing
users[i] = tempuser;
}
Where "bobsmith" is is different everytime through the loop. If I run this, as is, 5 times and the last entry is "janetsmith" all 5 places in the array before that, regardless of being different when assigned, all end up as "janetsmith". How should I assign users[i] so that it has a different value in all indexes?
Do not create the array users in loop body, and use strdup to create new string with the same content inside the array. Remember that You are using pointers not some kind of string objects. Each entry in array holds the address of the text inside memory.
char *users[100]={0}; //one hundred pointers that are null so You don't use a wild one.
int i=0;
while(/*whatever*/) {
char *tmp=getsometext(); //returns char pointer
users[i++]=strdup(tmp); //copies contents pointed by tmp into new memory location and returns its address
}
//don't forget to free every pointer when You are done.
It is because you are assigning address of the variable tempuser. By the end of it all, it will always hold the address of "janetsmith". Try creating the variable dynamically using malloc() function.
char * users[100]; //with this you can use it outside while
while (//something) {
static unsigned int i = 0;
//char * tempuser;
//tempuser = "bobsmith" //I'm not actually doing this. But using a method that does the same thing
users[i] = method_which_return_char_pointer();
i++;
if( 100 <= i)
i=0;
}
this what from your brief Question explanation .
typedef struct unit_class_struct {
char *name;
char *last_name;
} person;
int setName(person *array) {
array[0].name = strdup("Bob");
array[1].name = strdup("Dick");
return 1;
}
int setLastName(person *array) {
array->last_name = strdup("Sanchez");
array++;
array->last_name = strdup("Clark");
return 1;
}
int main()
{
person array[10];
person *pointer;
pointer = array;
setName(pointer);
setLastName(pointer);
printf("First name is %s %s\n", array[0].name, array[0].last_name);
printf("Second name is %s %s\n", array[1].name, array[1].last_name);
while(1) {}
return 0;
}
This is some example code I came up with to play around with structures.
Notice the way I set the name in setName and the way I did it in setLastName.
Both work, but I'm curious whats the difference between the two ways I did it?
Is one way better than the other?
Also is strdup necessary in this example? If not, would it be necessary if I was setting array.name to random sized variables rather than string literals?
If you set all your .name's to string constants, then no, strdup is not strictly needed. You'll want it if you're going to modify the string later. A better grounding in pointer's and memory management will make the distinction clear. If you do use strdup, be sure to free the result later.
Both options are quite risky, because you donĀ“t know the length of the array. Consequently, accessing the result of array++ or array[1] could result in undefined behaviour.
Perhaps you could try this apprach
int set_last_name(person* array, char* lastnames[],size_t amount){
int i=0;
for(;i<amount;i++,array++){
strncpy(array->lastname,lastnames[i],strlen(lastnames[i]));
}
return 1;
}
where amount is the length of the lastnames array.
Note that theres no usage of strdup. This function would expect the user to allocate memory for lastnames and array. Then the user should free that memory , if needed.
I dislike strdup because it returns a heap allocated string, and in the case of your functions, it should be clearly documented that the user of the functions has to free it.
Using the indexed approach is slightly clearer than using the pointer arithmetic, in my opinion but either works. I suspect the code the compiler generates for each is quite similar in both instances.
strdup is necessary in this instance if you're working with variables because you do not allocate memory to save your string values in in the person struct. If you'd already allocated space for those strings when either of your setters was called, strcpy (strcpy_s, preferably) would be sufficient.
When working with literals as you are in your example, strdup is not necessary: you can assign directly to the char*.
array->name is exactly the same as (*array).name.
In both your functions "array" is a pointer to a structure, so both *array and array[0] are structures, and you can set their members. The arrow notation is just a often used shortcut.