Write to double const pointer - c

I want to implement my own string implementation for education. For that I defined a struct named string as follows:
struct string {
const char *const data;
const int length;
};
I use functions to create these string structs and then I assign them to variables.
In order to override the const int length I use the following trick:
*(int *) &result.length = // a int
Now I also want to write to the const char *const data.
As far as I know the first const makes sure that you cant edit the items at which the pointer points, and the second const is that you can't point the pointer to a different memory location. These are properties of an immutable string. So my question is: How can I assign something to the const char *const data like I did to the const int length?
Edit: result as shown above is an instance of the struct string

Form the struct string at its declaration and initialize it.
Also recommend to store the size and not the length and use size_t.
#include <stdio.h>
#include <stdlib.h>
struct string {
const char * const data;
const size_t size;
};
struct string string_copy(const char *src) {
size_t size = strlen(src) + 1;
char *copy = malloc(size);
if (copy) {
memcpy(copy, src, size);
} else {
size = 0;
}
struct string retval = {copy, size}; // ****
return retval;
// or return a compound literal (C99)
return (struct string){ copy, size};
}
void string_free(struct string s) {
free((void*)s.data);
}
int main(void) {
struct string a = string_copy("Hello");
printf("%zu <%s>\n", a.size, a.data);
string_free(a);
// do not use `a` subsequently
return 0;
}
I do not recommend to initialize with a string literal like struct string retval = {"World", 6}; as that limits the usefulness of struct string.
Using a opaque struct has many advantages #Jonathan Leffler that exceed this approach - mainly to keep other code from messing with the struct string.

Related

Declaration of char pointer array without knowing the size at programm start

I have char* Array in a struct that strores song titles. Depending an the album the array size may vary. To be "safe" i defined the array with the size of 99. The code example below shows my problem
Is there a better way (i am sure there is) to solve the array size problem? Somehow creating the array after knowing the exact size of the array?
Thank you.
struct AudioObject{
int count;
const char* band;
const char * titles[99];
};
void fillStruct(AudioObject *a);
void printStruct(AudioObject * a);
void main(void){
AudioObject aO;
fillStruct(&aO);
printStruct(&aO);
}
void fillStruct(AudioObject *a){
a->count=3;
a->band="Iron Maiden";
const char *arr[3]={"The Wicker Man","Ghost of the Navigator","Brave New World"}; // example input
for(int i=0;i<a->count;i++){
a->titles[i]=arr[i];
}
}
void printStruct(AudioObject * a){
printf("Interpret: %s\n",a->band);
printf("Tracks: %d\n",a->count);
for(int i=0;i<a->count;i++){
printf("Title: %s\n",a->titles[i]);
}
}
In case this needs to be read-only, you should let titles be a const char** (or pedantically, const char*const *const) pointing to a separate array such as:
const char* IRON_MAIDEN_TITLES[] = { "...", };
If you do that, you probably wish to store the size of each such title array too, in a separate variable in the struct.
Another option is to skip const and allocate anything dynamically. You can for example make the last member of the struct a flexible array member:
struct AudioObject{
int count;
char* band;
char * titles[];
};
Then when you know the size, you allocate the whole object like this:
size_t number_of_titles = 666;
AudioObject* ao = malloc(sizeof *ao + sizeof(const char* [number_of_titles]));
and then strcpy (ao->titles[0], "something");

How to initialize struct char array?

I'm having trouble initializing a string of characters belonging to a struct. "Expression must have a modifiable lvalue". Do I need to use strcopy? I am not quite sure how to utilize this. Here is my code:
typedef struct {
char name[50];
int attackDamage;
int magicDamage;
int defense;
int power;
int type;
} ITEM;
int main() {
ITEM item[10];
char itemset[5][5] = { 0 };
char champion1[] = "Gnar";
char champion2[] = "Vi";
char champion3[] = "Fizz";
char champion4[] = "Draven";
char champion5[] = "Braum";
item[0].name = "Brutalizer"; // Having issues here
}
EDIT: I did this and seems there isn't anymore errors. Is this the proper way?
strcpy(item[0].name, "Brutalizer");
item[0].name is an array, you cannot assign a pointer (string literal) to an
array. You need to copy the contents, in this case with strcpy for example:
strcpy(item[0].name, "Brutalizer");
Or if the length of the source is not know beforehand, then you can use
strncpy to avoid buffer overflows:
strncpy(item[0].name, "Brutalizer", sizeof item[0].name);
item[0].name[sizeof(item[0].name) - 1] = '\0'; // make sure that it's \0-terminated
or you can use snprintf
snprintf(item[0].name, sizeof item[0].name, "Brutalizer");

