Malloc wont create array of structs with desired size - c

Im working on function which reads text file. Function should find out how many records the text file have and malloc an array of structures. It must be array of structures because it is specified in my assignment. LineCounter holds value of how big the array should be. It has value 17 which is correct but when I malloc the array it only have size of 4 structs. I am programming in C and I am also including <stdlib.h> but the compiler is still forcing me to cast malloc.
// SEPARATE HEADER FILE
#pragma once
#define FILECITATEL "citatel.txt" // textovy subor obsahujuci zoznam citatelov
typedef struct Citatel {
int id; // id cislo citatela
char meno[20]; // meno citatela
char priezvisko[30]; // priezvisko citatela
};
Citatel *getReaders();
void printReaders(Citatel *listOfReaders);
// END OF HEADER FILE
Citatel *getReaders() {
FILE *fileRead;
fileRead = fopen(FILECITATEL, "r");
if (fileRead == NULL) {
printf("File cannot be opened!...");
return NULL;
}
char readCharacter;
int lineCounter = 0;
while ((readCharacter = fgetc(fileRead)) != EOF) {
if (readCharacter == '\n') lineCounter++;
}
if (readCharacter == EOF) lineCounter++;
rewind(fileRead);
Citatel *list = (Citatel *)malloc(lineCounter * sizeof(Citatel));
for (int i = 0; i < lineCounter; i++) {
fscanf(fileRead, "%d %s %s", &list[i].id, &list[i].meno, &list[i].priezvisko);
}
printf("%d\n", sizeof list);
fclose(fileRead);
return list;
}

The variable list is a pointer, when you get the size of list you get the size of the pointer and not what it points to. You need to keep track of the memory you allocate yourself.
And the usual link: Don't cast the return of malloc in C (or any other function returning void *).
And if you're programming in C++ then you should be using std::vector instead (or worst case use new[]) and the standard library streams.

You are understanding wrong:
sizeof list
return the size of the pointer not the size of the memory that you allocate.

Your mistake is in the line where you take sizeof list, because that prints the size of list pointer, which is 4 bytes. You want to print lineCounter instead.
Additionally, you are suggested to avoid casting the result of malloc. See here:
Do I cast the result of malloc?

Related

Creating a function to allocate a array of strings in C

