C - Printing a dynamic array - c

I am creating a program that modifies a dynamic array. It must initialize the array and be able to insert into it. I have been unable print the array after in order to test it, how would I go about this?
Piece of relevant code:
typedef struct {
char first;
char second;
} name;
typedef struct {
int number;
name name;
} data;
/*points to array, number allocated, number used*/
typedef struct {
data *info;
size_t numof;
size_t numused;
} list;
void init(list *l) {
l->data = malloc(sizeof(l) * l->numof);
l->numused = 0;
l->numof = 2;
}
int insert(list *l, const data *dat) {
if (l->numused == l->numof) {
l->numof *= 2;
l->data = (int *)realloc(l->data, l->numof * sizeof(int));
}
l->data[l->numused++] = *dat;
return 0;
}
int main(void) {
int i;
list l;
data list1;
/*example info for testing*/
list.number = 1234;
strcpy(list1.name.first, "abc");
strcpy(list1.name.second, "xyz");
init(&l);
insert(&l, list1);
/*runs through array elements to print*/
for (i=0; i < ((int)sizeof(&l)) /(int)sizeof(&l); i++) {
printf("%s\n", list1);
}
return 0;
}
Edit: I just need to know how to print the array to see if I'm doing it correctly, the code above will have errors as I had been messing around trying to figure it out.

strcpy(list1.name.first, "abc");
strcpy(list1.name.second, "xyz");
These both will invoke undefined behaviour as first and second are declared as char variables , and you copy string literals to them .
You need to declare both of them as character arrays .
And this -
for (i=0; i < ((int)sizeof(&l)) /(int)sizeof(&l); i++) {
printf("%s\n", list1);
}
You try to print struct variable list1 with %s specifier, maybe you tend to print the strings that you wanted to copy. So directly print list1.name.first and list1.name.second in printf with %s specifier.
And the condition -
i < ((int)sizeof(&l)) /(int)sizeof(&l)
The cast is not necessary , and it will yield 1 so, loop will run for 1 time . Change the condition .

In your code, the member of structure name is defined as char. But you are trying to copy a string into it. May be this was a typo. If not you should define them as character array or character pointer. Also in your print statement you are trying to print structure data as string. It should be like -
printf("%s %s\n", list1.name.first, list1.name.second);
Also you assigned value 1234 to list.number. You may have meant list1.number. The parameters in function call of insert is wrong as well. And lastly, you have put l->data in functions init and insert which should be l->info.

Related

Is it possible to create a data type getter for unions (in C language)?

I have an array of pointers to unions:
typedef union element
{
float f;
int i;
long l;
char c;
char *s;
} element;
typedef struct Array
{
int capacity;
int original_capacity;
int count;
element *elements;
} Array;
My code works, error free! I can append to the array or insert into it at an index, and soon I'll be able to do more. I can also print the entire array out, with an arr_print function:
int main(void){
Array *arr = create_array(7);
arr_print(arr);
arr_append(arr, new_element_s("String 1"));
arr_print(arr);
arr_insert(arr, new_element_s("String2"), 0);
arr_insert(arr, new_element_s("add"), 0);
arr_print(arr);
}
Console:
Array count 3 and capacity 7
[add,String2,String 1]
The catch is I can only print the entire array out if the unions are of a single type and I want to be able to expand this capability.
Here is the arr_print function:
void arr_print(Array *arr)
{
printf("Array count %d and capacity %d\n", arr->count, arr->capacity);
printf("[");
for (int i = 0; i < arr->count; i++) //
{
printf("%s", arr->elements[i].s); // SEG FAULT IF MISMATCHED.
if (i != arr->count - 1)
{
printf(",");
}
}
printf("]\n");
}
printf causes a segfault error if the types are not matched.
For example if I add these lines:
arr_insert(arr, new_element_c('a'), 1);
arr_insert(arr, new_element_i(1), 1);
arr_print(arr); // This breaks
I get a seg fault because a char or int is not a %s.
So, what I'm looking for is some way to tell the type of data the union contains (and then utilize a switch or something). In pseudocode I might do something like this
// typeof(arr->elements[i].data) == 'string' ? printf("%s", arr->elements[i].data)
// typeof(arr->elements[i].data) == 'int' ? printf("%d", arr->elements[i].data)
If there's not a native way, is there a function I could write that could parse the data/infer what it is, or is there some library that can do this? Or is this something you're just expected to know? I suppose I could make a struct wrapper for the union with a field that tells the type, but I don't want to if I don't have to.