populating struct fields in a separate function in C

getting empty values in the struct for this implementation since pointers are freed after call to myFunc ends. what's a good way of populating a struct when its fields are populated in a different function?
struct Poke {
char *name;
char *type;
};
void myFunc(struct Poke *p) {
char fish[5] = "fish";
char *name = fish;
char fillet[8] = "fillet";
char *type = fillet;
p->name = name;
p->type = type;
}
int main () {
struct Poke p;
myFunc(&p);
printf("%s\n", (&p)->name);
printf("%s\n", (&p)->type);
}
So you realize that the memory allocated for fish and fillet is deallocated when the function returns.
So you need memory that persists after the function call.
So you go and do some research and discover C's memory allocation functions like malloc and free. You will also need C's string handling functions like strcpy.
Go read about all the functions you can find in the include headers "stdlib.h" and "string.h".
One way is by allocating memory for the strings inside the structure itself, like this:
#include <stdio.h>
#include <string.h>
struct Poke
{
char name[64];
char type[64];
};
void myFunc(struct Poke *p)
{
char fish[5] = "fish";
char fillet[8] = "fillet";
strncpy(p->name, fish, 64);
strncpy(p->type, fillet, 64);
}
int main ()
{
struct Poke p;
myFunc(&p);
printf("%s\n", p.name);
printf("%s\n", p.type);
return 0;
}
You either need to make the strings static (static const for completeness) so they are persistent:
void myFunc(struct Poke *p)
{
static const char fish[5] = "fish";
char *name = fish;
static const char fillet[8] = "fillet";
char *type = fillet;
p->name = name;
p->type = type;
}
Or you need to define your structure members as char arrays and copy the string in:
struct Poke
{
char name[5];
char type[8];
};
void myFunc(struct Poke *p)
{
strcpy(p->name, "fish");
strcpy(p->type, "fillet");
}
The issue in this particular case is that char fish[5] = "fish"; creates a local variable and copies the string "fish" into it. So assigning char *name = fish; then p->name = name; stores the address of this local variable in your struct (and the same goes for p->type).
You can avoid this by directly storing the addresses of the string literals:
char *name = "fish";
char *type = "fillet";
And on a somewhat unrelated note, you don't need to dereference the address of p here:
printf("%s\n", (&p)->name);
printf("%s\n", (&p)->type);
The following is sufficient:
printf("%s\n", p.name);
printf("%s\n", p.type);

Dynamic memory allocation of a structure

I need to write a program in which is structure with two fields: integer and string. Next I need to write a function which dynamically allocates this structure and takes int and string as parameters to pass them down to allocated structure. This function will also return pointer to newly made structure. Second element of this program should be function which takes struct pointer as parameter, then prints all of the fileds on screen and then free memory of struct. This is the best I could come up with.
#include <stdio.h>
#include <stdlib.h>
struct str{
int num;
char text[20];
};
struct str* return_address(int *num, char *text){
struct str* new_struct=malloc(sizeof(struct str));
new_struct->num=num;
new_struct->text[20]=text;
return new_struct;
};
void release(struct str* s_pointer){
printf("%d %s", s_pointer->num, s_pointer->text);
free(s_pointer);
};
int main()
{
struct str* variable=return_address(1234, "sample text");
release(variable);
return 0;
}
Your array is very small, also it's not dynamic at all. If you are allocating using malloc() anyway, why not allocate everything dynamically?
You cannot assign to an array.
The num member, which I suppose is meant to store the length of the "string", is being assigned a pointer, which is not what you apparently want. And also, the behavior is only defined in very special circumstances when you assign a pointer to an integer, the compiler should be warning you unless you turned off warnings.
Perhaps you want this,
struct string {
char *data;
int length;
};
struct string *
allocate_string(int length, const char *const source)
{
struct string *string;
string = malloc(sizeof *string);
if (string == NULL)
return NULL;
string->length = strlen(source);
// Make an internal copy of the original
// input string
string->data = malloc(string->length + 1);
if (string->data == NULL) {
free(string);
return NULL;
}
// Finally copy the data
memcpy(string->data, source, string->length + 1);
return string;
}
void
free_string(struct string *string)
{
if (string == NULL)
return;
free(string->data);
free(string);
}

