c structs, pointer and memory allocation for fields - c

Suppose the following code:
struct c {
char* name;
};
int main(int argc, char *argv[]) {
struct c c1;
c1.name = "Ana";
printf ("%s\n",c1.name);
return 0;
}
My first reaction would have been to think that I needed to allocate some space, either on the heap, or by an explicit char name[] = "Anna", but my example above works. Is the compiler just storing that string in the Data segment and pointing to it? In other words, is that like doing a
struct c {
char* name = "Ana";
};
Thanks.

struct c c1;
c1.name = "Ana";
You don't have allocate memory here because you are making the pointer c1.name point to a string literal and string literals have static storage duration. This is NOT similar to:
char name[] = "Anna";
Because in this case memory is allocated to store the sting literal and then the string literal "Anna" is copied into the array name . What you do with the struct assignment c1.name = "Ana" is similar to when you do:
char *name = "Anna";
i.e. make the pointer point to a string literal.

I am new to C but from what I think this could be just the same as
char *cThing;
cThing = "Things!";
where printf("%s\n", cThing); would then print "Things!", except you're declaring the pointer in a struct.

Related

Store char variables in other char variables in C

I am trying to do the following, create a multy-charr array with other char variables.
char data_info_1[] = "Wellcome.";
char data_info_2[] = "Please";
char data_info_3[] = "If";
int size_line= sizeof(data_info_1)/sizeof(data_info_1[0]);
char data_info[3][size_line]={{data_info_1},{data_info_2},{data_info_3}};
One solution would be the following one, but I am not interested in just putting the string right in the data_info variable
char data_info[3][size_line]={{"Wellcome"},{"Please"},{"If"}};
Could you please explain me why the first thing that I have writen is not valid. And if there is a solution to my problem.
Thanks.
To answer your question, neither of your solutions is correct, you can't initialize a 2D array of chars like that.
The second option would be valid if it wasn't a variable sized array, i.e.
char data_info[3][10]={"Wellcome", "Please" ,"If"};
^
Valid -> fixed size
Assignments like those would be possibe if you had an array of pointers:
char *data_info[] = {data_info_1, data_info_2, data_info_3}; //1
Or
const char *data_info[] = {"Wellcome", "Please", "If"}; //2
But these may not be what you need.
Option 1 will contain pointers to the original strings, any changes made to them through those pointers will be reflected in the original strings.
Option 2, the pointers are being initialized with string literals and those can't be changed, that's why I added the const qualifier as a metter of safety.
If neither of these constrains work for you, you'll need to copy the strings with something like strcpy, strncpy or better yet memcpy:
#include <string.h>
//...
memcpy(data_info[0], data_info_1, sizeof data_info_1);
memcpy(data_info[1], data_info_2, sizeof data_info_2);
memcpy(data_info[2], data_info_3, sizeof data_info_3);
Arrays may not be initialized by arrays. You may initialize a character array with string literals as you did in this declaration
char data_info[3][size_line]={{"Wellcome"},{"Please"},{"If"}};
Relative to your case you could declare an array of pointers to char like for example
char * data_info[] = { data_info_1, data_info2, data_info3 };
Some remarks:
you do not need to divide by sizeof char becuse it is by definition 1
You can only use constant expressions when defining or initializing global variables char data_info[3][sizeof(data_info_1)];
To "store" one char array in other you need to copy it. Initialization will not work as you cannot assign the arrays.
#include <string.h>
char data_info_1[] = "Wellcome.";
char data_info_2[] = "Please";
char data_info_3[] = "If";
char data_info[3][sizeof(data_info_1)];
void foo(void)
{
strcpy(data_info[0], data_info_1);
strcpy(data_info[1], data_info_2);
strcpy(data_info[2], data_info_3);
}
only structs or unions can be assigned. So you can wrap array into the struct and the assignment or initializations will copy the whole array.
struct stringWR
{
char str[50];
};
struct stringWR data_info_1 = {"Wellcome."};
struct stringWR data_info_2 = {"Please"};
struct stringWR data_info_3 = {"If"};
struct stringWR data_info[3];
void foo(void)
{
data_info[0] = data_info_1;
data_info[1] = data_info_1;
data_info[2] = data_info_1;
}
void bar(void)
{
struct stringWR data_info[3] = {data_info_1, data_info_2, data_info_2};
}