Incorrect values assigned to a member of a structure

I have a structure
struct services {
char *actived[50];
char *disactived[50];
};
and a function :
void servicesInfo(struct services *services_i) {
FILE *fp;
int status;
char *tmp;
const char *actived_cmd ="/usr/sbin/service --status-all | awk '/[+]/{ print $4 }'" ;
fp = popen(actived_cmd, "r");
int i=0;
while (fgets(tmp, 1024, fp)){
printf("service %s\n", tmp);
(services_i->actived)[i]=tmp;
i++;
}
status = pclose(fp);
}
when i call the function
struct services services_i;
servicesInfo(&services_i);
all is fine and all services printed, but if this code
for (i = 0; i < 20; ++i)
{
printf("service i=%d %s\n",i,services_i.actived[i] );
}
print just the last value (uvrandom)
You need to read up on C pointer and memory allocation. There are two misunderstandings here:
tmp is not, as it is written, a string buffer. It is just a string pointer. It can only be assigned to point to strings that are allocated somewhere else, and not contain the string itself.
You are just copying the pointer to actived (which by the way probably should be spelled activated). This means that all actived pointers all point to the same as tmp does, which is always the same, since tmp is never changed (and also has uninitialized value).
I suggest you use tmp = malloc(1024). Don't forget to use free(services_i.actived[i]) when you don't need them anymore.
I also suggest making an array of structs instead of a struct of arrays, to make it more logical.
Here is some example code of how to assign a value to structure:
#include <stdio.h>
struct date { /* global definition of type date */
int month;
int day;
int year;
};
main()
{
struct date today;
today.month = 10;
today.day = 14;
today.year = 1995;
printf("Todays date is %d/%d/%d.\n", \
today.month, today.day, today.year );
}

creating function to add word into dictionary

I want to create function that adds words into dictionary
so far i made this
void addWord(char **dictionary,int *dictionarySize,int *wordsInDictionary,char *word){
if(dictionary == NULL)
{
*dictionary = (char *)malloc(sizeof(char*)*(*dictionarySize));
}
else
{
if(*wordsInDictionary==*dictionarySize)
{
*dictionary = (char *)realloc(dictionary,sizeof(char*)*(*dictionarySize)*2);
(*dictionarySize)*=2;
}
}
dictionary[*wordsInDictionary]=word;
(*wordsInDictionary)++;
}
in main() i have
int i;
int dictSize = 1;
int wordsInDict = 0;
char *word;
char *dictionary;
dictionary=NULL;
then i want to print all words in dictionary , but here i get warning that %s is expecting char* but it is int
printf("Stats: dictsize: %d, words in dict: %d\n", dictSize,wordsInDict);
for(i=0;i<wordsInDict;i++)
{
printf("%d. %s\n",i, dictionary[i]);
}
it also gives me errors when i try to add words
i use this call to add words
addWord(&dictionary,&dictSize,&wordsInDict,word);
In your addWord function, dictionary will never be NULL.
And that's only the start of your problems. Because you want dictionary to be an array of arrays, which mean you need to declare it as a pointer to a pointer (if you want it to be dynamic). However, you declare it as just a (single) pointer. It's in the main function (or where ever you declare it originally) that you need to declare it as a pointer to a pointer. And you need to initialize it, or it will have an indeterminate value and using it in any way other than initializing it will lead to undefined behavior.
That means your addWord function should take a pointer to a pointer to a pointer, i.e. one more level of indirection. And you need to use the dereference operator to get the original pointer to pointer.
So the addWord function should start like e.g.
void addWord(char ***dictionary, int *dictionarySize, int *wordsInDictionary,char *word){
if(*dictionary == NULL)
{
*dictionary = malloc(sizeof(char*) * (*dictionarySize));
}
...
}
Also note that I don't cast the return of malloc.
Also note that realloc can fail, and then will return NULL, so if you assign the return to the same pointer you reallocate you will loose the original pointer. Always use a temporary pointer for the return-value of realloc and only assign to the real pointer after checking that the reallocation succeeded.
I suggest that you put together the members of the dictionary in one as a structure, rather than having individually.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dictionary {
char **words;//array of char *
int size;
int numOfWords;
} Dictionary;
Dictionary *D_new(void){
Dictionary *dic = malloc(sizeof(*dic));
if(dic){
dic->size = 16;//initial size
dic->words = malloc(dic->size * sizeof(*dic->words));//check omitted
dic->numOfWords = 0;
}
return dic;
}
void D_drop(Dictionary *dic){
int i;
for(i=0;i<dic->numOfWords; ++i)
free(dic->words[i]);
free(dic->words);
free(dic);
}
void addWord(Dictionary *dic, const char *word){
if(dic == NULL){
return ;
}
if(dic->numOfWords == dic->size){
dic->words = realloc(dic->words, sizeof(*dic->words)*(dic->size*=2));//check omitted
}
dic->words[dic->numOfWords++]=strdup(word);//make copy
}
int main(void){
int i;
Dictionary *dictionary = D_new();
addWord(dictionary, "apple");
addWord(dictionary, "banana");
addWord(dictionary, "melon");
printf("Stats: dictsize: %d, words in dict: %d\n",
dictionary->size, dictionary->numOfWords);
for(i=0;i<dictionary->numOfWords;i++){
printf("%d. %s\n", i, dictionary->words[i]);
}
D_drop(dictionary);
return 0;
}

