I am trying to find the size of the struct array that I am using to do a sort on it. Not sure how to implement it with the sizeof() function that is normally used in nonstruct arrays.
I am also trying to figure what I am doing wrong when initializing the vehicle struct in the arguments vs the temp struct variable.
error: incompatible types when initializing type ‘struct data *’ using type ‘struct data’
struct data *temp = vehicles[j];
This is the data struct that I am using
struct data{
char *model;
float engineSize;
int cost;
char *color;
};
This is the code that I am currently running for the sort that I am using
void bubbleSortFloats(struct data vehicles[], int check)
{
int i, j, n;
n = sizeof(vehicles)/sizeof(vehicles[0]);
// If check == 1 then ascending sort
if(check == 1){
for (i = 0; i < n-1; i++){
// Last i elements are already in place
for (j = 0; j < n-i-1; j++){
if (vehicles[j].engineSize > vehicles[j+1].engineSize){
struct data temp = vehicles[j];
vehicles[j] = vehicles[j+1];
vehicles[j+1] = temp;
}
}
}
}
// If check == 0 then decending sort
if(check == 0){
for (i = 0; i < n-1; i++){
// Last i elements are already in place
for (j = 0; j < n-i-1; j++){
if (vehicles[j].engineSize < vehicles[j+1].engineSize){
struct data temp = vehicles[j+1];
vehicles[j+1] = vehicles[j];
vehicles[j] = temp;
}
}
}
}
}
This is the update with the readfile function that I am using
struct values * readFile(){
FILE *fp;
int c;
int count = 0;
char *line = NULL;
size_t len = 0;
fp = fopen("hw3.data", "r");
while ((c = fgetc(fp)) != EOF){
if(c == '\n'){
count++;
}
}
if (feof(fp)){
rewind(fp);
struct data *vehicles = malloc((sizeof(struct data))* count);
count = 0;
char *token = NULL;
while (getline(&line, &len, fp)!= -1){
printf("%s", line);
token = strtok(line, " ");
vehicles[count].model = malloc(strlen(token) + 1);
strcpy(vehicles[count].model, token);
token = strtok(NULL, " ");
vehicles[count].engineSize = atof(token);
token = strtok(NULL, " ");
vehicles[count].cost = atoi(token);
token = strtok(NULL, " ");
vehicles[count].color = malloc(strlen(token) + 1);
strcpy(vehicles[count].color, token);
free(line);
line = NULL;
len = 0;
}
struct values *value = malloc(sizeof(struct values));
value.vehicles = vehicles;
value.count = count;
return value;
}
This code
sizeof(vehicles)/sizeof(vehicles[0]);
will only work with true arrays.
In
void bubbleSortFloats(struct data vehicles[], int check);
vehicles look like an array but in fact it is a pointer, this function
definition is the same as
void bubbleSortFloats(struct data *vehicles, int check);
In C you cannot pass true arrays to the functions, they always are passed as
pointers. Even with code like this:
void foo(int arr[10])
{
printf("%lu\n", sizeof arr / sizeof *arr);
}
int main()
{
int arr[10] = { 0 };
foo(arr);
}
I get a warning of my compiler:
a.c: In function ‘foo’:
a.c:6:25: warning: ‘sizeof’ on array function parameter ‘arr’ will return size of ‘int *’ [-Wsizeof-array-argument]
printf("%lu\n", sizeof arr);
^~~
a.c:4:14: note: declared here
void foo(int arr[10])
^~~
and if I execute it, I get 2, because on my system the size of a pointer is 8
and the size of an int is 2. That's why the sizeof arr / sizeof *arr doesn't
work in a function that gets an array passed.
You have to calculate the length of the array before you call
bubbleSortFloats and pass that length to the function. The correct function
would be:
void bubbleSortFloats(struct data *vehicles, size_t len, int check)
{
...
}
We don't see how you created the array, but the function that creates it will
know the size:
void foo(void)
{
struct data vehicles[SOME_LEN];
...
bubbleSortFloats(vehicles, sizeof vehicles / sizeof *vehicles, check);
}
or if you did it with malloc
void foo(void)
{
size_t len = ...;
struct data *vehicles = malloc(len * sizeof *vehicles);
if(vehicles == NULL)
return;
...
bubbleSortFloats(vehicles, len, check);
}
edit
Jeffrey Hennen asked in the comment section:
I made it clear. I am going to want to return a structure and an int count for the size of the array of structures
Like I said in the comments, if you want to return more than one value, you have
essentially two options:
Declare a struct that encapsulates all the returning values and return it
Or pass pointers to the function and let the function update the values
provided by the pointers.
You've chosen way 1, so I guess you have this struct:
struct values {
struct data *vehicles;
size_t count;
};
Then the way you are returning it, is OK. Of course you should check that the
last malloc did not return NULL (you are ignoring that throughout the whole
function, though).
The second option would be:
The easiest way would be:
struct data *readFile(size_t *length) {
if(length == NULL)
return NULL;
...
while (getline(&line, &len, fp)!= -1){
...
};
// NOT NEEDED ANYMORE
//struct values *value = malloc(sizeof(struct values));
//value.vehicles = vehicles;
//value.count = count;
*length = count; // UPDATE the length through the pointer
return vehicles; // return the array
}
and the calling function would do:
void foo(void)
{
size_t count;
struct data *vehicles = readFile(&count);
if(vehicles == NULL)
{
// error
return;
}
do_something_with_the_vehicles(vehicles, count);
free_the_vehicles(vehicles, count);
}
Of course you would have to write a function free_the_vehicles (you can of
course choose another name) that frees all the memory allocated.
struct data *temp = &vehicles[j];
Otherwise it is incompatible as you try to assign the pointer with the structure. You need to assign the address of the structure
When copying a struct, a direct assignment does not work.
Suggest using the function: memcpy().
memcpy( temp, &vehicles[j], sizeof( struct data );
similar considerations exist for all the statements that are trying to copy the 'struct data' instances
Related
I have an array structs that hold char names. I want to sort them alphabetically using qsort however I keep getting an error message saying "initialization discards ‘const’ qualifier from pointer target type". I believe my cmpmi() function and qsort arguments are correct. Any help is greatly appreciated!
My error is:
gcc -std=gnu11 -Werror -Wall -o main main.c -lm -g
main.c: In function ‘compmi’:
main.c:18:25: error: initialization discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
const student_t **p1 = a;
^
main.c:19:25: error: initialization discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
const student_t **p2 = b;
^
cc1: all warnings being treated as errors
makefile:2: recipe for target 'main' failed
make: *** [main] Error 1
This is my qsort function:
int compmi(const void *a, const void *b)
{
const student_t **p1 = a;
const student_t **p2 = b;
return strcmp((*p1)->name, (*p2)->name);
}
Code:
int main(int argc, char **argv) {
unsigned numrecords;
int i = 0;
int length_multiplier = 1;
char *lettergrade;
//char *input = NULL;
//char *pItem;
student_t **students = NULL;
// OPENS THE FILE IN BINARY
FILE *input_file;
input_file = fopen("input.bin", "rb");
// READS THE NUMBER OF RECORDS
fread(&numrecords, sizeof(u_int32_t), 1, input_file);
// LOOPING THROUGH EACH ENTRY
for(i = 0; i <= numrecords; i++)
{
// ALLOCATES MEMORY
students = realloc(students, sizeof(student_t *) * length_multiplier);
students[i] = malloc(sizeof(student_t));
students[i]->name = malloc(sizeof(student_t)* 20);
fread(students[i]->name, sizeof(student_t), 20, input_file);//READ NAME
fread(&students[i]->gpa, sizeof(student_t), 1, input_file); // READ GPA
fread(&students[i]->age, sizeof(u_int32_t), 1, input_file);// READ AGE
length_multiplier++;
}
//SORTING WITH QSORT
qsort(*students, numrecords, sizeof(student_t *), compmi);
// PRINTING OUTPUT
for(i = 0; i < length_multiplier - 2 ; i++)
{
printf("%i of %d:\n", i + 1, numrecords);
printf("Name: %s\n", students[i]->name);
//printf("UPDATED GPA USE THIS: %.1f\n", students[i]->gpa);
printf("GPA: %.1f \n", students[i]->gpa);
printf("Age: %i\n", students[i]->age);
printf("\n");
}
// FREEING MEMORY
for(i = 0; i < length_multiplier; i++)
{
free(students[i]);
}
free(students);
fclose(input_file);
return 0;
}
The variable a points to a const qualified type, but p1 does not point to a const type (but what that points to is). You need to add const between the *s.
int compmi(const void *a, const void *b)
{
const student_t * const *p1 = a;
const student_t * const *p2 = b;
return strcmp((*p1)->name, (*p2)->name);
}
There are multiple problems in the code:
the comparison function converts pointers to constant objects to pointers to non constant objects themselves pointers to constant student objects. The original constness is not preserved. The definitions should be:
const student_t * const *p1 = a;
const student_t * const *p2 = b;
the reading loop should stop when i == numrecords so you should use i < numrecords instead of i <= numrecords.
the fread sizes are incorrect: you should specify the size of the member type, not that of the student_t structure.
you pass *students to qsort instead of the array pointer students.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student_t {
char *name;
float gpa;
int age;
} student_t;
int compmi(const void *a, const void *b) {
const student_t * const *p1 = a;
const student_t * const *p2 = b;
return strcmp((*p1)->name, (*p2)->name);
}
int main(int argc, char **argv) {
unsigned numrecords;
int i = 0;
char *lettergrade;
// OPENS THE FILE IN BINARY
FILE *input_file = fopen("input.bin", "rb");
if (input_file == NULL) {
fprintf(stderr, "cannot open input.bin\n");
return 1;
}
// READS THE NUMBER OF RECORDS
fread(&numrecords, sizeof(unsigned), 1, input_file);
// allocate the array directly, no need for realloc
student_t **students = malloc(sizeof(*students) * num_records);
if (students == NULL) {
fprintf(stderr, "allocation error\n");
return 1;
}
// LOOPING THROUGH EACH ENTRY
for (i = 0; i < numrecords; i++) {
// ALLOCATE MEMORY
if ((students[i] = malloc(sizeof(student_t))) == NULL
|| (students[i]->name = calloc(21, 1)) == NULL) {
fprintf(stderr, "allocation error\n");
return 1;
}
// READ NAME, GPA and AGE
if (fread(students[i]->name, 20, 1, input_file) != 1
|| fread(&students[i]->gpa, sizeof(students[i]->gpa), 1, input_file) != 1
|| fread(&students[i]->age, sizeof(students[i]->age), 1, input_file) != 1) {
fprintf(stderr, "error reading data for record %d / %d\n", i + 1, numrecords);
return 1;
}
}
fclose(input_file);
//SORTING WITH QSORT
qsort(students, numrecords, sizeof(*students), compmi);
// PRINTING OUTPUT
for (i = 0; i < numrecords; i++) {
printf("%i of %d:\n", i + 1, numrecords);
printf("Name: %s\n", students[i]->name);
//printf("UPDATED GPA USE THIS: %.1f\n", students[i]->gpa);
printf("GPA: %.1f\n", students[i]->gpa);
printf("Age: %i\n", students[i]->age);
printf("\n");
}
// FREEING MEMORY
for (i = 0; i < numrecords; i++) {
free(students[i]->name);
free(students[i]);
}
free(students);
return 0;
}
Note however that using binary format for the data is problematic:
the sizes and representation of various types may change from one system to another.
binary files require a precise specification and are not easy to debug.
text files are a preferred format for interchange. They are easy to read and write.
I have searched quite a bit, before asking, but I can't seem to make this function work.
I have this array of structs with 2 strings (char*)
and the function put() that adds a new struct, Unless the key already exists in that case it just ovewrites the current value with the new one.
Despite I am passing the array by reference and not making a local copy in the function, the memory still is corrupted (Segmentation Fault).
The source code is compiled under Ubuntu 15.10 on latest version of gcc.
Thanks in advance for your help guys!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 3
struct store{
char *key;
char *value;
};
void put(char *key, char *value, struct store **store, int size){
int i, found;
struct store *temp = realloc(*store, (size + 1) * sizeof(struct store));
for(i = 0; i < size; ++i){
if(strcmp(key, store[i]->key) == 0){ //Key found, overwrite new value.
store[i]->value = strdup(value); //Assume that every value is null terminated
found = 1;
break;
}
}
if(found) return;
*store = temp;
if(!store){
perror("realloc failed");
exit(EXIT_FAILURE);
}
store[size]->key = strdup(key); //New element
store[size]->value = strdup(value);
return;
}
int main(){
int i = 0;
struct store *store = malloc(N * sizeof(struct store));
if(!store){
perror("malloc failed");
exit(EXIT_FAILURE);
}
store[0].key = strdup("123a");
store[1].key = strdup("456b");
store[2].key = strdup("789c");
store[0].value = strdup("John");
store[1].value = strdup("Sam");
store[2].value = strdup("Mary");
for(i = 0; i < N; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value); //This works fine
put("123a","Jim",&store,N);
for(i = 0; i < N; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value);
put("653a","Tom",&store,N);
for(i = 0; i < N+1; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value);
return 0;
}
struct store *temp = realloc(*store, (size + 1) * sizeof(struct store));
for(i = 0; i < size; ++i){
if(strcmp(key, store[i]->key) == 0){ //Key found, overwrite new value.
store[i]->value = strdup(value); //Assume that every value is null terminated
found = 1;
break;
}
}
if(found) return;
*store = temp;
If the key is found, you don't assign temp to *store. realloc can move the allocated memory to a completely new address, thus leaving *store a dangling pointer. And you really should also check that temp isn't null as well.
There's also the problem of your misuse of store. store is the the address of the pointer you passed into the function, not the first element of an array.
You need to index the array like this (*store)[i].
Here is my problem: I have to make this program for school and I spent the last hour debugging and googling and haven't found an answer.
I have an array of structures in my main and I want to give that array to my function seteverythingup (by call by reference) because in this function a string I read from a file is split up, and I want to write it into the structure but I always get a SIGSEV error when strcpy with the struct array.
This is my main:
int main(int argc, char *argv[])
{
FILE* datei;
int size = 10;
int used = 0;
char line[1000];
struct raeume *arr = (raeume *) malloc(size * sizeof(raeume*));
if(arr == NULL){
return 0;
}
if(argc < 2){
return 0;
}
datei = fopen(argv[1], "rt");
if(datei == NULL){
return 0;
}
fgets(line,sizeof(line),datei);
while(fgets(line,sizeof(line),datei)){
int l = strlen(line);
if(line[l-1] == '\n'){
line[l-1] = '\0';
}
seteverythingup(&line,arr,size,&used);
}
ausgabeunsortiert(arr,size);
fclose(datei);
return 0;
}
and this is my function:
void seteverythingup(char line[],struct raeume *arr[], int size,int used)
{
char *token,raumnummer[5],klasse[6];
int tische = 0;
const char c[2] = ";";
int i=0;
token = strtok(line, c);
strcpy(raumnummer,token);
while(token != NULL )
{
token = strtok(NULL, c);
if(i==0){
strcpy(klasse,token);
}else if(i==1){
sscanf(token,"%d",&tische);
}
i++;
}
managesize(&arr[size],&size,used);
strcpy(arr[used]->number,raumnummer);
strcpy(arr[used]->klasse,klasse);
arr[used]->tische = tische;
used++;
}
Edit: Since there is more confusion I wrote a short program that works out the part you are having trouble with.
#include <cstdlib>
struct raeume {
int foo;
int bar;
};
void seteverythingup(struct raeume *arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
arr[i].foo = 42;
arr[i].bar = 53;
}
}
int main() {
const size_t size = 10;
struct raeume *arr = (struct raeume*) malloc(size * sizeof(struct raeume));
seteverythingup(arr, size);
return 0;
}
So basically the signature of your functions is somewhat odd. Malloc returns you a pointer to a memory location. So you really dont need a pointer to an array. Just pass the function the pointer you got from malloc and the function will be able to manipulate that region.
Original Answer:
malloc(size * sizeof(raeume*));
This is probably the part of the code that gives you a hard time. sizeof returns the size of a type. You ask sizeof how many bytes a pointer to you raeume struct requires. what you probably wanted to do is ask for the size of the struct itself and allocate size times space for that. So the correct call to malloc would be:
malloc(size * sizeof(struct raeume));
I've looked enough about this problem on this site and still haven't found a solution.
I have an array of struct, and I want to read from a file some records and store them in the structs. The problem is the allocation of the memory.
This is the struct I use:
struct Rec{
int mat;
char *nome;
char *cognome;
};
typedef struct Rec* Record;
This is the readFromFile function:
void readFromFile(char* fileName, Record** data, int* pn)
{
char line[LINE_LENGTH];
int n, i;
char* token;
printf("\n\nReading file %s\n", fileName);
FILE* fin = fopen(fileName, "r");
if (fin == NULL)
{ printf("Error readinf file\n");getch();
goto end;
}
n = 0; // first read to know the number of lines
while (fgets(line, LINE_LENGTH, fin) != NULL) n++;
n = (n < MAX_LENGTH ? n : MAX_LENGTH);
printf("N: %d\n", n);
*pn = n;
//Then I allocate the memory for the n lines I previously read
*data = (Record*)malloc(n * sizeof(Record));
if(*data == NULL){
printf("Problem allocating memory\n");
exit(0);
}
i = 0;
for(i = 0; i < n; i++){
(*data)[i].nome = malloc(sizeof(char) * MAX_LENGTH + 1);
if((*data)[i]->nome == NULL){
printf("Problem allocating memory\n");
exit(1);
}
//Here comes the problem, the allocation of the second string fails and the program exit
(*data)[i]->cognome = malloc((sizeof(char) * MAX_LENGTH + 1));
if((*data)[i]->cognome == NULL){
printf("Problem allocating memory\n");
exit(2);
}
}
rewind(fin);
n = 0;
while (fgets(line, LINE_LENGTH, fin) != NULL && n < MAX_LENGTH)
{
token = strtok(line, ";");
strcpy((*data)[n]->nome, token);
token = strtok(line, ";");
strcpy((*data)[n]->cognome, token);
token = strtok(line, ";");
(*data)[n]->mat = atoi(token);
n++;
}
fclose(fin);
end:return;
}
I've tried to modify the structure and the code in many ways but have not found a solution, I think that probably is a pointer problem but I can't figure it out. The readFromFile function was provided from the professor and was built to read int from file and I had to modify it to read records.
There's a big difference between:
(*data)[i].nome = malloc(sizeof(char) * MAX_LENGTH + 1);
and:
(*data)[i]->cognome = malloc((sizeof(char) * MAX_LENGTH + 1));
The first line with the dot notation used, is implying, access to a member of a struct, whereas the -> implies accessing a member of a struct using pointer notation, i.e. pointer to a structure.
The confusion is showing there, as (*data) is a pointer to a struct of type Record which is a type definition of Rec.
typedef struct Rec* Record;
Since data when stripped down, is type definition of Record, aliased to a pointer to struct of Rec. The double pointer as part of parameter, which will be modified through pass by reference, is declared, after determining the number of lines in input dataset, as an array of pointers:
*data = (Record*)malloc(n * sizeof(Record));
Accessing the member data, for each entry in the array would be:
(*data)[i] dot name_of_member
The rule would have changed, had the type definition be like this:
typedef struct Rec Record;
i.e. a normal struct, no pointer usage.
Then access to the member data would have been, if allocation was achieved,
(*data)[i]->name_of_member
However, do not try hide pointers behind a typedef as that will give grief, come back to the code again in the future, and wondering why it failed, the hidden pointer has bitten you!
Record is defined as
typedef struct Rec* Record;
therefore it is pointer to struct Rec. malloc returns pointer to allocated memory (or NULL) but you cast this to pointer to pointer
*data = (Record*)malloc(n * sizeof(Record));
// = Rec**
This code has a problem in the struct data members. When I call a function like Evaluator() function the token[0].value will corrupt or will turn into a garbage. I tried to allocate a memory for the value data member but still no luck. I also tried to allocate a memory for the struct itself but still it doesn't work. Can someone help me with this?
struct tokens
{
char *value;
char type = ' ';
};
void inputComponent(char input_string[size])
printf("\n> ");
scanf("%[^\n]s", input_string);
}
int processingComponent(char *input_string, int *result)
{
int error_flag = 0;
tokens token[size];
error_flag = Parser(input_string, token);
if (error_flag == 0)
error_flag = Evaluator(result, token);
return error_flag;
}
int Parser(char *input_string, struct tokens token[size])
{
char valid_operators[size] = { "+-*/%" };
char temp = ' ';
char number_string[size] = { NULL };
int counter = 0;
int countStruct = 0;
int tempCounter = 0;
do
{
temp = input_string[counter];
if (isdigit(temp))
{
number_string[tempCounter] = temp;
tempCounter++;
}
else if (strpbrk(input_string, valid_operators))
{
if (temp == '%')
return (-1);
else if (number_string != NULL)
{
char tempNum[size] = { NULL };
strcpy(tempNum, number_string);
token[countStruct].value = tempNum;
token[countStruct].type = 'N';
countStruct++;
tempCounter = 0;
for (int x = 0; number_string[x] != NULL; x++)
number_string[x] = NULL;
}
}
else
return (-2);
counter++;
} while (counter < strlen(input_string));
return 0;
}
int Evaluator(int *result, struct tokens token[size])
{
for(int x = 0; x < 3; x++) //value of token[0].value = ÌÌÌÌÌÌÌÌÌÌÌÌ
printf("%s", token[x].value);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
char input_string[size] = { NULL };
int result = 0;
int error_flag = 0;
inputComponent(input_string);
error_flag = processingComponent(input_string, &result);
_getch();
_getch();
return 0;
}
For starters, when you pass an array of tokens to the Parser and Evaluator functions, you are passing the variables by value. The token array is not actually changed after calling Parser():
`
int Parser(char *input_string, struct tokens myArray[size])
{
//modifying myArray will not modify the array that was actually passed
//to this function from the processingComponent() function.
}
`
First change your Parser and Evaluator functions like so:
#define ARRAY_SIZE 100 //an arbitrary size
int Parser( char* input_string, struct token* tokenArray )
{
//access each element as so:
//tokenArray[0];
//tokenArray[ ARRAY_SIZE - 1 ];
}
int Evaluator(int *result, struct token* tokenArray )
{
for(int x = 0; x < ARRAY_SIZE; x++)
printf("%s", tokenArray[x].value);
return 0;
}
Then call the Parser() function as so:
EDIT: Since it is a good idea to allocate and free memory within the same function (so that you don't end up with spaghetti code), this would be a better solution:
int processingComponent(char *input_string, int *result)
{
int error_flag = 0;
token tokenArray[ARRAY_SIZE];
//allocate memory here
for( int i = 0; i < ARRAY_SIZE; i++ ) {
tokenArray[i].value = (char*)malloc( sizeof(char) * MAX_STRING_LENGTH);
}
error_flag = Parser(input_string, &tokenArray[0]);
if (error_flag == 0)
error_flag = Evaluator(result, &tokenArray[0]);
//free memory here before the token array goes out of scope:
for( int i = 0; i < ARRAY_SIZE; i++ ) {
free( tokenArray[i].value );
tokenArray[i].value = NULL;
}
return error_flag;
}
When you allocate memory for your token string, it needs to be dynamically allocated using malloc() and deleted using free().
Replace this:
strcpy(tempNum, number_string);
token[countStruct].value = tempNum;
//with:
#define MAX_STRING_LENGTH 255 //arbitrary
//Memory has already been allocated, so just copy the string into the token
strncpy( token[countStruct].value, number_string, MAX_STRING_LENGTH - 1 );
token[countStruct].value[MAX_STRING_LENGTH-1] = NULL;
You don't appear to be allocating any storage for token[].value. You set it equal to tempNum, but that goes out of scope in the inner block in Parser(). I would say that anything this code does is undefined because you're accessing memory that was deallocated when Parser() returned.
Precautions with Structures
I have added a text file, which contains your running code with instructions.
one important thing you can not assign any thing directly into structure, because declaration of structure reserve no space.
Why did you do such a hectic job to achieve something like this..
input :12+3-1/7
output:12317
Click this link to get your running c code