I am new to C and working on it since two months. I have a structure shown below:
struct profile_t
{
unsigned char length;
unsigned char type;
unsigned char *data;
};
typedef struct profile_datagram_t
{
unsigned char *src;
unsigned char *dst;
unsigned char ver;
unsigned char n;
struct profile_t profiles[MAXPROFILES];
} header;
header outObj;
Now the values inside the elements of the structure are read as outObj.src[i], outObj.dst[i], and outObj.profiles[i].type.
Now I want to call a function and pass the values read by me to a function which is actually a Berkeley DB.
void main()
{
struct pearson_record {
unsigned char src[6];
unsigned char dst[6];
unsigned char type;
};
DB *dbp;
int ret;
if ((ret = db_create(&dbp, dbenv, 0)) !=0)
handle_error(ret);
if ((ret = dbp->open(dbp, NULL, "pearson.db", NULL, DB_BTREE, DB_CREATE, 0600)) !=0)
handle_error(ret);
const DBT *pkey;
const DBT *pdata;
struct pearson_record p;
DBT data, key;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
memset(&s, 0, sizeof(struct pearson_record));
Now the above code is written by looking at a example from the DB reference guide. but i don't understand what is const DBT. Also they have added the value inside structure using memcopy which I know is the right way, but now I want to memcopy the values passed which are mentioned above and store them in the structure pearson_record. How should I go with this?? Any kind of help would be appreciated.
Please post the complete code. You mention "they memcopy" (which I assume you refer to memcpy), but all I see is a bunch of memset(*,0). Hope you're not confusing them.
Also "they have added the value inside structure using memcopy which I know is the right way" is not entirely true. It's not necessarily wrong, BUT... char* is basically interpreted as a C string. that is an array of bytes which represent characters which MUST be null terminated (that is the last character must be 0, equivalent to '\0'). The proper way to copy strings is using strcpy() (or strcpy_s on windows), the difference is memcpy is faster and used in other situations (such as pointers\buffer management).
unsigned char* is not so used (at least I never saw it till now). As a note read about char, unsigned char, signed char, char[] and char* (not that it changes your code in any way, but just to make sure you understand the differences).
As for copying data, I assume you mean src, dst and type from pearson_record to header, correct ? If so, for the sake of simplicity I wanted to suggest memcpy but you say that each element is accessed as [i]. Does that mean header.src is an array of more than one pearson_record.src or does header.src[i] correspond to pearson_record.src[i] ? This is slightly unclear to me.
There is a difference between char* src and char* *src.
Related
I am novice on the topic, I have unsinged char *buffer
I am trying to inspect it at 3 bytes at a time
I think maybe this can be solved with a 2 dimensional array.
so I tried this -
unsigned char *bytes[3] = {};
*bytes = buffer;
but I see that's a notation to create array of 3 elements of type unsigned char *
is there any way to achieve this without having to memcpy
any pointers are greatly appreciated.
this approach seems to work
typedef struct utf8 {
unsigned char bytes[3];
};
typedef struct utf8 utf8x;
utf8x *xx = (utf8x *) buffer; //buffer is a return from fread (unsinged char *)
if (xx->bytes[0] == 0xe0) {
printf("scratch");
}
however I am still trying to figure out how to compare all the bytes, I guess if I cast xx->bytes to return 3 bytes it should work.
You want to compare three bytes of a buffer at once. You can do this using memcmp() (which a good compiler will optimize out so there is no actual function call). For example:
utf8x *xx = (utf8x *) buff;
if (memcmp(&xx->bytes[0], "\100\50\10", 3) == 0) {
printf("scratch");
}
That will print scratch if the first three bytes are \100 \50 \10.
so i have a struct call Process_Info
struct Process_Info {
char name[128];
int pid;
int parent_pid;
int priority;
int status;
};
and an array of Process_Info call info. I set pid in info to an integer, it works but when I try to set name in info to "{kernel}" like this
info[i].name="{kernel}";
and it give me incompatible type in assignment error. I search online it seem i can do this, like in http://www.cs.bu.edu/teaching/cpp/string/array-vs-ptr/, they did char label[] = "Single"; So what am i doing wrong?
The short answer: A C compiler will bake constant strings into the binary, so you need to use strncpy (or strcpy if you aren't worried about security) to copy "{kernel}" into info[i].name.
The longer answer: Whenever you write
char label[] = "Single";
the C compiler will bake the string "Single" into the binary it produces, and make label into a pointer to that string. In C language terms, "Single" is of type const char * and thus cannot be changed in any way. However, you cannot assign a const char * to a char *, since a char * can be modified.
In other words, you cannot write
char label[] = "Single";
label[0] = "T";
because the compiler won't allow the second line. However, you can change info[i].name by writing something like
info[i].name[0] = '[';
because info[i].name if of type char *. To solve this problem, you should use strncpy (I referenced a manual page above) to copy the string "{Kernel}" into info[i].name as
strncpy(info[i].name, "{Kernel}", 256);
info[i].name[255] = '\0';
which will ensure that you don't overflow the buffer.
I think you may be mistaken. The way you would assign this would be one char at a time like so...
name[] = {'a','b','c','d'};
#define STRING(s) (((String*)s)-1)
what in the world is (((String*)s)-1)?
typedef
struct String {
int length;
int capacity;
unsigned check;
char ptr[0];
} String;
You're casting s to a String *. Then you're subtracting one from it (making it point to the previous whatever).
Anything more specific would need to know the definition of String - but (WILD SPECULATION) I would guess the application uses dual VB/C-style strings (null terminated, preceded by the length), and this function changes it from a form suitable for C functions (pointer to the first character) into one usable for the other type (pointer to the length).
Mechanically, the macro works as others have already described it. Semantically, though, you can think of this as a form of casting from char *s to String *s.
The String structure is the header of a counted string, ie, one where you know the total length without having to scan for a NUL byte. This particular version also keeps the total allocated. You would create one as follows:
struct String *str = malloc(sizeof(*s) + maxlen);
str->length = 0;
str->capacity = maxlen;
str->checked = /* ??? */;
There should be some assorted functions around somewhere to manipulate these counted strings.
The macro itself is a hack to go from a plain char *, assumed to point to the first character of the a String as allocated above, back to a String *. It would be used something like this:
/* allocate str as above */
char *s = str->p;
Now, through a chain of function calls or returns, you somehow loose track of the String structure containing s, and you need to find it again. You write:
String *str2 = STRING(s);
This is not a particularly good way to implement a counted string in C, but it demonstrates a technique that one sees from time to time.
Others have answered your question. The technique of declaring ptr inside struct String with zero size is called "the struct hack", and wasn't portable until C99 (although it was widely used even before C99, and seems to work everywhere). The idea is that ptr uses 0 bytes, so if you have a pointer to ptr, and want one to the original struct, you would use the STRING macro. You are subtracting the size of the struct from the address of the ptr member, and thus getting the start address of the struct.
A better way to get the start address of a struct given a pointer to any of its members is to use offsetof() macro defined in stddef.h. offsetof(struct type, member), as the name implies, gives the offset of member in struct type:
#define STRING(x) ((String *)(((char *)(x) - offsetof(struct String, ptr))))
Then you can do:
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
typedef struct String {
int length;
int capacity;
unsigned check;
char ptr[0];
} String;
#define STRING(x) ((String *)(((char *)(x) - offsetof(struct String, ptr))))
int main(void)
{
String *s = malloc(sizeof *s + 100);
String *t;
char *mystring = s->ptr;
t = STRING(mystring);
assert(t == s);
return EXIT_SUCCESS;
}
offsetof() is defined in stddef.h.
Note that in C99, "struct hack" would declare ptr inside the struct as:
char ptr[];
i.e., without a size.
(String*) = type cast to pointer to String object,
s = the string,
-1 = point to one String object's length before in the memory block
Don't know why the macro is made this way. Possibly the definition of String requires this, but that's just a wild guess.
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 );
Using c, I have defined a byte and word as follows:
typedef unsigned char byte;
typedef union {
byte b[4];
unsigned long w;
} word;
This allows me to easy go from words to bytes, but I'm not sure of a good way to go the other way. Is it possible to do something like cast from byte* to word* or do I have to stick with iteratively copying bytes to words?
One of the great and terrible things about c is you can take a void pointer and cast it to anything. As long as you know what you are doing it will work, but not something you want to get in the habit of.
const byte input[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
unsigned long output[sizeof(input) / sizeof(unsigned long)];
memcpy(output, input, sizeof(input));