Multiple arrays with malloc

I am initializing a struct called Array which consists of an array of Items and an int to keep track of the number of the Items.
typedef struct anything{
char text[MAXI];
int any;
}Item;
typedef struct array{
Item arr[0];
int size;
}Array;
To initialize the Array, I'm using malloc and returning the pointer.
Array create(){
Array *p1 = malloc(sizeof(Array));
p1->size = 0;
return *p1;
}
The problem I have is that some functions are designed for 2 Arrays, such as intersection:
Array intersection(Array S,Array T){
int i, j;
Array I = create();
for(i=0; i<(S.size); i++){
for(j=0; j<(T.size); j++){
if((compStructs(S.arr[i], T.arr[j])) == true)
add(I, S.arr[i]);
}
}
return I;
}
According to this code, if I were to execute create() twice, I would lose the pointer to the first array. Is there something I can do in the main program to prevent this, or what modifications can I do to the current function?
Edit: Added the add item function:
void add(Array S,Item x){
bool rep = false;
int i = 0;
for(i = 0; i<(S.size); i++){
if(compStructs(x,S.arr[i]) == true)
rep = true;
}
if(rep == false){
Item *p2 = realloc(S.arr, sizeof(Item));
*p2 = x;
(S.size)++;
}
else
printf("The item is already in the set.");
}
My main problem is that I'm not sure how to call two seperate arrays which are to be created at the user's request. The program is in it's build up but currently it looks somehitng like this:
#include "array.h"
Item x;
void arraymenu(){
char inp;
while((inp = getchar())!= '\n'){
printf("a. To Create a new Array\n"
"b. To Add a new Item\n"
"c. To Remove an Item\n"
"d. To Clear all contents of the Array\n"
"e. To Get the size of the Array\n"
"f. To Get a list of the number of elements of your choice\n"
"g. To Check whether the array is empty\n"
"h. To Get the union of two sets\n"
"i. To Get the intersection of two sets\n"
"j. To Get the difference of two sets\n"
"k. To Check if a set is the subset of the other one\n"
"l. To map a function to all Items of an Array\n"
"m. To apply a function to all Items of an Array\n"
"n. To store the Array in a File\n"
"o. To load the Array from a File\n" );
switch(inp){
case 'a' : printf("Array A has been created.");
Array A = create();
break;
case 'b' : printf("Enter any integer, followed by any string.");
scanf("%d", &x.any);
scanf("%s", &x.text);
add(A, x);
break;
case 'c' : printf("Enter the integer and string you wish to remove ");
scanf("%d", &x.any);
scanf("%s", &x.text);
removee(A,x);
break;
}
}
}
Basically, instead of a derefferenced pointer to a variable local to a given function's scope you need to return a pointer (BTW, compiling return *ptr should give a warning when compiling, add -Wall, and don't ignore what the compiler is telling you):
Array *create()
{
Array *a_ptr = malloc(sizeof(*a_ptr));
if (a_ptr == NULL) exit (EXIT_FAILURE);//failed to allocate memory
a_ptr->size = 0;
return a_ptr;
}
To be called like this:
Array *S, *T;
S = create();
T = create();
Now you have 2 arrays ready to play with. Note that you'll need to either dereference these pointers, or use the indirection operator on them always:
(*S).size = 1;
//or
S->size += 123;
You'll also probably want to change intersection to something like:
Array *intersection(Array *S,Array *T)
{
int i, j;
Array *I = create();
for(i=0; i<(S->size); ++i)
{
for(j=0; j<(T->size); ++j)
if(compStructs(S.arr[i], T.arr[j])) add(I, S.arr[i]);
}
}
return I;
}
Of course, once you're done with all of these Array structs, you'll have to free() them, too.
As far as compStructs and add go, I expect you'll have to work on those functions, too. While you're at it, perhaps change the struct to better fit the way you're using it:
typedef struct array
{
Item *arr;
size_t size;//size_t makes more sense here
}Array;
Of course, this in turn requires a bit more work when free-ing the memory, so a generic free function is advisable:
void free_array(Array **a)
{//pointer to pointer
while((*a)->size--) free((*a)->arr+(*a)->size);
free(*a);
*a = NULL;//NULL pointers are safer
}
//call like so:
free_array(&Array_ptr);//yes, address of pointer
And realloc calls should look something like:
realloc(a->arr, (a->size + 1)*sizeof(*(a->arr)));
a->size += 1;
typedef struct array{
int size;
Item arr[];
}Array;
Array *create(int size){
Array *p1 = malloc(sizeof(Array) + size*sizeof(Item));
if(p1)p1->size = size;
//return *p1;//memory leak
return p1;
}