I'm working on a minisql code in C and i having some issues to allocate array of strings. I made a function called "alocaString" to do this (bc i'm using that a lot), but i don't think is working.
When the code reaches the line "strncpy(lista[qtnPalavras], splitStr, 100);" in the function "listaPalavras" (that have the purpose of split a string in different types of characters) a file named "strcpy-avx2.S" is created, one of the arguments of that function (**lista) is allocated with "alocaString" so i think the problem is in that function.
I already try to use valgrind and shows "is used uninitialized in this function [-Werror=uninitialized]" to all arrays of strings that i tried to use on that function, but i'm initializing them inside of the function
int alocaString (char **string, int tamanho, int posicoes){
string = malloc (posicoes * sizeof(char*));
for (int i = 0; i < posicoes; i++){
string [i] = malloc (tamanho * sizeof(char));
if (string[i] == NULL){return 0;}
}
return **string;
}
void desalocaString (char **string, int posicoes){
for (int i = 0; i < (posicoes); i++){
free (string[i]);
}
free (string);
}
int listaPalavras(char *entrada, char **lista, char *separador){ // lista as palavras
char *splitStr;
int qtnPalavras = 0;
splitStr = strtok(entrada, separador);
while (splitStr != NULL){
strncpy(lista[qtnPalavras], splitStr, 100);
qtnPalavras++;
splitStr = strtok(NULL, separador);
}
return qtnPalavras;
}
I assume that you are using these functions like this:
alocaString(lista, tamanho, posicoes);
listaPalavras(some_string, lista, some_delimiters);
desalocaString(arr);
Even without looking at the code, it seems logically wrong to allocate an array of strings first and then populate it if you do not already know how many strings it will need to fit. If you happen to allocate an array of n strings, but your listaPalavras() functions splits the provided string into n+1 or more substrings, you're going to overflow your previously allocated array. Nonetheless, this can be done taking the appropriate precautions, like carrying around sizes and checking them to avoid overflow.
The only sane way to achieve what you want is therefore to either (A) count the number of delimiters in the string first to know in advantage how many pointers you will need or (B) dynamically allocate the needed amount in listaPalavras() while splitting. You seem to be going with something similar to option A, but your code is flawed.
The desalocaString() is the only function that seems correct.
A correct implementation of alocaString() would return the allocated array (or NULL in case of failure), but you are returning **string which is just the first character of the first string. Needless to say, this does not make much sense. You don't need to take a char ** parameter, just the sizes. Secondly, in case of failure of any of the calls to malloc() you should free the previously allocated ones before returning NULL.
char **alocaString (unsigned tamanho, unsigned posicoes) {
char **lista = malloc(posicoes * sizeof(char*));
if (lista == NULL)
return NULL;
for (unsigned i = 0; i < posicoes; i++) {
lista[i] = malloc(tamanho * sizeof(char));
if (lista[i] == NULL) {
for (unsigned j = 0; j < i; j++)
free(lista[j]);
free(lista);
return NULL;
}
}
return lista;
}
As per listaPalavras(), which has the job of splitting the given string into other strings and copying them into the previously allocated array, to avoid overflowing the given array of strings you will need to also provide its length as well as the length of the previously allocated strings as argument (let's call them posicoes and tamanho like for the above function). Moreover, strncpy() will not add a NUL-terminator (\0) to the destination string if it is not found in the source string within the first n characters (n being the third argument), so you will need to add it yourself to make sure your strings are correctly terminated.
unsigned listaPalavras(const char *entrada, char *separador, char **lista, unsigned posicoes, unsigned tamanho) {
char *splitStr;
unsigned qtnPalavras = 0;
splitStr = strtok(entrada, separador);
while (qtnPalavras < posicoes && splitStr != NULL){
strncpy(lista[qtnPalavras], splitStr, tamanho);
lista[qtnPalavras][tamanho - 1] = '\0';
qtnPalavras++;
splitStr = strtok(NULL, separador);
}
return qtnPalavras;
}
Finally the code of the caller should look something like this:
char **lista;
unsigned tamanho = 100;
unsigned posicoes = 10;
unsigned palavras;
lista = alocaString(tamanho, posicoes);
if (lista == NULL) {
// handle the error somehow
}
palavras = listaPalavras(YOUR_STRING, YOUR_DELIMITERS, lista, posicoes, tamanho);
desalocaString(lista);
This should work fine, however you are limited by the fact that:
You cannot know beforehand the number of substrings that strtok() will find.
You cannot know beforehand the length of any of those substrings.
Therefore, allocating the needed lista dynamically inside listaPalavras() would make more sense.
Finally, as a side note, the names of your functions are misleading: if you need to allocate an array of strings, you might want to choose a better name than alocaString() which seems to imply that you are allocating a single string. Maybe alocaLista() and dealocaLista() would be better choices.

Array of pointers in C with easy iteration

Recently I was pondering over this question: how to make an easier way to iterate over an array of pointer in C.
If I create an array of string in C, it should look like this right?
int size = 5;
char ** strArr = (char **) malloc(sizeof(char *) * size);
if (strArr == NULL) return;
But the problem is, when you want to iterate over this array for some reason (like printing all values inside it), you have to keep track of its current size, storing in another variable.
That's not a problem, but if you create lots of arrays, you have to keep track of every single one of their sizes inside the code. If you pass this array to another function, you must pass its size as well.
void PrintValues (char ** arr, int size) {
for (int i = 0; i < size; i++)
printf("%s\n", arr[i]);
}
But when iterating over a string, it's different. You have the '\0' character, which specifies the end of the string. So, you could iterate over a string like this, with not need to keep its size value:
char * str = (char *) malloc(sizeof(char) * 4);
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';
for (int i = 0; str[i] != '\0'; i++)
printf("%c", str[i]);
printf("\n");
Now my question:
Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
char ** strArr = (char **) malloc(sizeof(char *) * (5 +1);
if (strArr == NULL) return;
strArr[0] = PseudoFunc_NewString("Car");
strArr[1] = PseudoFunc_NewString("Car#1");
strArr[2] = PseudoFunc_NewString("Car#2");
strArr[3] = PseudoFunc_NewString("Tree");
strArr[4] = PseudoFunc_NewString("Tree#1");
strArr[5] = NULL; // Stop iteration here as next element is not allocated
Then I could use the NULL pointer to control the iterator:
void PrintValues (char ** arr) {
for (int i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
This would help me to keep the code cleaner, though it would consume more memory as a pointer size is larger than a integer size.
Also, when programming with event-based libraries, like Gtk, the size values would be released from the stack at some point, so I would have to create a pointer to dynamically store the size value for example.
In cases like this, it ok to do this? Or is it considered something bad?
Is this technique only used with char pointers because char type has a size of only 1 byte?
I miss having a foreach iterator in C...
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
This is ok, the final NULL is called a sentinel value and using one is somewhat common practice. This is most often used when you don't even know the size of the data for some reason.
It is however, not the best solution, because you have to iterate over all the data to find the size. Solutions that store the size separately are much faster. An arrays of structs for example, containing both size and data in the same place.
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
In C this is quite a common pattern, and it has a name. You're simply using a sentinel value.
As long as your list can not contain null pointers normally this is fine. It is a bit error-prone in general however, then again, that's C for you.
It's ok, and is a commonly used pattern.
As an alternative you can use a struct, in there you can create a size variable where you can store the current size of the array, and pass the struct as argument. The advantage is that you don't need to iterate through the entire array to know its size.
Example:
Live demo
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
char **strArr;
int size;
} MyStruct;
void PrintValues(MyStruct arr) //pass the struct as an argument
{
for (int i = 0; i < arr.size; i++) //use the size passed in the struct
printf("%s\n", arr.strArr[i]);
}
int main()
{
// using the variable to extract the size, to avoid silent errors
// also removed the cast for the same reason
char **strArr = malloc(sizeof *strArr * 5);
if (strArr == NULL) return EXIT_FAILURE;
strArr[0] = "Car";
strArr[1] = "Car#1";
strArr[2] = "Car#2";
strArr[3] = "Tree";
strArr[4] = "Tree#1";
MyStruct strt = { strArr, 5 }; // initialize the struct
PrintValues(strt); //voila
free(strArr); // don't forget to free the allacated memory
return EXIT_SUCCESS;
}
This allows for direct access to an index with error checking:
// here if the array index exists, it will be printed
// otherwise no, allows for O(1) access error free
if(arr.size > 6){
printf("%s\n", arr.strArr[6]);
}

How to make malloc to a struct inside of another struct?

In the first .h file, i have this struct:
typedef struct system
{
char* name;
DArray Info;
} *System;
And in the .c file I have this function:
System createSystem(char *name){
if (!name){
return NULL;
}
System newSystem=malloc(sizeof(*newSystem));
if (!newSystem){
return NULL;
}
newSystem->name=malloc(sizeof(strlen(name)+1));
if (!newSystem->name){
free(newSystem);
return NULL;
}
strcpy(newSystem->name,name);
newSystem->Info=malloc(sizeof *(newSystem->Info));
if (!newSystem->Info){
free(newSystem->name);
free(newSystem);
return NULL;
}
newSystem->Info->x=0;
newSystem->Info->elements=NULL;
return newSystem;
}
In another .h file I have the struct dArray:
typedef struct dArray
{
int x;
Element *elements;
} *DArray;
where Element could be of any type.
However, the function always stops working in Eclipse and I get the error
hw stopped working
I know that the problem is in this line:
newSystem->Info=malloc(sizeof(*newSystem->Info));
but I don't understand why this is a problem as I am trying to malloc to the struct DArray in a regular way!
I have been using this test in the main file:
int main() {
sys=createSystem("ss1");
if (sys) {
printf ("ok");
return 0;
}
Any help would be appreciated.
System createSystem(char *name){
if (!name){
return NULL;
}
System newSystem=malloc(sizeof *newSystem);
if (!newSystem){
return NULL;
}
newSystem->name=malloc(sizeof *newSystem->name * (strlen(name)+1)); // <-- change here.
if (!newSystem->name){
free(newSystem);
return NULL;
}
strcpy(newSystem->name,name);
newSystem->Info=malloc(sizeof *newSystem->Info);
if (!newSystem->Info){
free(newSystem->name);
free(newSystem);
return NULL;
}
newSystem->Info->x=0;
newSystem->Info->elements=NULL;
return newSystem;
}
In case you are copying the string to dynamically allocated memory, it(malloc) basically allocate sizeof (strlen(str)+1) bytes of memory. And that will be nothing but sizeof operator applied to size_t which is unlikely to hold a characters string. (5 characters in my machine).
(why size_t? Because the function strlen has a signature size_t strlen(const char *s);)
Also in my system sizeof size_t is 4 bytes. So basically you are allocating 5 bytes. That means the string will consists of 5 characters including the nul terminating character.
Anything more than length more comes like "ABCDED", you are writing out of the memory you allocated causing an illegal memory access - and this has undefined behavior. In your case it simply stops.
To add more clarification, in your case I guess when you are entering the string you are passing something more than length 4. But if you pass the string "ss1" then this will work.
newSystem->name=malloc(sizeof *newSystem->name * (strlen(name)+1)); can be more clearly written as newSystem->name=malloc(strlen(name)+1);. As sizeof char is 1 byte we have avoided it.
You may later try to look up strdup function which is not part of ISO standard.
Also, the following is not at all what you are after:
newSystem->name=malloc(sizeof(strlen(name)+1));
That is going to malloc() a buffer of (at minimum) sizeof(size_t) not a buffer capable of holding strlen(name)+1 bytes -- size_t is the return type of strlen and that is what the sizeof is being applied to.
below statement are not correct:-
System newSystem=malloc(sizeof(*newSystem)); it should be System newSystem=malloc(sizeof(struct system));
and newSystem->Info=malloc(sizeof *(newSystem->Info)); is newSystem->Info is a pointer? if pointer it should be newSystem->Info=malloc(sizeof(DArray));

How to differentiate empty and 0 in an int array in C?

I'm a beginner of C and now I'm learning pointer and dynamic memory allocation. I want to write a simple program to create empty arrays and check for the existence of a given number. Here's my code:
/* create an empty array pointer */
int* createArray(){
int *a = (int*) malloc(sizeof(int));
return a;
}
void findArrayElement(int *list, int element){
int i;
int len = (sizeof(list) / sizeof(int));
if (sizeof(list) == 0) {
printf("NO\n");
return;
}
for (i=0; i<len; i++) {
if (list[i] == element) {
printf("YES\n");
return;
}
}
printf("NO\n");
}
int main(int argc, const char * argv[]) {
int *p;
p = createArray();
printf("size of int is: %lu\n", sizeof(int));
printf("size of p is: %lu\n", sizeof(p));
printf("LENGTH of p is: %lu\n", ARRLENGTH(p));
findArrayElement(p, 2);
findArrayElement(p, 0);
return 0;
}
But when I run the program, I always get 'YES' when I looking for 0, so
Is there a way to differentiate integer 0 and a complete empty array?
Also I'm not sure whether my function createArray() is a correct way to create an empty array.
Thanks guys.
Is there a way to differentiate integer 0 and a complete empty array?
How do you define an empty array? Once you allocate a memory chunk and assign it to a pointer, it already has some value (which is undefined in case of alloc). The most used way to mark a pointer as not used or not allocated os to assign NULL to it.
Also I'm not sure whether my function createArray() is a correct way to create an empty array.
sizeof returns the number of bytes which the given object (or type) occupies in the memory. In your case sizeof(list) returns 8 as it is a pointer.
In oder to allocate an array, the function has to receive its size. Currently it always allocates size for one integer only.
Edit: Adding example.
/* create an empty array pointer */
int* createArray(size_t size)
{
return (size ? (int*) malloc(sizeof(int)*size) : NULL);
}
So now the returned pointer should be 'coupled' with the size of the array. Which means that each function that receives an array as a parameter should receive also its size.
sizeof returns the memory size of the array pointer, regardless of contents.
edit: if it exists in memory, it will be nonzero.
edit 3: removed inaccurate information, see the comments about creating a variable to record the length. Also from comments, note that your createArray function is creating an array for exactly 1 integer. In C, arrays are of fixed length. So this Array will always be the same size (whether you stored something in it or not). sizeof(pointer) will always return the memory allocated for the pointer, not the memory allocated for the array at which it is pointing.

copying an array of integers to another integer array

#include<stdio.h>
void int_copy(int* ptrA,int* ptrB,int nbr){
//int* temp = ptrB;
while(nbr != 0){
*ptrB++ = *ptrA++;
nbr--;
}
*ptrB = -1;
//ptrB = temp;
}
int main(){
int stringa[40] = {100,101,102,103,104,105,106,107,108,109,110,-1};
int stringb[40] = {0};
int *ptr;
int *ptr1;
int len = 0;
ptr = stringa;
ptr1 = stringb;
while(*ptr != -1){
*ptr++;len++;
}
printf("\n len : %d \n",len);
int_copy(stringa,stringb,len);
while(*ptr1 != -1){
printf("%d\t",*ptr1);
*ptr1++;
}
return 0;
}
I was trying out an example program to copy an array of integers to another integer array. Is there another way to do it in a more efficient way.
EDITED :
void int_copy(int* ptrA,int* ptrB,int nbr){
memcpy(ptrA,ptrB,(sizeof(int)*nbr));
}
Don't use a sentinel (-1), store the length.
Then you can use memcpy - hint: copy sizeof(int)*len bytes.
I was trying out an example program to copy an array of integers to
another integer array. Is there another way to do it in a more
efficient way.
Since this is a sample program, I'm not sure how your real program looks like. But as for allocating an array: you can either do it statically (as in your example) or dynamically using e.g. malloc(). In either way, the size of the array is known (either fixed in your source code or indirectly through the size parameter to the malloc call).
So yes, since you should know the size of the array, you can use memcpy() which is more efficient since its implementation is optimized for the architecture it runs on.
BTW: an exception could be a library that allocates the memory for you and does not provide back the length of the array. But I never came across such a situation...

Resources