Accessing information from nested struct passed to function

I have the following code:
struct wordPair {
char* englishWord;
char* foreignWord;
};
struct dictionary {
struct wordPair ** data;
int nbwords;
int size;
};
Say I have struct dictionary *dictionaryPtr filled with some data, and I pass it to the following function:
char* dictionary_translate( struct dictionary* d,
const char* const english_word,
const char* const foreign_word)
Within the function dictionary_translate, how can I access the data from the struct wordPair that is nested within the passed struct? I need the function to return a strdup of either englishWord or foreignWord.
I was trying d->data->englishWord, but this gives me the error "request for member 'englishWord' in something not a structure or union".
UPDATE!
What I need the function dictionary_translate to do is determine if there is a matching word pair that contains one of the words passed to it, and return the strdup of the translation (the other word in the pair). Here is the array of words I have defined:
const char* test_translations[NB_TESTS][NB_COLS] =
{
{"hello", "hola"},
{"cat", "gato"},
{"dog", "perro"},
{"thanks", "gracias"},
{"pants", "pantalones"},
{"shoes", "zapatos"},
};
This is how I'm calling the function in the first test I'm trying, which is when the translate function is passed an English word and is required to return a foreign word:
char* translationPtr = NULL;
for (i = 0; i < NB_TESTS; i++) {
translationPtr = dictionary_translate(dictionaryPtr, test_translations[i][0], NULL);
printf("English Word %s translated: %s\n", test_translations[i][0], translationPtr);
}
Here is the translate function as I have it so far...
char* dictionary_translate( struct dictionary* d,
const char* const english_word,
const char* const foreign_word){
int i;
if (d == NULL) return NULL;
for (i = 0; i < d->nbwords; i++) {
if (strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return NULL;
}
As soon as the program gets to the translation function, it crashes. I can't make sense of the debugger to find out what is going on, but it seems like translationPtr never has a value other than NULL (0x0). I'm new with the debugger, so I'm sure it could tell me more if I knew how to read it.
It isn't entirely clear what your function is to do, but about the simplest implementation that might legitimately work is:
#include <string.h>
struct wordPair
{
char *englishWord;
char *foreignWord;
};
struct dictionary
{
struct wordPair **data;
int nbwords;
int size;
};
extern char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word);
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return 0;
}
I think you should review the design of your struct dictionary. Using a double pointer seems unnecessary (or the reason for using it is not obvious). The only advantage is that you'd have a contiguous array of pointers to struct wordPair, while the actual struct wordPair elements need not be contiguously allocated themselves. The following code is a more orthodox definition, assuming that a contiguous array of struct wordPair is not a problem:
#include <string.h>
struct wordPair
{
char *englishWord;
char *foreignWord;
};
struct dictionary
{
struct wordPair *data;
int nbwords;
int size;
};
extern char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word);
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (strcmp(english_word, d->data[i].englishWord) == 0)
return strdup(d->data[i].foreignWord);
else if (strcmp(foreign_word, d->data[i].foreignWord) == 0)
return strdup(d->data[i].englishWord);
}
return 0;
}
Given the sample test code where one of the arguments to dictionary_translate() is a NULL pointer, the code in the function must be revised not to dereference the argument if it is null. This assumes the double-pointer version of struct dictionary.
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (englishWord != NULL && strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (foreignWord != NULL && strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return 0;
}
d->(*data)->englishWord
Should compile.

Resources