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])
?
Related
I'm trying to get to read string input from user and store it in two dim array using pointers.
I'm getting Access violation reading location exception when trying to use those strings.
first I declared char*** that will store pointers for two dim array , then I use for loop to initial two dim array for each cell.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORDLEN 80
#define DEFLEN 200
#define KEYVALUE 2
char*** MallocDic(int dictionarySize);
char** MallocDicElement(char* word, char* definition);
void PrintDictionary(char*** dictionary, int dictionarySize);
int main()
{
int dictionarySize;
printf("Please enter dictionary size\n");
scanf("%d", &dictionarySize);
char*** dictionary = MallocDic(dictionarySize);
int i;
for (i = 0; i < dictionarySize; i++) {
char* inputWord = (char*)malloc(WORDLEN * sizeof(char));
char* inputDef = (char*)malloc(DEFLEN * sizeof(char));
if (inputWord == NULL || inputDef == NULL)
{
printf("Failed to allocate memory!\n");
exit(1);
}
printf("enter word : \n");
scanf("%s", inputWord);
printf("enter definition : \n");
scanf("%s", inputDef);
printf("word : %s ,def : %s\n", inputWord, inputDef);
//dictionary[i] = MallocDicElement(inputWord, inputDef);
//free(inputDef);
free(inputWord);
}
printf("Print Dictionary : \n");
//PrintDictionary(dictionary, dictionarySize);
}
char*** MallocDic(int dictionarySize) {
char*** p;
p = (char***)malloc(dictionarySize * sizeof(char**));
return p;
}
char** MallocDicElement(char* word, char* definition) {
char** p = (char**)malloc(KEYVALUE * sizeof(char*));
int i;
for (i = 0; i < KEYVALUE; i++) {
if (i == 0) {
p[i] = (char*)malloc(WORDLEN * sizeof(char));
p[i] = word;
}
else {
p[i] = (char*)malloc(DEFLEN * sizeof(char));
p[i] = definition;
}
}
return p;
}
void PrintDictionary(char*** dictionary, int dictionarySize) {
int i = 0, j = 0;
for (i = 0; i < dictionarySize; i++) {
for (j = 0; j < KEYVALUE; j++) {
printf("word : %s\n", dictionary[i][0]);
printf("definition : %s\n", dictionary[i][1]);
}
}
}
The logic breaks in when trying to print the first string.
what am I missing here ?
Thanks for any help.
At least these problems.
Leaked memory
Code allocates memory and saves the pointer to that allocation to p[i] and then copies the pointer word to p[i] in the next line. This loses the pointer returned from malloc().
p[i] = (char*)malloc(WORDLEN * sizeof(char));
p[i] = word; // ???
Much more likely OP wants to copy the string, pointed to by word to the memory pointed to by p[i].
p[i] = malloc(WORDLEN);
strcpy(p[i], word);
More common to allocate only what is needed.
p[i] = malloc(strlen(word) + 1);
strcpy(p[i], word);
Research strdup().
Error checking omitted for brevity.
Do not use "%s", "%[]" without a width in *scanf()
Limit acceptable input to 1 less than the size of the destination array.
"%s" does not read and save spaces
The below will not work to read a definition that contains spaces.
printf("enter definition : \n");
scanf("%s", inputDef); // Stops after first word
Scanning will stop at the first white-space after reading some non-white-space.
Perhaps:
scanf(" %199[^\n]", inputDef);
Check return value of input functions
if (scanf(" %199[^\n]", inputDef) != 1) {
Handle_input_error();
}
Other:
Avoid hard to read & maintain allocation
Rather than cast (not needed) and size to the type (defined someplace else), allocate to the size of the referenced object - no type needed to get wrong.
// p = (char***)malloc(dictionarySize * sizeof(char**));
p = malloc(sizeof p[0] * dictionarySize);
Easier to code right, review and maintain.
At the risk of a non-answer here (not working with your extant code) I would like to suggest you take the time to better structure your data. Even something as simple as:
// A `dictionary` is an array of `capacity` entries, `size` of which are in use.
// Elements are kept in lexicographical order.
struct dictionary
{
struct entry
{
const char * word;
const char * definition;
};
struct entry * entries;
size_t size;
size_t capacity;
};
typedef struct dictionary dictionary;
This makes life about a bazillion times easier when dealing with stuff. You can now create a couple of useful functions:
dictionary * new_dictionary( size_t capacity );
void free_dictionary( dictionary * dict );
This structured nature makes it easier to manage individual parts. In particular, your users can pass the pointer to the dictionary around and never have to worry about it changing. For example, suppose you want to update the dictionary’s capacity:
void set_dicitionary_capacity( dictionary * dict, size_t new_capacity )
{
if (new_capacity < dict->size) return;
struct entry * new_entries = realloc( dict->entries, new_capacity * sizeof dict->entries[0] );
if (!new_entries) return;
dict->capacity = new_capacity;
dict->entries = new_entries;
}
This idea of having functions to interface with your opaque dictionary object is the basis for basic data encapsulation. Doing so makes the using code so much easier:
dictionary * words = new_dictionary( 1000 );
if (!words) fooey();
update_dictionary( words, "hello", "a greeting" );
update_dictionary( words, "world", "the Earth; a planet; any organism’s collective society" );
printf( "There are %zu words in the dictionary.\n", dictionary_size( words ) );
const char * desc = find_word( words, "there" );
printf( "Obi Wan can%s use this dictionary.\n", desc ? "" : "not" );
free_dictionary( words );
Hopefully we can already see how things are easier to grok on every level.
In other words, write code in such a way as to make meaning and structure as clear as possible. This helps to reduce the amount of failure our befuddled minds can generate when writing code.
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
}
}
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);
}
I am trying to improve my C skills so I apologize if my question is long. I am having a hard time understanding as to why my struct pointer holds the wrong value in my program, I tried to debug it but I am still relatively new to C and was hoping one of you could tell me what I'm doing wrong here and how I could improve my code and what to focus on.
I am making a program that stores user data on this struct and then prints it out.
typedef struct table {
char *firstName;
char *lastName;
int id;
}USER;
This function below stores the first name
void firstName(int *counter, int *check, USER *pt) {
for (int i = *counter; i < *check; i++) {
pt[i].firstName = calloc (MAX_LENGTH, sizeof(pt));
printf("Enter First Name: ");
getchar();
fgets(pt[i].firstName, MAX_LENGTH, stdin);
}
}
This is just my bool function returning true or false
bool isTrue(char *decision) {
if(*decision == 'Y') {
return true;
}
else {
return false;
}
}
And this is my main
int main(int argc, char **argv) {
USER *pt = calloc(1, sizeof(pt));
int counter = 0, check = 0;
char decision = '\0';
while (1) {
printf("Would you like to enter a user?(Y/N):");
fgets(&decision, 2, stdin);
strtok(&decision, "\n"); //remove the newline char
if (!isTrue(&decision)) {
break;
}
if (counter != 0) {
pt = realloc(pt, sizeof(pt) * 10); //the 10 is temporary
}
check = counter + 1; // make sure loop only runs once.
firstName(&counter, &check, pt);
++counter; // increment counter;
}
printStruct(pt, &counter);
return 0;
}
When I run it out sometimes it works fine and returns everything and sometimes it skips a value. This is what I get. It skips the value at pointer index 1 and prints garbage instead.
Would you like to enter a user?(Y/N):N
First name at array 0 is Ermir
First name at array 1 is P#1First name at array 2 is Kevin
First name at array 3 is Blaus
First name at array 4 is Adam
Also I was wondering why is it when I realloc here If i do I get a realloc error when I enter the second name.
if (counter != 0) {
pt = realloc(pt, sizeof(pt) * 10); //realloc(pt, sizeof(pt) * counter + 1) wont work
}
char decision = '\0';
...
fgets(&decision, 2, stdin);
You are only allocating 1 char but are at least reading 2 chars into it. Fix by allocating a sufficiently sized array for decision.
Unrelated but in firstName() pt[i].firstName = calloc (MAX_LENGTH, sizeof(pt)); should be pt[i].firstName = calloc (MAX_LENGTH, 1);
so I'm having a little problem with my struct array not doing what its supposed to. I get no compiler warnings or errors when building the program.
int Array_Size=0;;
int Array_Index=0;
FILE *Writer;
struct WordElement
{
int Count;
char Word[50];
};
struct WordElement *StructPointer; //just a pointer to a structure
int Create_Array(int Size){
StructPointer = (struct WordElement *) malloc(Size * sizeof(StructPointer));
Array_Size = Size;
return 0;
}
int Add_To_Array(char Word[50]){
int Word_Found=0;
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
{
if(strcmp(StructPointer[i].Word, Word)) // This should only run if the word exists in struct array
{
StructPointer[i].Count++;
Word_Found=1;
}
}
if(Word_Found==0) // if the above if statement doesnt evualate, this should run
{
strcpy(StructPointer[Array_Index].Word, Word); //copying the word passed by the main function to the struct array at a specific index
printf("WORD: %s\n", StructPointer[Array_Index].Word); // printing it just to make sure it got copied correctly
Array_Index++;
}
return 0;
}
int Print_All(char File_Name[50])
{
Writer = fopen(File_Name, "w");
printf("Printing starts now: \n");
for(int i=0; i < Array_Size; i++)
{
fprintf(Writer, "%s\t\t%d\n",StructPointer[i].Word, StructPointer[i].Count);
}
free(StructPointer);
return 0;
}
These functions get called from a different file, The Add_To_Array is called when the program reads a new word form the text file. That function is supposed to check if the word already exists in the struct array and if it does, it should just increment the counter. If it doesn't, then it adds it.
The Print_All function is called after all the words have been stored in the struct array. Its supposed to loop through them and print each word and their occurrence. In the text file, there are 2 of every words but my program outputs:
this 13762753
document -1772785369
contains 1129268256
two 6619253
of 5701679
every 5570645
word 3342389
doccontains 5374021
I don't know what to make of this as im really new to C programming... It's probably worth mentioning the if(Word_Foun==0) doesn't execute
StructPointer = malloc(Size * sizeof(*StructPointer));
This will be the correct allocation. Otherwise you will have erroneous behavior in your code. Also check the return value of malloc.
StructPointer = malloc(Size * sizeof(*StructPointer));
if(NULL == StructPointer){
perror("malloc failure");
exit(EXIT_FAILURE);
}
You are allocating for struct WordElement not a for a pointer to it. You already have a pointer to struct WordElement all that you needed was memory for a struct WordElement.
Also in the loop you are accessing array index out of bound
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
^^^
It will be i < Array_Size.
In case match occurs you want to set the variable Word_found to 1.
if(strcmp(StructPointer[i].Word, Word) == 0){
/* it macthed */
}
Also Writer = fopen(File_Name, "w"); you should check the return value of fopen.
if(Writer == NULL){
fprintf(stderr,"Error in file opening");
exit(EXIT_FAILURE);
}
Also when you are increasing the Array_index place a check whether it might access the array index out of bound.
The more global variable you use for achieving a small task would make it more difficult to track down a bug. It is always problematic because the places from which data might change is scattered - making it difficult to manage.