I am working with a bunch of strings for logging. I want to refactor my code and make a new struct that combines the char, its length and allocated size. The idea is to make my internal string operations smoother and the code nicer to read, whilst assigning each string its own max allocated memory to keep the usage to a minimum but prevent stack overflow. I made this simple example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *str;
int size;
int max;
} Text;
void defText(Text *text, int max)
{
text->str=(char*) malloc(max * sizeof(char));
text->str="";
text->max=max;
}
int main() {
Text *a;
defText(a,50);
a->str="Test all you want";
printf("OUT: %s %zu %lu",a->str,strlen(a->str),sizeof(a->str));
return 0;
}
The function defText initializes and allocates memory. However, when I check the sizeof the char in my struct, I always get 8, no matter what I set in defText. Is this kind of struct handling strings and their properties together even possible? If so, what is wrong here?
There are several problems in your code, this is an example that cleans up these problems:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *str;
// you could use size to keep track of the strlen. That's particularly
// desirable if you find yourself calling strlen "a lot", since that
// function recalculates the length every time it's called
int size;
int max;
} Text;
void defText(Text *text, int max)
{
// no need to cast the return of malloc. In fact, sizeof(char) is defined by
// the standard to be 1 so you could take that out also.
text->str=malloc(max * sizeof(char));
// `=` is not the proper way to write strings in C, you must use strcpy
// or something similar. It looks like here you're simply trying to
// create an empty string.
//text->str="";
// per #JohnBollinger's comment, the best thing to do here to create
// an empty string is simply set to the first byte to the NUL
// terminator.
text->str[0] = '\0';
text->max=max;
}
int main() {
Text a; // store this in automatic memory, now the object exists without having to malloc
defText(&a,50); // Use & to pass the address of a to defText
// as mentioned, this is not the proper way to write data to a string in
// C. What you've done here is create a memory leak and point a.str to
// the string literal "Test all you want". Use strcpy (or similar) to
// write that string into the data you actually malloc'ed (using the dot
// operator now since `a` is no longer a pointer)
//a->str="Test all you want";
strcpy(a.str, "Test all you want");
// a.str is a pointer, and will always be 8 bytes on your system no matter
// the size of the memory it points to
printf("OUT: %s %zu %zu",a.str,strlen(a.str),sizeof(a.str));
// clean up allocated memory. Since we're about to exit, there's
// really no need to do this here (the OS will reclaim all allocated
// memory when the process ends), but if you're writing a more
// involved, long-running program, you need to be sure to handle
// memory allocations and deallocations appropriately as needed
free(a.str);
return 0;
}
Demo
The
a->str
is pointer .
the correct answer is
sizeof(*(a->str))
I am trying to modify a field inside a struct. I have no trouble doing this with other types (i.e. int, float etc.) but char * is giving me problems. I think I have to do something like:
typedef struct{
char *string_field;
} struct_name;
struct_name *struct_name1;
struct_name1 = (struct_name *) malloc(sizeof(struct_name));
strcpy(struct_name1->string_field, new_string);
printf("New string: %s\n", struct_name1->string_field);
But this gives me a segmentation fault. What reason do you think I would get this problem for? Initially, I thought maybe the char *string_field was not big enough to copy to, but I changed the size of it manually to be of size 100 (more than enough) and I still get this problem.
You reserve memory for your struct, which comprises a pointer to a string, but not the space for a string's content. Reserve memory for the string content and let your struct's pointer point to it; then you can copy newstring's content into that memory:
struct_name1->string_field = malloc(strlen(new_string)+1);
strcpy(struct_name1->string_field, new_string);
Allocate memory for the structure as well as for the string.
In example below there is a room for 63 characters in the string.
Remember to free the allocated memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *string_field;
} struct_name;
int main()
{
struct_name *struct_name1;
struct_name1 = malloc(sizeof(struct_name));
struct_name1->string_field = malloc(64*sizeof(char));
strcpy(struct_name1->string_field, "new_string");
printf("New string: %s\n", struct_name1->string_field);
free(struct_name1->string_field);
free(struct_name1);
return 0;
}
OUTPUT:
New string: new_string
How can I write the program below without any functions like strcpy()?
I know that we can do it with functions but I want to know learn how to do it without any function.
#include <stdio.h>
#include <string.h>
struct name
{
char fname[100];
};
struct list
{
struct name m;
};
int main()
{
struct list l;
strcpy(l.m.fname,"hello");
}
With C99 (or newer):
l.m = (struct name){"hello"};
That's a compound literal. See it live on coliru.
Note that it only works if the array is inside a struct, as in your original, because C does not allow direct assignment to an array.
All the same, the strcpy may be slightly faster, because it will only copy six bytes, while the compound literal assignment above copies 100.
I believe it would pretty much require writing out the code behind the function itself. Either that or you could hardcode every value.
You pretty much have to just expand out the code that would be in strcpy, which is just simple loop copying over each character until it hits the null terminator at the end..
{
struct list l;
const char *in = "hello";
char *out = l.m.fname;
while (*in)
*out++ = *in++;
}
*out=0;
}
I want to store a string in char array I am trying to do so by using a memcpy() but I am getting a segmentation fault. Can someone explain why? And what could be the correct way of doing this.
What would be better to use char * name; or char name[100]; ?
#include <stdio.h>
struct A
{
char * name;
};
typedef struct A A ;
int main()
{
A *a;
memcpy(a->name,"hello",sizeof(A));
printf("The value of name is %s",a->name);
return 0;
}
You have to allocate memory for structure and it's member and then after you can do copy data in it.
A *a = malloc(sizeof(A));
a->name=malloc(100); //change the size other then 100 what ever you want.
In first place you are asking two questions. You should read a bit here in order to understand how to ask good questions and get good answers.
You get segmentation fault because you haven't allocated memory for you variable name. The fastest way to solve this according the code and description you have provided is to use char name[100] in your declaration. Bear in mind that this is not the only possible way to do things. It depends what you are doing.
struct A
{
char name[100];
};
Then you have to allocate memory for the A *a pointer you are declaring. Better would be to use a normal variable A a and then access the member with the point operator (not sure if that is really an operator but the correct words doesn't come to mind at the moment). A simple snippet would be:
...
A a;
memcpy(a.name, "hello", 6);
printf("The value of name is %s",a.name);
...
A bit of documentation doesn't harm: memcpy()
My structure looks as follows:
typedef struct {
unsigned long attr;
char fileName[128];
} entity;
Then I try to assign some values but get an error message...
int attribute = 100;
char* fileNameDir = "blabla....etc";
entity* aEntity;
aEntity->attr = attributes;
aEntity->fileName = fileNameDir;
Compiler tells me:
Error: #137: expression must be a modifiable lvalue
aEntity->fileName = fileNameDir;
Why cant I assign here this character to the one in the structure?
Thanks
You're treating a char[] (and a char*, FTM) as if it was a string. Which is is not. You can't assign to an array, you'll have to copy the values. Also, the length of 128 for file names seems arbitrary and might be a potential source for buffer overflows. What's wrong with using std::string? That gets your rid of all these problems.
You're defining a pointer to some entity, don't initialize it, and then use it as if at the random address it points to was a valid entity object.
There's no need to typedef a struct in C++, as, unlike to C, in C++ struct names live in the same name space as other names.
If you absolutely must use the struct as it is defined in your question (it is pre-defined), then look at the other answers and get yourself "The C Programming Language". Otherwise, you might want to use this code:
struct entity {
unsigned long attr;
std::string fileName;
};
entity aEntity;
aEntity.attr = 100;
aEntity.filename = "blabla....etc";
You can't assign a pointer to an array. Use strncpy() for copying the string:
strncpy( aEntity->fileName, fileNameDir, 128 );
This will leave the destination not null-terminated if the source is longer than 128. I think the best solution is to have a bigger-by-one buffer, copy only N bytes and set the N+1th byte to zero:
#define BufferLength 128
typedef struct {
unsigned long attr;
char fileName[BufferLength + 1];
} entity;
strncpy( aEntity->FileName, fileNameDir, BufferLength );
*( aEntity->FileName + BufferLength ) = 0;
You should be copying the filename string, not changing where it points to.
Are you writing C or C++? There is no language called C/C++ and the answer to your question differs depending on the language you are using. If you are using C++, you should use std::string rather than plain old C strings.
There is a major problem in your code which I did not see other posters address:
entity* aEntity;
declares aEntity (should be anEntity) as a pointer to an entity but it is not initialized. Therefore, like all uninitialized pointers, it points to garbage. Hence:
aEntity->attr = attributes;
invokes undefined behavior.
Now, given a properly initialized anEntity, anEntity->fileName is an array, not a pointer to a character array (see question 6.2 in the C FAQ list). As such, you need to copy over the character string pointed to by fileNameDir to the memory block reserved for anEntity->fileName.
I see a lot of recommendations to use strncpy. I am not a proponent of thinking of strncpy as a safer replacement for strcpy because it really isn't. See also Why is strncpy insecure?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct st_entity {
unsigned long attr;
char fileName[FILENAME_MAX + 1];
} entity;
int main(void) {
int status = EXIT_FAILURE;
unsigned long attribute = 100;
char *fileNameDir = "blabla....etc";
entity *anEntity = malloc(sizeof(*anEntity));
if ( anEntity ) {
anEntity->attr = attribute;
anEntity->fileName[0] = '\0';
strncat(anEntity->fileName, fileNameDir, sizeof(anEntity->fileName) - 1);
printf("%lu\n%s\n", anEntity->attr, anEntity->fileName);
status = EXIT_SUCCESS;
}
else {
fputs("Memory allocation failed", stderr);
}
return status;
}
See strncat.
You're trying to use char* as if it was a string, which it is not. In particular, you're telling the compiler to set filename, a 128-sized char array, to the memory address pointed by fileNameDir.
Use strcpy: http://cplusplus.com/reference/clibrary/cstring/strcpy/
You can't assign a pointer to char to a char array, they're not compatible that way, you need to copy contents from one to another, strcpy, strncpy...
Use strncpy():
strncpy( aEntity->fileName, fileNameDir, sizeof(entity.fileName) );
aEntity.fileName[ sizeof(entity.fileName) - 1 ] = 0;
The strncpy() function is similar,
except that not more than n bytes of
src are copied. Thus, if there is no
null byte among the first n bytes of
src, the result will not be
null-terminated. See man page.
1) The line char* fileNameDir = "blabla....etc" creates a pointer to char and assigns the pointer an address; the address in this case being the address of the text "blabla....etc" residing in memory.
2) Furthermore, arrays (char fileName[128]) cannot be assigned to at all; you can only assign to members of an array (e.g. array[0] = blah).
Knowing (1) and (2) above, it should be obvious that assigning an address to an array is not a valid thing to do for several reasons.
What you must do instead is to copy the data that fileNameDir points to, to the array (i.e. the members of the array), using for example strncpy.
Also note that you have merely allocated a pointer to your struct, but no memory to hold the struct data itself!
First of all, is this supposed to be C or C++? The two are not the same or freely interchangeable, and the "right" answer will be different for each.
If this is C, then be aware you cannot assign strings to arrays using the '=' operator; you must either use strcpy() or strncpy():
/**
* In your snippet above, you're just declaring a pointer to entity but not
* allocating it; is that just an oversight?
*/
entity *aEntity = malloc(sizeof *aEntity);
...
strcpy(aEntity->fileName, fileNameDir);
or
strncpy(aEntity->fileName, fileNameDir, sizeof aEntity->fileName);
with appropriate checks for a terminating nul character.
If this is C++, you should be using the std::string type for instead of char* or char[]. That way, you can assign string data using the '=' operator:
struct entity {unsigned long attr; std::string fileName};
entity *aEntity = new entity;
std::string fileNameDir = "...";
...
entity->fileName = fileNameDir;
The major problem is that you declared a pointer to a struct, but allocated no space to it (unless you left some critical code out). And the other problems which others have noted.
The problem lies in the fact that you cannot just use a pointer without initialising it to a variable of that same datatype, which in this is a entity variable. Without this, the pointer will point to some random memory location containing some garbage values. You will get segmentation faults when trying to play with such pointers.
The second thing to be noted is that you can't directly assign strings to variables with the assignment operator(=). You have to use the strcpy() function which is in the string.h header file.
The output of the code is:
100 blabla......etc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
unsigned long attr;
char fileName[128];
} entity;
void main()
{
unsigned long int attribute = 100;
char *fileNameDir = "blabla....etc";
entity struct_entity;
entity *aEntity = &struct_entity;
aEntity->attr = attribute;
strcpy(aEntity->fileName, fileNameDir);
printf("%ld %s", struct_entity.attr, struct_entity.fileName);
}
For char fileName[128], fileName is the array which is 128 char long. you canot change the fileName.
You can change the content of the memory that filename is pointing by using strncpy( aEntity->fileName, fileNameDir, 128 );