I've looked through topics of similar kind, but didn't find a solution for my problem. I've got a struct like
typedef struct {
int number;
char *string;
} mystruct;
//Then define a pointer to the struct:
mystruct *data;
// Allocate memory:
data = malloc(sizeof(mystruct));
//Assign some number, let's say 5:
(*data).number = 5;
//So far ok, works (checked: 5 can be retrieved from the struct somewhere else) but:
strcpy((*data).string = "Hello!");
//This line fails with segmentation fault.
I don't understand why? Can somebody please explain what I'm doing wrong?
As mentioned in the comments, the problem with your attempted strcpy call is that your destination (the string member of your data) isn't a pointer to valid memory. (I am assuming that your invalid syntax, strcpy((*data).string = "Hello!") is a typo, and that your real code has something like strcpy((*data).string, "Hello!") – otherwise, it won't even compile, so you won't get a segmentation fault.)
There are several approaches to fix this, depending on what you actually want to happen. First, as also mentioned in the comments, you can just copy the pointer to the destination, like this1:
data->string = "Hello!";
However, this may not be what you want, because, if the source is not actually a literal, but a modifiable string, then, after that assignment, any changes to the source will also apply to your copy.
If you want a copy of the source data, you will need to allocate sufficient space for it, then call strcpy; like this:
#include <stdlib.h> // For malloc
const char* src = "Hello!";
data->string = malloc(strlen(src) + 1); // Add 1 for the required nul-terminator
strcpy(data->string, src);
However, the strdup function2 does the job of the above malloc and strcpy calls in one fell swoop:
data->string = strdup("Hello!");
In each of the above two cases, be sure to call free(data->string) when you're finished.
1 Note that you can use the "member access through pointer" (->) operator, rather than dereferencing and then using the . operator: data->number = 5 is equivalent to your (*data).number = 5.
2 Some compilers/platforms may not support the strdup function, but it is part of the ISO C Standard from C23
As other users mentioned, you need to allocate space for the string.
I would use a flexible array member and have only one allocation for the struct and string.
typedef struct {
int number;
char string[];
} mystruct;
mystruct *create(const char *str)
{
mystruct *ms = NULL;
if(str)
{
ms = malloc(sizeof(*ms) + strlen(str) + 1);
if(ms)
{
strcpy(ms -> string, str);
ms -> number = 0;
}
}
return ms;
}
int main(void)
{
mystruct *ms = create("Hello");
if(ms)
{
printf("ms -> string = `%s`\n", ms -> string);
}
free(ms);
}
I am not sure to understand this line
strcpy((*data).string = "Hello!");
Do you mean
strcpy((*data).string, "Hello!");
I believe the issue is that your struct contain a pointer char * string that doesn't point to a valid allocated memory.
You can try multiple solutions
Have struct with predefined size
typedef struct {
int number;
char string[100];
} mystruct;
You can allocate memory for the string during the initialization
data = malloc(sizeof(mystruct));
data->string = malloc(sizeof(char) *100));
Related
We have pointers inside a struct, do we need to initialize the pointers inside the struct?
I have tried the code below, include this sentence below or not, the code all run well.
(Could some experts give help here? and I read some code, and found seems sometimes initialized, sometimes not, so confused and search/ask here.)
The answer in this link seems not mentioned initialize this pointer inside struct. initializing-a-member-of-a-structure-with-pointers-c
#include "stdio.h"
#include "stdlib.h"
struct part{
int num;
char *name;
};
int main()
{
struct part *p = (struct part*)malloc(sizeof(struct part));
//Include this or not, this code all run well
p->name = (char*)malloc(sizeof(char));
p->num = 1;
p->name = "ss";
printf("%d, %s\n", p->num, p->name);
return 0;
}
No, you should not do that, you are creating a memory leak, because you allocate memory and then forget the pointer value and don't free it.
To remove the memory leak:
p->name = malloc(1); //sizeof char is 1 by definition, and cast not needed
free(p->name);
p->name = "ss";
However, if you look at that, it should be clear that allocating 1 byte of memory, then immediately freeing it, is pointless.
Perhaps you want a copy of the string?
const char *initdata = "ss";
p->name = malloc(strlen(initdata)+1);
strcpy(p->name, initdata);
// Remember to free this at some point
Alternatively, you could use initialize with the string literal, but then you should have const char pointer because string literals are read-only:
struct part{
int num;
const char *name;
};
#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.
Can someone explain me why this doesn't work? It appears that the program stops at sprintf(t->tuple[0], "abc"); and I don't know why. Really need help.
int testRemoveMeio(){
int result, i;
struct list_t *list = list_create();
char *tdata[3] = {" ", "2014", "Fixe!"};
struct tuple_t *t = tuple_create2(3, tdata);
struct tuple_t *tdups[4];
struct entry_t *entries[4];
sprintf(t->tuple[0], "abc");
tdups[0] = tuple_dup(t);
entries[0] = entry_create(tdups[0]);
list_add(list, entries[0]);
//extra code similar to above
return 0;
}
Edit:
struct tuple_t {
int tuple_dimension;
char **tuple;
};
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = tuple;
return t;
}
Edited to add another example from the comments:
#include <stdio.h>
#include <string.h>
int main(void)
{
char * s = "ABC";
printf("%s\n",s);
sprintf(s,"DEF");
printf("%s\n",s);
return 0;
}
I pasted the code from your comment into the question. Both that and your original code are failing for the same reason, I think: you're modifying string literals.
It's sad but true that in C, string literals like "hello world" are illegal to modify, yet are assignable to char* without const and without a cast. This makes it easy to screw up, because modifying such a string is undefined behavior, because it may reside in read-only memory in your program.
To fix it, try this:
char tdata[3][6] = {" ", "2014", "Fixe!"};
Or in your second example:
char s[] = "ABC";
This way you are allocating an actual character array with writable storage. But please, always use snprintf() and never sprintf() because the latter is prone to buffer overruns which can crash your program or worse.
You second example is wrong. You should use snprintf(3) (there is no reason to use sprintf in 2014; it is old and dangerous, since it may give a buffer overflow) on some array of char like this:
#include <stdio.h>
int main(void) {
char buf[64];
snprintf(buf, sizeof(buf), "here %s", "ABC");
printf("%s\n",buf);
return 0;
}
You could have used some dynamically allocated memory zone (but then, you should know its size), e.g.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t siz=32;
char* ptr = malloc(siz);
if (!ptr) { perror("malloc"); exit(EXIT_FAILURE); };
snprintf(ptr, siz, "here %s and two is %d", "ABC", 2);
printf("%s\n", ptr);
free (ptr);
return 0;
}
You might use asprintf(3) if your system gives it (e.g. on Linux) like
#define _GNU_SOURCE
#include <stdio.h>
int main (void) {
char* ptrzone = NULL;
asprintf(&ptrzone, "and here %s and one is %d", "ABC", 1);
printf("%s\n", ptrzone);
free (ptrzone), ptrzone = NULL;
}
In serious programs, you often should use the result of snprintf.
Read the documentation of all the functions you are using, so also: perror(3), exit(3), malloc(3), free(3)
You absolutely should read more about C dynamic memory allocation
You should compile with all warnings and debug info (gcc -Wall -g) and learn to use the debugger (gdb) and the memory leak detector valgrind
Some important information is missing as the definition to struct tuple_t and the definition of function tuple_create2. If the error occurs on sprintf(t->tuple[0], "abc") then either t->tuple and/or t->tuple[0] is not correctly initialized/allocated. This former should be an array of at least 1 for the example (but more probably 3 if we look at tdata) strings and the latter to a string buffer (array of char). Check you or provide us the tuple_create2 function.
The way you use sprintf to copy a string is dangerous. On your example this works but if the string to copy contains the '%' character, bad things can happen (% is the character used to specify a format in printf/scanf family of functions. If you want to stay with sprinf use sprintf(t->tuple[0], "%s", "abc") but the simpler is strcpy(t->tuple[0], "abc")
Since you have now added the definition of tuple_create2, I try to answer.
In C, it is up to you to manage the memory. What do you expect from tuple_create2 ?. Your code allocates the space for the "header" (i.e. a struct tuple containing the dimension and an array of strings) and fills it with tuple. The result is a new object which points to the same memory for the data (i.e. the array of strings). This is OK except if you want to modify this array (which seems to be the case). There are 2 things: the array itself (each entry is a pointer to an array of chars - do you want to modify the pointers ?) and the strings (the content of the array of chars). There are several possibilities for this but this depends on you. For instance the function could allocate its own array of pointers and initialize with the existing data:
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = (char **) malloc(sizeof(char *) * tuple_dim);
for(i = 0; i < tuple_dim; i++) // could be replaced by a memcpy
t->tuple[0] = tuple[0];
return t;
}
Then you have to be aware that we copied only pointers. So when you want to modify an element either you simply copy the pointer :
t->tuple[0] = "abc";
or you allocate a new string if you thing it can be modified and you don't want this. I give you an example with "abc" but this is not relevant because "abc" is a constant string which will not be modified. Anyway here is the code (note the use of stdrup which duplicates the string doing a malloc)
t->tuple[0] = strdup("abc");
I have been trying and searching online for too long without any success. I've tried a lot of the suggested answers but nothing has worked for me.
I want to basically send in a char*. It can make it NULL if necessary, but would rather the function modify a char* that already has something.
Example:
char *old = "kit";
function(old){ //does stuff and writes "kat" to old}
printf("new = %s", old);
And
result: new = kat
How can I do this?
Thanks
EDIT:
What I'm currently trying:
calling_function(char *in){
char **old = NULL;
function(&old);
printf("old in calling function is now = %s", *old);
}
function(**old){
<does stuff to get char *another_string = "kat">
*old = another_string;
printf("old is now = %s ", *old);
}
And the result is:
old is now "kat"
old in calling function is now =
and it immediately exist the system with an unspecified error exit(-1) then hangs.
A char* is nothing more an address that points to some bytes which are then interpreted as a string, how to do what you need really depends on what you need to do.
If you want to change a character of the string then a normal char* (non const) pointer will be enough:
void function(char *data) {
data[0] = 'a';
}
If, instead, you want to replace the whole string with another one (possibly of different length), then you will need to pass the address that contains the address, so that you can directly replace it to a new address (that points to a different string):
void function(char **data) {
*data = strdup("newstring");
// strdup is used because a string literal must be considered as const
// otherwise you could invoke UB by modifying the returned string
}
char *value;
function(&value);
An example for passing integer as reference is here: Passing by reference in C
For your example, the value can be changed in the function as below:
char *old = "kit";
/* this will print kit */
printf("old = %s",old);
function(old);
/* this will print kat */
printf("updated old = %s", old);
function(char *old) {
*old = "kat"
}
The line
char *old = "kit";
Can cause trouble because old may point to read-only memory. What you want to do is this:
char old[128]; // or however many you need
function(old){ //does stuff and writes "kat" to old // You can use sprintf for this}
printf("new = %s", old);
Which will allocate old on the stack, where it can be modified.
This will take an existing char * and change it.
char* old = "kit";
void changingFunction( char* pointer ) {
strcpy( pointer, "kat" );
/* or just pointer[1] = 'a'; */
}
changingFunction(old);
printf("new = %s\n", old);
Be careful, though. Remember that you're essentially dealing with an array, and the function doesn't know the size of the array. You always want to stay within the bounds of the array.
Consequently, you should make the function more advanced:
void changingFunction( char* pointer ) {
char * newString = "kat";
strncpy(pointer, newString, strlen(pointer));
}
By using strncpy, you ensure that you stay within your bounds, and since you're dealing with a null terminated char*, you can use strlen to find how big your bounds are.
You can change your function prototype to
void myFunction(char** pold)
and within that function, you are free to write
*pold = "kat";
And call the function like this: myFunction(&old);
But beware; this approach has dangers:
1) You may leak memory as the previous string (i.e. what was old originally pointing to?) may be dangling.
2) *pold = "kat"; assigns read-only memory to *pold. This is because "kat" is probably added to a string literal pool on program startup by the C runtime library. Attempting to modify the string (e.g. (*pold)[0] = 'K') is undefined behaviour. Using *pold = strdup("kat"); circumvents this problem.
I learned something by trying to answer this question! Here's my program that does the operation:
#include <stdio.h>
void f(char* str)
{
strcpy(str, "kat");
}
int main(void) {
// char* str = "kit"; // Initializing like this causes a crash!
char str[4]; // This initialization works
strcpy(str, "kit");
f(str);
printf(str); // Prints "kat"
return 0;
}
There are obvious issues with safety, but what was strange to me is that if you declare str using the commented-out line, the program crashes. I didn't realize that initializing a string literal like that gave you a pointer to read-only memory. That's very non-obvious to me, so I was confused when my little program crashed.
I think it's important to point out that fact first and foremost because it's central to why a naive solution to the problem wouldn't necessarily work. Interesting.
I'm very new to C, I'm getting stuck using the strncpy function.\
Here's an example of what I'm working with:
int main()
{
const char *s = "how";
struct test {
char *name;
};
struct test *t1 = malloc(sizeof(struct test));
strncpy(t1->name, s, sizeof(*s));
t1->name[NAMESIZE] = '\0';
printf("%s\n", t1->name);
}
I have a const char *, I need to set the "name" value of test to the const char. I'm having a really tough time figuring this out. Is this even the correct approach?
Thank you very much!
Well, you allocate the structure, but not the string inside the structure. You need to do that before you copy to it. Even when you do, you will probably overwrite unallocated memory when you attempt to set the string terminator.
And, due to a hight intake ow wine, I just noticed you actually only copy one character, but it's still undefined behavior.
Let's take this one step at a time:
struct test *t1 = malloc(sizeof(struct test));
this allocates space for a struct test; enough space for the pointer name, but not any memory for the pointer to point to. At a minimum, you'll want to do the following:
t1->name = malloc(strlen(s) + 1);
Having done that, you can proceed to copy the string. However, you already computed the length of the string once to allocate the memory; there's no sense in doing it again implicitly by calling strncpy. Instead, do the following:
const size_t len = strlen(s) + 1; // +1 accounts for terminating NUL
t1->name = malloc(len);
memcpy(t1->name, s, len);
In general, try to use this basic pattern; compute the length of strings once when they come into your code, but then use explicit-sized memory buffers and the mem* operations instead of implicit-length strings with str* operations. It is at least as safe (and often safer) and more efficient if done properly.
You might use strncpy if t1->name was a fixed-size array instead (though many people prefer to use strlcpy). That would look like the following:
struct test { char name[MAXSIZE]; };
struct test *t1 = malloc(sizeof *t1);
strncpy(t1->name, s, MAXSIZE - 1);
t1->name[MAXSIZE-1] = 0; // force NUL-termination
Note that the size argument to strncpy should always be the size of the destination, not the source, to avoid writing outside the bounds of the destination buffer.
Without any attempt at completeness or educational direction, here's a version of your code that should work. You can play "spot the difference" and search for an explanation for each one separately on this site.
int main()
{
const char s[] = "how"; // s is an array, const char[4]
struct test{ char name[NAMESIZE]; }; // test::name is an array
struct test * t1 = malloc(sizeof *t1); // DRY
strncpy(t1->name, s, NAMESIZE); // size of the destination
t1->name[NAMESIZE - 1] = '\0'; // because strncpy is evil
printf("%s\n", t1->name);
free(t1); // clean up
}
strncpy() is always wrong
if the result is too long, the target string will not be nul-terminated
if the target is too long (the third argument) , the trailing end will be completely padded with NULs. This will waste a lot of cycles if you have large buffers and short strings.
Instead, you cound use memcpy() or strcpy, (or in your case even strdup() )
int main()
{
const char *s = "how";
struct test {
char *name;
};
struct test *t1
size_t len;
t1 = malloc(sizeof *t1);
#if USE_STRDUP
t1->name = strdup(s);
#else
len = strlen(s);
t1->name = malloc (1+len);
memcpy(t1->name, s, len);
t1->name[len] = '\0';
#endif
printf("%s\n", t1->name);
return 0;
}