String assignment in C - 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};

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};
}

How to write to char* from a function in C

I am struggling to write a char* passed as an argument. I want to write some string to char* from the function write_char(). With the below code, I am getting a segmentation fault.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
int main(){
char* test_char;
write_char(test_char);
printf("%s", test_char);
return 0;
}
You have two problems (related to what you try to do, there are other problems as well):
Arguments in C are passed by value, which means that the argument variable (c in your write_char function) is a copy of the value from test_char in the main function. Modifying this copy (like assigning to it) will only change the local variables value and not the original variables value.
Assigning to a variable a second time overwrites the current value in the variable. If you do e.g.
int a;
a = 5;
a = 10;
you would (hopefully) not wonder why the value of a was changed to 10 in the second assignment. That a variable is a pointer doesn't change that semantic.
Now how to solve your problem... The first problem could be easily solved by making the function return a pointer instead. And the second problem could be solved by copying the string into the memory instead of reassigning the pointer.
So my suggestion is that you write the function something like
char *get_string(void)
{
char *ptr = malloc(strlen("some string") + 1); // Allocate memory, +1 for terminator
strcpy(ptr, "some string"); // Copy some data into the allocated memory
return ptr; // Return the pointer
}
This could then be used as
char *test_string = get_string();
printf("My string is %s\n", test_string);
free(test_string); // Remember to free the memory we have allocated
Within the function
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
c = "some string";
}
the parameter c is a local variable of the function. Changing it within the function does not influence on the original argument because it is passed by value. That is the function deals with a copy of the original argument.
You have to pass the argument by reference through pointer to it.
Also the function has a memory leak because at first the pointer was assigned with the address of the allocated memory and then reassigned with the address of the first character of the string literal "some string".
If you want to create a copy of a string literal then what you need is the following
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void write_char( char **s )
{
const char *literal = "some string";
*s = malloc( strlen( literal ) + 1 );
if ( *s ) strcpy( *s, literal );
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
if ( test_char ) puts( test_char );
free( test_char );
}
The program output is
some string
Do not forget to allocate dynamically a character array that is large enough to store also the terminating zero of the string literal.
And you should free the allocated memory when the allocated array is not needed any more.
If you want just to initialize a pointer with the address of a string literal then there is no need to allocate dynamically memory.
You can write
#include <stdio.h>
void write_char( char **s )
{
*s = "some string";
}
int main( void )
{
char *test_char = NULL;
write_char( &test_char );
puts( test_char );
}
In C, you'll need to pass a pointer to a pointer. Your malloc call is trying to change the value of the variable that's being passed in, but it's actually only a copy. The real variable you pass in will not be changed.
Also, the way that you copy a string into a char* is not using assignment... Here's some revised code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void write_char(char** c){
size_t len = strlen("some string");
*c = (char*)malloc(len + 1); // + 1 for null termination
strncpy(*c, "some string", len);
}
int main(){
char* test_char;
write_char(&test_char);
printf("%s", test_char);
return 0;
}
String assignment in C is very different from most modern languages. If you declare a char * and assign a string in the same statement, e.g.,
char *c = "some string";
that works fine, as the compiler can decide how much memory to allocate for that string. After that, though, you mostly shouldn't change the value of the string with =, as this use is mostly for a constant string. If you want to make that especially clear, declare it with const. You'll need to use strcpy. Even then, you'll want to stay away from declaring most strings with a set string, like I have above, if you're planning on changing it. Here is an example of this:
char *c;
c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
If you're passing a pointer to a function that will reallocate it, or even malloc in the first place, you'll need a pointer to a pointer, otherwise the string in main will not get changed.
void myfunc(char **c) {
char *tmp = realloc(*c, 32 * sizeof(char));
if(tmp != NULL) {
*c = tmp;
}
}
char *c = malloc(16 * sizeof(char));
strcpy(c, "Hello, world\n");
myfunc(&c);
char* test_char="string"; // initialize string at the time of declaration
void write_char(char* c){
c = (char*)malloc(11*(sizeof(char)));
}
int main(){
char* test_char="strin";
write_char(test_char);
printf("%s", test_char);
return 0;
}

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.

c structs, pointer and memory allocation for fields

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.

C -- Basic Struct questions

So I'm trying to learn C right now, and I have some basic struct questions I'd like to clear up:
Basically, everything centers around this snippet of code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME_LEN 127
typedef struct {
char name[MAX_NAME_LEN + 1];
unsigned long sid;
} Student;
/* return the name of student s */
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct
return s->name; // returns the 'name' member of a Student struct
}
/* set the name of student s
If name is too long, cut off characters after the maximum number of characters allowed.
*/
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct | 'name' is a pointer to the first element of a char array (repres. a string)
s->name = name;
}
/* return the SID of student s */
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct
return s->sid;
}
/* set the SID of student s */
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID
s->sid = sid;
}
I've commented up the code in an attempt to solidify my understanding of pointers; I hope they're all accurate.
So anyway, I have a feeling that setName and setStudentID aren't correct, but I'm not exactly sure why. Can someone explain? Thanks!
EDIT:
char temp
int i;
for (i = 0, temp = &name; temp != '\0'; temp++, i++) {
*((s->name) + i) = temp;
You are not copying the full name array with this
void setName(Student* s, const char* name) {
s->name = name;
}
try this
strcpy(s->name,name);
to copy this string to your structs array. You cant simply assign a pointer argument to an array variable like you have currently. You need to copy each character pointed to by name to the elements of your array s->name. This is what strcpy will do - it copies elements from the source to the destination until it finds a terminating null character.
EDIT: Alternatively you could use strncpy as suggested in a comment. Check this question and its answers to see why some people think this is a good idea Why should you use strncpy instead of strcpy?
s->name = name;
Since s->name is an array, you can't assign to it (it's not a modifiable lvalue) - it should be a compiler error. You'll have to strcpy or memcpy into it, but make sure name isn't too large.
setStudentID is perfectly fine, but setStudentName isn't. You're trying to assign a char* to an array, and that doesn't work. You'll have to use a function that copies it element-wise, like strcpy.

Resources