Here is the struct that I am using.
#define MAX_CAR_LEN 12 ///< length does not include the trailing NUL byte
/// Racer_S structure represents a racer's row, position and display graphic.
typedef struct Racer_S {
int row; ///< vertical row or "racing lane" of a racer
int distance; ///< column of rear of car, marking its position in race
char *graphic; ///< graphic is the drawable text of the racer figure
} Racer;
When I call this function everything works fine inside it and creates everything correctly. I am able to access the row and distance fine. When I try and print the graphic I am printed an empty row in my terminal. I believe that this might be because "graphic" in the struct is a char* but I assign it a fixed sized array of char. When this function is called and passed in the name "Tom", graphic is supposed to be "~O=Tom----o>". I am new to C what am I doing wrong?
Racer * make_racer( char *name, int row ){
//Creating a newRacer instance
Racer *newRacer = malloc(sizeof(*newRacer));
newRacer->graphic = (char*)malloc(MAX_CAR_LEN);
char car[MAX_CAR_LEN] = "~O="; //"~O=-------o>"
char *pCar;
int length = strlen(name) + 2;
//Add the name after the engine of the car
for (int i = 0; i < length; ++i)
car[i+3] = name[i];
//Calculate the amount of dashes needed
int printDashes = 7 - strlen(name);
//add the extra dashes
for (int j = 1; j <= printDashes; ++j)
car[length + j] = '-';
// creates the end of the car
car[MAX_CAR_LEN-2] = 'o';
car[MAX_CAR_LEN-1] = '>';
pCar = strdup(car);
newRacer->row = row;
newRacer->distance = 0;
newRacer->graphic = &car[0];
// printf("%s\n", car);
return newRacer;
}
This is the code I am running in my main to test it
Racer *t = make_racer("Tom", 4);
printf("%s\n", t->graphic);
You have mentioned the below statement in your question.
This is the code I am running in my main to test it
acer *t = make_racer("Tom", 4);
printf("%s\n", t->graphic);
In make_racer function you have used a local charecter array variable called car and assigned the address to newRacer->graphic . This variable(char car[MAX_CAR_LEN+1] ;) memory goes out of scope after returning from the function.
Please refer this thread to understand more about the local scope in C.
Now to resolve your problem, In make_racer function you have to dynamically allocate memory for newRacer->graphic as well.
Racer * make_racer( char *name, int row ){
:
Racer *newRacer = malloc(sizeof(*newRacer));
newRacer->graphic = (char*)malloc(MAX_CAR_LEN+1);
:
//newRacer->graphic = &car[0]; # this is wrong.
strcpy(newRacer->graphic,car); //copy the content to allocated memory.
/*
* Warning:Just i am pointing out the issue here.
* strcpy may cause buffer over run.
* You have to use snprintf/strncpy family to prevent buffer overrun.
*/
}
Make sure you free the memory in your main.
int main() {
:
free(newRacer->graphic); //before free the momory for "newRacer"
free(newRacer);
}
Related
I am having a hard time getting an array of pointer to structures to save and retrieve the data I filled, the code snippet has the core of my program.
I was able to make the program itself work using an array of struct, but I figure that is more memory intensive and I am trying to only realloc the array of pointers to the structures instead of all the structs at each loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dados_aluno {
int matricula;
char nome[60];
int situacao;
float nota1, nota2, nota3, media;
}dados_aluno;
int main(void){
int done = 0;
int i;
int n_alunos = 0;
int matricula_atual;
dados_aluno *novo_aluno;
dados_aluno **alunos_da_turma;
alunos_da_turma = malloc(sizeof(dados_aluno*));
while (done == 0){
printf("Matricula: ");
scanf("%d", &matricula_atual);
fflush(stdin);//scanf followed by gets = bad time!
if (matricula_atual == -1){
done = 1;
continue;
}
n_alunos++;
novo_aluno = calloc(1, sizeof(dados_aluno));
novo_aluno->matricula = matricula_atual;
printf("\nNome: ");
gets(novo_aluno->nome);
//the code below rises warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
//and returns garbage on the for loop at the end of the program
alunos_da_turma[n_alunos - 1] = &novo_aluno;
//using memcpy instead doesnt rise an error, but the first field is garbage and the 3ยบ interation of the loop crashes
//memcpy(alunos_da_turma[n_alunos -1],&novo_aluno,sizeof(dados_aluno *));
alunos_da_turma = realloc(alunos_da_turma, (sizeof(dados_aluno *) * (n_alunos + 1)));
}
for (i=0;i<(n_alunos);i++){
printf("%d %s\n",alunos_da_turma[i]->matricula,alunos_da_turma[i]->nome);
}
}
I expect to dynamic allocate a struct "dados_alunos" and also dynamic allocate an array of pointers to said structs, insert user input "nome" and "matricula_atual" to the fields of the struct "dados_alunos" and be able to read them after exiting the while loop.
On trying to save the address to the current struct to the array using
alunos_da_turma[n_alunos - 1] = &novo_aluno;
gives the warning "assignment from incompatible pointer type [-Wincompatible-pointer-types]" and seems to save to all the positions of the array the first pointer/garbage written to it no matter how many interactions.
Using memcpy instead store garbage on the first field if I only try one interaction and crashes within 2 interactions or more on the while loop.
alunos_da_turma[n_alunos - 1] = &novo_aluno;
is refused because alunos_da_turma is a dados_aluno ** so alunos_da_turma[n_alunos - 1] is a dados_aluno *, but novo_aluno is a dados_aluno * so &novo_aluno is a dados_aluno **
you wanted
alunos_da_turma[n_alunos - 1] = novo_aluno;
Warning
gets(novo_aluno->nome);
is dangerous (and deprecated since years) because if the input string is greater than 59 characters you write out of the field with an unexpected behavior, do
fgets(novo_aluno->nome, sizeof(novo_aluno->nome), stdin);
However except if you enter the name on the same line you enter the matricula you will get an empty line because the rest of the line/newline is not flush by fflush(stdin);, fflush does not work out of a file
If the name cannot contain separator use scanf("%59s", novo_aluno->nome); rather than fgets, else bypass characters up to the newline explicitely
Note also in
alunos_da_turma = realloc(alunos_da_turma, (sizeof(dados_aluno *) * (n_alunos + 1)));
you reallocate with one extra element, you already increased n_alunos
Doing
int done = 0;
...
while (done == 0){
...
if (matricula_atual == -1){
done = 1;
continue;
}
...
}
is quite complicated for nothing and can be replaced by
for (;;) {
...
if (matricula_atual == -1)
break;
...
}
alunos_da_turma[X] is a pointer to struct dados_aluno, not a pointer to a pointer to a struct dados_aluno.
What would be valid is alunos_da_turma[n_alunos-1] = novo_aluno
So, some solution for general problem:
dados_alunos** alunos_da_turma = malloc (10 * sizeof(dados_aluno*)); //array for 10 pointers
int length = 0; //number of inserted alunos_dados elements
int size = 10; //number of allocated pointers spaces
while(done == 0){
//ask for input
dados_aluno* novo_aluno = malloc (sizeof(dados_aluno));
novo_aluno->matricula = //input
//etc
dados_alunos[length] = novo_aluno;
length++;
if (length == size){
dados_alunos = realloc(dados_alunos, 2 * size * sizeof(dados_aluno*));
size += size; //doubles size
}
}
I have a major issue that is happening to my code, that I've been trying to fix for hours now.
The code below is the one relevant to the issue that I am having...
The method addBucket:
void addBucket(SPACE * hashmap,char * tempvalue, char * tempkey){
printf("BEGINNING OF FUNC...\n");
void *prevadd = hashmap[0];
char *value = varString(tempvalue);
char *key = varString(tempkey);
void *aftadd = hashmap[0];
printf("BUCKET %s - %s\n",value,key);
BUCKET *newBucket = malloc(sizeof(BUCKET *));
fillBucket(value,key,newBucket);
int hash = hashFunc(key);
printf("FILL, FULFILLED\n");
if(!hashmap[hash]){
hashmap[hash] = malloc(sizeof(BASE*));
hashmap[hash]->first = NULL;
}
ITEM *location;
location = hashmap[hash]->first;
//This creates a new item in the list, if there isn't any.
//It does this by initialising the base, called box.
if(!location){
hashmap[hash]->first = (ITEM *) calloc(1,sizeof(ITEM *));
hashmap[hash]->first->next = NULL;
hashmap[hash]->first->prev = NULL;
hashmap[hash]->first->data = newBucket;
}
//This instead adds a new item to the list.
else{
//This loop reaches the last ITEM in the linked list itself
while(location->next){
location = location->next;
}
//This initialises the newItem that will be added
ITEM *newItem = (ITEM *) calloc(1,sizeof(ITEM));
newItem->next = NULL;
newItem->data = newBucket;
newItem->prev = location;
location->next = newItem;
}
}
The declared structs that are used:
//Declares a struct called BUCKET.
//Serves as the bucket of the hash table.
typedef struct bucket{
char * value; //The value inputted.
char * key; //The key to be hashed.
}BUCKET;
//Declares a struct called ITEM.
//Holds the bucket, as well as the address to the next bucket.
//It also holds the address to the previous bucket.
typedef struct item{
struct bucket * data;
struct item * next;
struct item * prev;
}ITEM;
//Declares a struct called BASE.
//Serves as the base node for the linked lists.
//The amount of initialised linked lists is the same as the amount of bases.
typedef struct base{
struct item * first;
}BASE;
//Declares a struct of an array of BASES, meaning linked lists.
//Essentially defines the size of the hashspace.
typedef BASE *SPACE;
...And the method expandHashspace(); :
//Makes the size of the entire hashspace larger.
//Only takes a value larger than the current size due to possible data loss.
SPACE* expandHashspace(SPACE *hashmap, int newSize){
if(newSize>100 || newSize<hashSpaceSize){
printf("Exiting...\n");
return NULL;
}
else {
SPACE *nw = NULL;
nw = realloc(hashmap, sizeof(SPACE *) * newSize);
hashmap = nw;
hashSpaceSize = newSize;
return hashmap;
}
}
Here's also the initHashmap() method:
SPACE* hashmapInit(SPACE *hashmap){
hashmap = calloc(5, sizeof(SPACE *));
hashSpaceSize = 5;
return hashmap;
}
What I am doing here is initialising the hashmap, adding three buckets, expanding the hashmap, then adding three more buckets. Here's the order in more simple terms:
initHashmap();
addBucket(...); x3
expandHashmap();
addBucket(...); x3
However, on that last part, as soon as I run addBucket once, I get a SIGSEGV error. Checking through debugging, I realised something that was off.
Do you see the variables *prevadd and *aftadd? I added them while debugging to see what was happening to the address of hashmap[0]. Here is a picture of my results:
As you can see there, the address of hashmap[0] varied wildly during those two char * lines. Specifically, the change of address happens on the char *value line.
Please go easy on me, as I've just started learning C 3 months ago, and I am still incredibly unaccustomed to memory allocation. If the error is obvious, please point it out, and if I have some problem with the way that I am allocating memory, or freeing it, I am more than happy to hear them (my code has a pretty major heisenbug that I cannot fix for the life of me, but that's beside the point).
Thank you in advance... Sorry for all the recent questions.
update : forgot to add varString();...
char* varString(const char *origString){
size_t i;
for(i = 0;origString[(int)i]!='\0';i++){}
if(origString[i-1]=='\n') i-=2;
char *newString = malloc(i);
for(int j = 0; j <= i; j++){
newString[j] = origString[j];
}
newString[i+1] = '\0';
return newString;
}
This is not an answer, but it needed more formatting than would fit in a comment:
Note that you are writing "Value No. 1"
Note the value of aftadd is 0x756c6156
In memory, assuming a little-endian machine, the layout of the number in aftadd would be:
0x56 0x61 0x6c 0x75
In ASCII these would be:
'V' 'a' 'l' 'u'
Hint hint.
I am working on a programming assignment in C, which is about creating basic automation for cinema halls.
For holding data of halls, I define a structure like this:
typedef struct {
char *hallName;
char *movieName;
seat** hallSeats;
int studentCount;
int fullFareCount;
int totalSum;
int width;
int height;
}Hall;
So I am given a text file with commands and whenever I came up with a specific command, I should create a separate hall. For that reason, I created another function for that.
Hall makeHall(char **temp) //TEMP HOLDING THE LINES FROM FILE
{
int width = strToInt(temp[3]);
int height = strToInt(temp[4]);
char currentRowLetter = 'A';
int currentRow;
int currentSeat;
seat **hall = malloc(sizeof(seat*) * width );
for (currentRow=0 ; currentRow < width ; currentRow++)
{
hall[currentRow] = malloc(sizeof(seat) * height );
for(currentSeat=0; currentSeat < height ; currentSeat++)
{
hall[currentRow][currentSeat].rowLetter = currentRowLetter;
hall[currentRow][currentSeat].seatNumber = currentSeat + 1;
hall[currentRow][currentSeat].seatTaken = ' ';
}
++currentRowLetter;
}
Hall newHall;
newHall.hallName = temp[1];
newHall.movieName = temp[2];
newHall.hallSeats = hall;
newHall.width = width;
newHall.height = height;
return newHall;
}
Since I will have multiple halls, I created a Hall array in order to access them later.
Hall *allHalls = malloc(sizeof(Hall) * 10); /*Hall placeholder*/
While I iterate over the lines, I check commands and create halls or sell tickets.
Hall *allHalls = malloc(sizeof(Hall) * 10); /*Hall placeholder*/
FILE *f;
f = fopen("input.txt", "rt");
char *line = malloc (sizeof(char) * 200); /*LINE HOLDER*/
int currentLineNumber = 0;
char *tmp;
int hallNumber = 0;
while (1) { /*PARSING FILE*/
if (fgets(line,200, f) == NULL) break; /*FILE END CHECKER*/
currentLineNumber++;
tmp = strtok(line," ");
char **temp = malloc(sizeof(char*) * 6);
int currentWordNumber = 0;
while(tmp != NULL) /*PARSING LINES*/
{
temp[currentWordNumber] = malloc(strlen(tmp) + 1);
strcpy(temp[currentWordNumber],tmp);
tmp = strtok (NULL, " ");
currentWordNumber++;
}
if(!strcmp("CREATEHALL",temp[0]))
{
allHalls[hallNumber] = makeHall(temp); /*<<<<<<<PROBLEM*/
hallNumber++;
printf("%d\n",hallNumber);
}
Now that's the part I am lost at. Whenever I tried to access the array, the program crashes.
I thought it was a memory problem, so increased memory allocated by malloc for allHalls to 40 (even though it should not be a problem, since file only gives 3 different halls) and program no longer crashes, but instead overwrites the previous hall in the array.
I tried multiple solutions but none of them came out any good, so closest I get is this.
I did use java a lot before, so I am still stuck to OOP and pretty new to C.
EDIT
Seat is defined as
typedef struct {
char rowLetter;
int seatNumber;
char seatTaken;
}seat;
also example createhall command is
CREATEHALL Hall_A Avatar 24 20
while the numbers at the end being width and height for hall
EDIT : CODE
I got the bug:
At the bottom of the while(1) loop in main you do a free(allHalls); so now there are no more halls and you get a segfault...
It was in the code you didn't show us:
while (1) {
...
if(!strcmp("CREATEHALL",temp[0]))
{
allHalls[hallNumber] = makeHall(temp); /*<<<<<<<PROBLEM*/
hallNumber++;
printf("%d\n",hallNumber);
}
....
free(temp);
free(allHalls); // <-- there's your bug
}
fclose(f);
free(line);
So... in the past I've been told that my questions aren't good... I believe mostly because I haven't isolated out problematic code well enough. I'll do my best to ask a pointed, concise, and to the point question in this post. I'm certainly open to suggestions about how my question could be asked better.
Thanks.
I'm working on a small project in C that will serve as a prototype for a larger, buggy program that I've been working on for some time. I'm trying to work out the details in a smaller program first. I have two structs:
struct list
{
char ownerName[20];
int ownerAge;
char sex;
}owner;
and
struct list2
{
char petName[20];
char owner[20];
char animal[4];
char breed[50];
char color[20];
}pets;
The program is supposed to fgets ownerName from user input and compare it to ".owner" in the pets struct. The ownerName and petName elements should then be copied into an array, and the name of the owner and his/her pets will be printed in a list. While I'm aware I don't need the owner struct to accomplish this, I'm using it to model the other program I'm writing.
I'm using
if (strcmp(pets[i].owner, name) == 0)
to compare the struct elements and seem to have this part down.
The variable j counts the number of records that meet this criteria, and the variable l = j + 1. I call the array using:
char *petsList[l];
The size of the array is dictated by l (j + 1) because I need j elements for the petNames + 1 element for the owner name.
I've also created a pointer to the petsList array via the following:
char *(*ptr)[l] = &petsList
The owner name is added to the array via the following command:
(*ptr)[0] = (char *)malloc(sizeof(name));
strcpy ( (*ptr)[0], name);
The petNames are added to the the array petsList using a for loop. I've initialized i = 1 to prevent petsList[0] from being overwritten and am trying to write petNames to the array via the following loop:
i = 1;
for (k=0; k < PETS; k++)
{
if (strcmp(pets[k].owner, name) == 0)
{
(*ptr)[i] = (char *)malloc(sizeof(pets[k].petName));
if (!*(ptr)[i])
{
puts("\nMemory Allocation Error");
exit (1);
}
strcpy( (*ptr)[i], pets[k].petName);
i++;
}
}
Let's say for a given input of name, I get three pets that match. The loop iterates the first two times just fine, but then on the third iteration of the loop, I get a memory allocation error. This happens on the last iteration of the loop consistently. For example, if I have 2 pets associated with the ownerName, the list will run the first iteration fine and fail on the second; if I have 4 pets associated with the ownerName, the loop will run fine the first 3 times and fail on the fourth, so it appears that the final iteration of the loop consistently fails. I've tried changing the code a number of times, but am now at a loss for how I can move forward with this program. Any help is greatly appreciated.
Thanks.
Don`t cast the malloc return value.
Since I can`t really check with a minimal example.
char *(*ptr)[l] = &petsList
why do you make such a complex construct? I am not even sure what it is supposed to accomplish. do you want all pets in the first index and the next index to contain the owner? this could be accomplished just with the petslist
what structure do you really need at the end?
is it something like:
array:
0 = owner
1 = pet 1
2 = pet 2
or something like
0,0 = owner 1,0 = owner 2 etc.
0,1 = pet 1 1,1 = pet 3
0,2 = pet 2 1,2 = pet 4
Ok here is a working example of what you want to do. you can easily extend it to do the second data arrangement. If you have any questions feel free to ask
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PETAMOUNT 40
struct list2
{
char petName[20];
char owner[20];
char animal[4];
char breed[50];
char color[20];
};
int main() {
struct list2 *pets; // list of all pets
char name[128]; // contain name of the owner, get from stdin
unsigned int i; // i and j are both counter variable
unsigned int j;
fgets(name, 128, stdin); // get string from stdin
name[strlen(name) - 1] = '\0'; // remove newline
pets = malloc(PETAMOUNT * sizeof(struct list2)); // allocate memory for the list of all pets
if (pets == NULL) {
printf("malloc err\n");
exit(1);
}
for (i = 0; i < PETAMOUNT; i++) { // initialize some pets and some owners
strcpy(pets[i].petName, "petname ");
strcpy(pets[i].owner, "owner ");
pets[i].petName[7] = i + '0'; // there are PETAMOUNT of petnames. petname0, petname1 etc
pets[i].owner[5] = (i / 4) + '0'; // there are PETAMOUNT / 4 owners. owner0 has petname0 to petname3, owner1 has petname4 to 7 etc
}
char ***petslist; // a list of list of strings or 3d char array
petslist = malloc(sizeof(char **)); // allocate pointer to contain a double array
petslist[0] = malloc(sizeof(char *)); // allocate a pointer to contain the name of the owner
if (petslist[0] == NULL) {
printf("malloc err\n");
exit(1);
}
petslist[0][0] = malloc(strlen(name) + 1); // allocate memory to contain the owner
if (petslist[0][0] == NULL) {
printf("malloc err\n");
exit(1);
}
strcpy(petslist[0][0], name); // copy owner into the first index
for (i = 0, j = 1; i < PETAMOUNT; i++) { // go through all pets
if (strcmp(pets[i].owner, name) == 0) { // if the owner of the current pet is the same as the inputted owner
petslist[0] = realloc(petslist[0], (j + 1) * sizeof(char *)); // allocate pointer for the next pet
petslist[0][j] = malloc(strlen(pets[i].petName) + 1); // allocate memory to contain the chars of the pet
if (petslist[0][j] == NULL) {
printf("malloc err\n");
exit(1);
}
strcpy(petslist[0][j], pets[i].petName); // copy the petname into the array
j++;
}
}
puts("petslist:"); // print it all out
for (i = 0; i < j; i++) {
printf("|%s|\n", petslist[0][i]);
}
exit(0);
}
currently I always write to the [0][0] but if you realloc you can make room for more after that
This is a little weird. Maybe:
if(!*(ptr)[i])
should be
if(!(*ptr)[i])
?
I want to change the value in a linked list. The list is defined as
struct car_elements {
char *car_rego;
double time_parked;
struct car_elements *next;
};
typedef struct car_elements car;
I have created a linked list that has 10 elements. I can change the time_parked easily but having trouble updating char *car_rego. To create the string
char *rego_array = malloc(7*sizeof(char));
CreateCarRego(rego_array);
The definition for CreateCarRego is
void *CreateCarRego(char *rego_array)
{
int temp = 0;
for (int w = 0; w < 6; w++)
{
if (w < 3)
{
temp = GenerateRandomNumber(26.0);
temp = temp + ASC_TO_LETTER;
rego_array[w] = (char)temp;
}
else
{
temp = GenerateRandomNumber(10.0);
temp = temp + ASC_TO_NUMBER;
rego_array[w] = (char)temp;
}
rego_array[7] = '\0';
}
}
Then to change the value
car *current_carpark = head; //head holds the linked list
for (int i = 1; i < carspace_number; i++) { //I know which element I want to change
current_carpark = current_carpark->next;
}
current_carpark->car_rego = (char*)calloc(strlen(rego_array), sizeof(char));
strncpy(current_carpark->car_rego, rego_array, strlen(rego_array));
This works but now I have a memory leak - I cannot free current_carpark. With the struct definition I have what is the best way to create a string (which is just 3 random letters and 3 random number) and update car_rego. I cannot just use
current_carpark->car_rego = rego_array;
As nothing is stored. I am new to C and yes this is an assignment however I have tried and tried to get this to work with no success
Code has out of bounds char * issues.
In CreateCarRego(), change
rego_array[7] = '\0';
to
rego_array[6] = '\0';
It is good to put the NUL terminator on, but it is done in the wrong place. rego_array is 7 bytes long and the 7th byte is accessed via rego_array[6].
Change
current_carpark->car_rego = (char*)calloc(strlen(rego_array), sizeof(char));
strncpy(current_carpark->car_rego, rego_array, strlen(rego_array));
to
current_carpark->car_rego = malloc(strlen(rego_array) + 1);
strcpy(current_carpark->car_rego, rego_array);
Not enough memory is allocated using only the length of the string, one needs the length of the string + 1. The following strncpy() limit is too tight, it should also be strlen(rego_array) + 1. As it is known that the destniation is long enough, strcpy() could be used.
or
Simplify the string duplication with
current_carpark->car_rego = strdup(rego_array);
A number of improvements could also be mentioned, but the above should get rid of memeory problems.