Array of strings in C

I'm trying to create a structure storing strings and I'm getting an error incompatible types when I try and insert as string into the array. This my first time working with a program in C. Could somebody help spot my problem.
This is my implementation of list.c
struct list *init_list(int num) {
struct list *p;
p = malloc(LISTSZ(num));
if(p == NULL)
return(NULL);
p->maxsz = num;
p->sz = 0;
return(p);
}
void debug_list(struct list *p) {
int i;
fprintf(stderr, "\nDynamic List\n\n");
fprintf(stderr, " sz = %d\n", p->sz);
fprintf(stderr, " maxsz = %d\n", p->maxsz);
for(i = 0; i < p->maxsz; i++)
fprintf(stderr," %s\n", (p->item[i]));
}
void prt_list(struct list *p) {
int i;
for(i = 0; i < p->sz; i++)
printf("%s\n", (p->item[i]));
}
int ins_list(char *data, struct list **p) {
struct list *q;
if((*p)->sz == (*p)->maxsz) {
q = realloc(*p, LISTSZ((*p)->maxsz + INCRSZ)); // Problem?
if(q == NULL)
return(-1);
q->maxsz += INCRSZ;
*p = q;
}
(*p)->item[(*p)->sz] = data; // incompatible types in assignment
(*p)->sz ++;
return(0);
}
This is my implementation of list.h
struct list {
int sz;
int maxsz;
char item[][1024]; // Problem?
};
#define INITSZ 5
#define INCRSZ 5
#define LISTSZ(n) ((size_t)(sizeof(struct list) + ((n)-1)*sizeof(char[1024]))) // Problem?
struct list *init_list(int num);
int ins_list(char *data, struct list **p);
void prt_list(struct list *p);
void debug_list(struct list *p);
You have an array of char, yet you're trying to put a char * into it.
I would guess that strncpy will do what you want. Alternatively, declare item as an array of char *.
struct list {
int sz;
int maxsz;
char *item[1024];
};
There more differences between C and C++ than it's commonly admit.
For your error the reason is simple you are trying to assign a pointer (char*) at sz wich is an int.
This kind of assignment generate the incompatible type warning.
Second thing you can't do (a least as far as i know) a partially dynamic array as you do it. In your case you should use at least a malloc and the type of item should be char**. However there is a trick to use only one malloc to create a 2D array.
For the realloc nothing hit me ... What is the compilation error ?
However your code doesn't looks like C code :/
You might need to rebuild it form scratch, because you are here making confusion between lists and 2D arrays ...
I can write some examples of codes if you want but you should probably find a C basics tutorial on google.
Good luke :)
At this line:
(*p)->item[(*p)->sz] = data; // incompatible types in assignment
(*p)->item[(*p)->sz] is an array of 1024 char - you can't assign to arrays with = (arrays are "non-modifiable lvalues").
You just need to do a copy. For a length-safe string copy, I prefer to use strncat():
(*p)->item[(*p)->sz][0] = '\0'; /* Truncate existing string to empty */
strncat((*p)->item[(*p)->sz], data, (sizeof (*p)->item[(*p)->sz]) - 1);

Resources