String vs String Literal: Direct assignment or strcpy/strncpy?

I think I have some issue understanding string and string literal.
This is what I learned from my class, when passing to a function, const char * indicates this is a string literal, while char * indicates a string.
Suppose I have a struct declaration:
struct node{
char *name;
struct node *next;
};
and a function, this is the function I want to implement:
void load_buffer(struct node *input_node, char *input_name);
This function is supposed to assign input_name to the struct's member name.
My confusion comes from here. Within the body of load_buffer, should I write:
input_node->name = input_name;
Or I should use strcpy/strncpy to do this?
strcpy(input_node->name, input_name);// Suppose it's safe in this case.
To summarize, I am not sure if I should use direct assignment or strcpy family functions to assign a string/string literal to the member of my struct.
Thanks for help. :)
In case of pointer assignment, pointers in each node will point to same location. Thus nodes will be always pointing to updated value. If you are intended to make each node to contain different input then this approach does not suit your requirement.
input_node->name = input_name;
In case of strcpy, pointers in each node will point to different location. Before to that you need to create memory for each pointer.
input_node->name = malloc(strlen(input_name)+1); //Allocate memory first.
strcpy(input_node->name, input_name);// Suppose it's safe in this case.
To visualize:
... when passing to a function, const char * indicates this is a string literal, while char * indicates a string.
Not exactly. const char * declares that the function will not try to modify the string. So it is perfectly suited for string litteral because they cannot be modified.
For your question, the answer is it depends on your real requirements. But simply storing the passed pointer if dangerous if the struct can persist after the function and if the string can be changed in the caller. Let us look at the following code:
void load_buffer(struct node *input_node, const char *input_name) {
input_node->name = name;
}
struct node nodes[2];
char buf[4];
const char *data[] = { "foo", "bar"};
for (int i=0; i<2; i++) {
strcpy(buf, data[i]); // suppose it is read from somewhere (file, stdin, socket)
load_buffer(node + i, buf);
}
Both node objects will have their name member pointing to the string buf from caller and will both point to "bar" (the content of buf at the end of the loop)!
If you want to keep the value of the string at call time, you should copy it in allocated memory:
void load_buffer(struct node *input_node, const char *input_name) {
input_node->name = strdup(name); // allocation errors should be tested...
}
But you should then free the name member, when the node is no longer in use...
First to address some terminology:
this is a string literal: "I am a string literal"
this is a type: char* (aka pointer to char)
this is also a type: const char* (aka pointer to constant char)
this is the declaration of a variable of type char*: char* str
this is the declaration of a variable of type const char*: const char* cstr
A pointer is not a string literal. A pointer can point to string literal, an array, just to a single element or can be null.
In C a string is a null-terminated char array.
In C you can assign a char* variable to a string literal, but modifying the string literal is illegal, so it is strongly advised to never do that. The reason why this is allowed are historical.
char* a = "asd"; // allowed, but frowned upon
// a points to a string literal, so we can say a is a string
// a is not a string literal
char b = 'x';
char* c = &b;
// c points to a single char
// we cannot say c is a string
char d[10] = "asd";
// d is a char array. Its content is a string, so we can say d is a string.
// d is not a string literal
// the string literal is copied into the array d
char* e = d; // or equivalent char* e = &d[0];
// e points to a string
char f[4] = {'a', 's', 'd', '\0'};
// f is an array. Its content is a string, so we can say f is a string
char* g = f;
// g points to a string. We can say g is a string
char h[3] = {'a', 's', 'd'};
// h is an array. Its content is NOT a string, because the char array is not null terminated
char* i = h;
// i is not a string
And now go through all the above once more, but not replace char with const char and all the comments still stand (except that `const char* a = "asd" is now ok).
And now to the problem at hand.
There are two scenarios:
Each node has its own string and "owns" that string. Each node is responsible for allocating memory for the string and freeing that memory. The string lives as long as the node lives. In this case use malloc and strcpy to create a string for each node. Don't forget to free the string when the node is destroyed. This is the most common scenario and probably what you want.
A node doesn't own its own string, but rather points to an external string. It is not allowed to neither allocate nor free memory for that string. There is another entity responsible for managing the lifetime of that string and making sure the string is alive at least as the node is alive. The string can outlive the node without a memory leak.
For example consider this scenario:
there is a list R of string resources. This list owns those resources. This list would use scenario 1
we need to keep two different sort orders of R. So we have two lists A and B that would use scenario 2: each node in A and B just points to a string of R.

Assigning a string to a pointer in a struct

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char *forename;
char *surname;
int age;
};
void change_struct(struct Person *person, char *forename, char *surname,
int age);
void print_struct(struct Person *person);
int main(void)
{
struct Person person1;
person1.forename = malloc((strlen("Max") + 1) * sizeof(char));
if (!person1.forename) {
exit(EXIT_FAILURE);
}
strcpy(person1.forename, "Max");
person1.surname = malloc((strlen("Mustermann") + 1) * sizeof(char));
if (!person1.surname) {
exit(EXIT_FAILURE);
}
strcpy(person1.surname, "Mustermann");
person1.age = 35;
print_struct(&person1);
change_struct(&person1, "Hans", "Bauer", 45);
print_struct(&person1);
free(person1.forename);
free(person1.surname);
exit(EXIT_SUCCESS);
}
void change_struct(struct Person *person, char *forename, char *surname,
int age)
{
person->forename = realloc(person->forename,
(strlen(forename) + 1) * sizeof(char));
if (!person->forename) {
exit(EXIT_FAILURE);
}
strcpy(person->forename, forename);
person->surname = realloc(person->surname,
(strlen(surname) + 1) * sizeof(char));
if (!person->surname) {
exit(EXIT_FAILURE);
}
strcpy(person->surname, surname);
person->age = age;
}
void print_struct(struct Person *person)
{
printf("%s\n", person->forename);
printf("%s\n", person->surname);
printf("%d\n", person->age);
}
When assigning a string to a pointer in a struct is it well-defined behaviour if I would do
person1.forename = "Max";
person1.surname = "Mustermann";
in main() initially instead of using malloc() and strcpy()?
NOTE: (Of course in this specific case I would need to also change the realloc() calls in change_struct() since it is undefined behaviour when realloc() receives a non- malloc(), calloc(), or realloc() created pointer.)
If dynamic memory allocation should be required could you give an explanation why?
As long as you don't want to modify the contents,
person1.forename = "Max";
person1.surname = "Mustermann";
are perfectly valid.
In this case, person1.forename will be a pointer to the string literal and any attempt to modify the contents will result in undefined behaviour.
That said,
for print_struct() function, you don't need to pass a pointer to the structure.
sizeof(char) is guaranteed to produce 1 in C. Using it for multiplication (to get the size in malloc())is redundant, can be omitted easily.
person1.forename = "Max";
person1.surname = "Mustermann";
You are making your pointers point to string literals , so make a note that string literls are read-only. So once you have the above initialization you can't modify the string the pointer is pointing to which is not the case with the memory allocated by malloc() and family functions.
Since you are allocating memory explicitly you can use it to read and write.So you need dynamic memory allocation here if you wish to modify the string the pointers are pointing to
"Max" is a null-terminated read-only string literal in C; using a const char* to point to the first character is well-defined and idiomatic.
You ought to change the types of your structure elements to const char* if you are going to populate it in such a manner as the behaviour on amending a read-only literal is undefined.
Of course, you can set forename &c. to point to another character string.
It is a bad approach. In this case you may not apply function realloc inside function change_struct because string literals have static storage duration. They are not allocated dynamically
This function is a general-purpose function and it can accept arguments for parameters forename and surname of various kind not only string literals.
For example the function can be called like
char name[] = "Hans";
change_struct(&person1, name, "Bauer", 45);
Or even like
if ( some_condition )
{
char name[] = "Hans";
change_struct(&person1, name, "Bauer", 45);
}
In this case any changing of name will also change the string pointed to by data member forename of an object of the type of the structure. Moreover if array name will be defined in some local scope as it is shown in the example with the if statement then the pointer will be even invalid.

String assignment in C

I'm new to C. The string assignment in the following code works:
#include<stdio.h>
int main(void){
char str[] = "string";
printf("%s\n",str);
}
But doesn't work in the following,even I give the index number to the name[]:
#include <stdio.h>
int main(void){
struct student {
char name[10];
int salary;
};
struct student a;
a.name[10] = "Markson";
a.salary = 100;
printf("the name is %s\n",a.name);
return 0;
}
Why does this happen?
You can't assign to an array. Two solutions: either copy the string:
strcpy(a.name, "Markson");
or use a const char pointer instead of an array and then you can simply assign it:
struct {
const char *name;
/* etc. */
};
a.name = "Markson";
Or use a non-const char pointer if you wish to modify the contents of "name" later:
struct {
char *name;
}
a.name = strdup("Markson");
(Don't forget to free the memory allocated by strdup() in this latter case!)
You cannot do this
a.name[10] = "Markson";
You need to strcpy the string "Markson" to a.name.
strcpy declaration:
char * strcpy ( char * destination, const char * source );
So, you need
strcpy( a.name, "Markson" );
char str[] = "string"; is a declaration, in which you're allowed to give the string an initial value.
name[10] identifies a single char within the string, so you can assign a single char to it, but not a string.
There's no simple assignment for C-style strings outside of the declaration. You need to use strcpy for that.
because in one case you assigning it in a declaration and in the other case you are not. If you want to do the equivalent write:
struct student a = {"Markson", 0};

string literal in c

Why is the following code illegal?
typedef struct{
char a[6];
} point;
int main()
{
point p;
p.a = "onetwo";
}
Does it have anything to do with the size of the literal? or is it just illegal to assign a string literal to a char array after it's declared?
It doesn't have anything to do with the size. You cannot assign a string literal to a char array after its been created - you can use it only at the time of definition.
When you do
char a[] = "something";
it creates an array of enough size (including the terminating null) and copies the string to the array. It is not a good practice to specify the array size when you initialize it with a string literal - you might not account for the null character.
When you do
char a[10];
a = "something";
you're trying to assign to the address of the array, which is illegal.
EDIT: as mentioned in other answers, you can do a strcpy/strncpy, but make sure that the array is initialized with the required length.
strcpy(p.a, "12345");//give space for the \0
You can never assign to arrays after they've been created; this is equally illegal:
int foo[4];
int bar[4];
foo = bar;
You need to use pointers, or assign to an index of the array; this is legal:
p.a[0] = 'o';
If you want to leave it an array in the struct, you can use a function like strcpy:
strncpy(p.a, "onetwo", 6);
(note that the char array needs to be big enough to hold the nul-terminator too, so you probably want to make it char a[7] and change the last argument to strncpy to 7)
Arrays are non modifiable lvalues. So you cannot assign to them. Left side of assignment operator must be an modifiable lvalue.
However you can initialize an array when it is defined.
For example :
char a[] = "Hello World" ;// this is legal
char a[]={'H','e','l','l','o',' ','W','o','r','l','d','\0'};//this is also legal
//but
char a[20];
a = "Hello World" ;// is illegal
However you can use strncpy(a, "Hello World",20);
As other answers have already pointed out, you can only initialise a character array with a string literal, you cannot assign a string literal to a character array. However, structs (even those that contain character arrays) are another kettle of fish.
I would not recommend doing this in an actual program, but this demonstrates that although arrays types cannot be assigned to, structs containing array types can be.
typedef struct
{
char value[100];
} string;
int main()
{
string a = {"hello"};
a = (string){"another string!"}; // overwrite value with a new string
puts(a.value);
string b = {"a NEW string"};
b = a; // override with the value of another "string" struct
puts(b.value); // prints "another string!" again
}
So, in your original example, the following code should compile fine:
typedef struct{
char a[6];
} point;
int main()
{
point p;
// note that only 5 characters + 1 for '\0' will fit in a char[6] array.
p = (point){"onetw"};
}
Note that in order to store the string "onetwo" in your array, it has to be of length [7] and not as written in the question. The extra character is for storing the '\0' terminator.
No strcpy or C99 compund literal is needed. The example in pure ANSI C:
typedef struct{
char a[6];
} point;
int main()
{
point p;
*(point*)p.a = *(point*)"onetwo";
fwrite(p.a,6,1,stdout);fflush(stdout);
return 0;
}

Resources