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 );
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have this code:
char** SplitToWords(char* str);
int main()
{
char** wordarr;
char str[] = "This is a sentence";
wordarr = SplitToWords(str);
return 0;
}
After the main comes the function implementation.
I am not sure the following does what I want it to do (i.e. receive an array of strings from a function):
wordarr = SplitToWords(str);
I somehow managed to convince the compiler that it's ok, but I assume it just does something else.
If it does, how do I find out the length of the array (the number of strings in it).
Thanks
I'll try to quickly visit all aspects you might not yet fully understand:
A string in C is described as a contiguous sequence of chars, ending with a char of value 0 (as a literal: '\0'). It is not a first class object, therefore hasn't its own type. So what you use to hold a string is an array of char. Therefore, taking your question by the word, "receive an array of strings from a function" is not possible.
An array is a contiguous sequence of objects of the same type. In C, the identifier of an array doesn't have a value itself; when it's evaluated, it decays as a pointer to the array's first element instead. This is especially important when passing arrays to functions or returning them from functions -- you can't actually pass the array, you always pass a pointer
e.g. you could write:
char x[] = "foo"; // initialize a char array from a string literal
char *xp = x; // here, x evaluates as a pointer to the first element of the array
You already use pointer types for your function's argument and return value, I just think it's quite important to understand what happens entirely.
You write char** SplitToWords(char* str); and ask whether this returns an "array of strings" -- well, sort of, as you should understand after reading 1. and 2. -- What it does is returning a pointer to char *. This pointer could be a pointer to the first element of an array. So in this case, it would return a pointer to an array of char * pointers. Each of these pointers could itself be a pointer to an array of chars, therefore point to a string. But what's very important is to understand you never return an array, you always return a pointer to it. It's so important because:
You might get the idea to do something like this:
char** SplitToWords(char* str)
{
char *words[16];
// code to fill `words` with pointers to the actual words
return words; // WRONG!
}
Here, because you're not returning the array words but a pointer to it (see point 2), you return a pointer to an object that no longer exists. words is in the scope of your function and has automatic storage duration, that means it only lives as long as the execution is inside of the function. One solution would be to declare words with the static storage class specifier. This way, it lives for the entire execution time of the program. But be aware that this also means there's only a single instance ever, it's always the same object. This will be a major headache for threaded programs, for example. The other way around is to dynamically allocate words using malloc(). But then, the caller of the function must free() it later.
As for your second question, how to let the caller know the number of words -- it's in the comments already, but just for completeness, a typical approach to solve this is to append another entry that is a NULL pointer. So the caller can iterate over the pointers until it finds NULL.
Regarding your comment, of course you can create the array outside the function and pass a pointer to the function, so the function only fills it. This is a common idiom in C (e.g. think about fgets(), which takes a pointer to the char array that's filled with a string by the function).
Functions working this way will need an additional size_t parameter, so they know the size of the array they should fill through the pointer, otherwise you'd have the risk of buffer overflows (this is why gets() was finally removed from the C standard). If you decide that the caller provides the storage, your function should have this prototype:
// returns the number of words found, up to `nwords`
size_t SplitToTwords(char **words, size_t nwords, char *str);
It should be called e.g. like this:
char *words[16];
size_t nwords = SplitToWords(words, 16, "the quick brown fox"); // returns 4
Remember that the strings holding the words themselves need storage as well. You can either manipulate the bytes in str to insert a '\0' after each word, overwriting the first whitespace character (this is what strtok() does) or you can copy the words to new strings, but then you would have to malloc() each of them again and the caller has to free() them later.
Yes, you could solve it by using a function with return value char **. However, there's no way to find out how many words there are afterwards.
You can solve this by allocating one more element for the return pointer and set it to NULL. Then you can get the number of words with this code:
wordarr = SplitToWords(str);
char **ptr=wordarr;
int noWords=0;
while(!*(ptr+noWords))
noWords++;
But if you want to return multiple data in C, you either need to define a return struct or using return arguments. In this case, it could look like this for the first option:
typedef struct wordList {
char **wordarr;
int noWords;
}
wordList SplitToWords(char* str);
And the second:
char** SplitToWords(char* str, int *noWords);
or
void SplitToWords(char* str, char*** wordarr, int *noWords);
Note that there's three *. That's because we want it to be a pointer to char **
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSTRINGS 5000
int main(int argc, char *argv[]) {
char *stringTable[MAXSTRINGS];
char sentence[] = "This is a sentence";
char *token = NULL;
int i = 0;
while ((token = strtok(token == NULL ? sentence : NULL, " ")) != NULL)
{
printf("%s\n\r", token);
stringTable[i] = (char *)malloc(strlen(token) + 1); //have no "plain" C compiler - VS C++ used so cast needed :)
strcpy(stringTable[i++], token);
}
stringTable[i] = NULL; // if you need to iterate through later
printf("%d tokens found\n\r", i);
for (int y = 0; y < i; y++)
free(stringTable[y]);
}
I've been studying C, and I decided to practice using my knowledge by creating some functions to manipulate strings. I wrote a string reverser function, and a main function that asks for user input, sends it through stringreverse(), and prints the results.
Basically I just want to understand how my function works. When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
I guess answering this question would tell me: Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now? I want to know whether I'm sending a duplicate of the array tempstr, or a memory address.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
printf("\nEnter a string:\n\t");
char tempstr[1024];
gets(tempstr);
char *revstr = stringreverse(tempstr, revstr); //Assigns revstr the address of the first character of the reversed string.
printf("\nReversed string:\n"
"\t%s\n", revstr);
main();
return 0;
}
char* stringreverse(char* tempstr, char* returnptr)
{
char revstr[1024] = {0};
int i, j = 0;
for (i = strlen(tempstr) - 1; i >= 0; i--, j++)
{
revstr[j] = tempstr[i]; //string reverse algorithm
}
returnptr = &revstr[0];
return returnptr;
}
Thanks for your time. Any other critiques would be helpful . . only a few weeks into programming :P
EDIT: Thanks to all the answers, I figured it out. Here's my solution for anyone wondering:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stringreverse(char* s);
int main(void)
{
printf("\nEnter a string:\n\t");
char userinput[1024] = {0}; //Need to learn how to use malloc() xD
gets(userinput);
stringreverse(userinput);
printf("\nReversed string:\n"
"\t%s\n", userinput);
main();
return 0;
}
void stringreverse(char* s)
{
int i, j = 0;
char scopy[1024]; //Update to dynamic buffer
strcpy(scopy, s);
for (i = strlen(s) - 1; i >= 0; i--, j++)
{
*(s + j) = scopy[i];
}
}
First, a detail:
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
That prototype should go outside main(), like this:
char* stringreverse(char* tempstr, char* returnptr);
int main()
{
As to your main question: the variable tempstr is a char*, i.e. the address of a character. If you use C's index notation, like tempstr[i], that's essentially the same as *(tempstr + i). The same is true of revstr, except that in that case you're returning the address of a block of memory that's about to be clobbered when the array it points to goes out of scope. You've got the right idea in passing in the address of some memory into which to write the reversed string, but you're not actually copying the data into the memory pointed to by that block. Also, the line:
returnptr = &revstr[0];
Doesn't do what you think. You can't assign a new pointer to returnptr; if you really want to modify returnptr, you'll need to pass in its address, so the parameter would be specified char** returnptr. But don't do that: instead, create a block in your main() that will receive the reversed string, and pass its address in the returnptr parameter. Then, use that block rather than the temporary one you're using now in stringreverse().
Basically I just want to understand how my function works.
One problem you have is that you are using revstr without initializing it or allocating memory for it. This is undefined behavior since you are writing into memory doesn't belong to you. It may appear to work, but in fact what you have is a bug and can produce unexpected results at any time.
When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
Yes. When arrays are passed as arguments to a function, they are treated as regular pointers, pointing to the first element in the array. There is no difference if you assigned &temp[0] to a char* before passing it to stringreverser, because that's what the compiler is doing for you anyway.
The only time you will see a difference between arrays and pointers being passed to functions is in C++ when you start learning about templates and template specialization. But this question is C, so I just thought I'd throw that out there.
When I call it with 'tempstr' as the first param, is that to be understood as the
address of the first element in the array? Basically like saying &tempstr[0],
right?
char tempstr[1024];
tempstr is an array of characters. When passed tempstr to a function, it decays to a pointer pointing to first element of tempstr. So, its basically same as sending &tempstr[0].
Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now?
No difference. You might do -
char* pointer = tempstr ; // And can pass pointer
char *revstr = stringreverse(tempstr, revstr);
First right side expression's is evaluavated and the return value is assigned to revstr. But what is revstr that is being passed. Program should allocate memory for it.
char revstr[1024] ;
char *retValue = stringreverse(tempstr, revstr) ;
// ^^^^^^ changed to be different.
Now, when passing tempstr and revstr, they decayed to pointers pointing to their respective first indexes. In that case why this would go wrong -
revstr = stringreverse(tempstr, revstr) ;
Just because arrays are not pointers. char* is different from char[]. Hope it helps !
In response to your question about whether the thing passed to the function is an array or a pointer, the relevant part of the C99 standard (6.3.2.1/3) states:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
So yes, other than the introduction of another explicit variable, the following two lines are equivalent:
char x[] = "abc"; fn (x);
char x[] = "abc"; char *px = &(x[0]); fn (px);
As to a critique, I'd like to raise the following.
While legal, I find it incongruous to have function prototypes (such as stringreverse) anywhere other than at file level. In fact, I tend to order my functions so that they're not usually necessary, making one less place where you have to change it, should the arguments or return type need to be changed. That would entail, in this case, placing stringreverse before main.
Don't ever use gets in a real program.. It's unprotectable against buffer overflows. At a minimum, use fgets which can be protected, or use a decent input function such as the one found here.
You cannot create a local variable within stringreverse and pass back the address of it. That's undefined behaviour. Once that function returns, that variable is gone and you're most likely pointing to whatever happens to replace it on the stack the next time you call a function.
There's no need to pass in the revstr variable either. If it were a pointer with backing memory (i.e., had space allocated for it), that would be fine but then there would be no need to return it. In that case you would allocate both in the caller:
char tempstr[1024];
char revstr[1024];
stringreverse (tempstr, revstr); // Note no return value needed
// since you're manipulating revstr directly.
You should also try to avoid magic numbers like 1024. Better to have lines like:
#define BUFFSZ 1024
char tempstr[BUFFSZ];
so that you only need to change it in one place if you ever need a new value (that becomes particularly important if you have lots of 1024 numbers with different meanings - global search and replace will be your enemy in that case rather than your friend).
In order to make you function more adaptable, you may want to consider allowing it to handle any length. You can do that by passing both buffers in, or by using malloc to dynamically allocate a buffer for you, something like:
char *reversestring (char *src) {
char *dst = malloc (strlen (src) + 1);
if (dst != NULL) {
// copy characters in reverse order.
}
return dst;
}
This puts the responsibility for freeing that memory on the caller but that's a well-worn way of doing things.
You should probably use one of the two canonical forms for main:
int main (int argc, char *argv[]);
int main (void);
It's also a particularly bad idea to call main from anywhere. While that may look like a nifty way to get an infinite loop, it almost certainly will end up chewing up your stack space :-)
All in all, this is probably the function I'd initially write. It allows the user to populate their own buffer if they want, or to specify they don't have one, in which case one will be created for them:
char *revstr (char *src, char *dst) {
// Cache size in case compiler not smart enough to do so.
// Then create destination buffer if none provided.
size_t sz = strlen (src);
if (dst == NULL) dst = malloc (sz + 1);
// Assuming buffer available, copy string.
if (dst != NULL) {
// Run dst end to start, null terminator first.
dst += sz; *dst = '\0';
// Copy character by character until null terminator in src.
// We end up with dst set to original correct value.
while (*src != '\0')
*--dst = *src++;
}
// Return reversed string (possibly NULL if malloc failed).
return dst;
}
In your stringreverse() function, you are returning the address of a local variable (revstr). This is undefined behaviour and is very bad. Your program may appear to work right now, but it will suddenly fail sometime in the future for reasons that are not obvious.
You have two general choices:
Have stringreverse() allocate memory for the returned string, and leave it up to the caller to free it.
Have the caller preallocate space for the returned string, and tell stringreverse() where it is and how big it is.
I radically re-edited the question to explain better my application, as the xample I made up wasn't correct in many ways as you pointed out:
I have one pointer to char and I want to copy it to another pointer and then add a NULL character at the end (in my real application, the first string is a const, so I cannot jsut modify it, that's why I need to copy it).
I have this function, "MLSLSerialWriteBurst" which I have to fill with some code adapt to my microcontroller.
tMLError MLSLSerialWriteBurst( unsigned char slaveAddr,
unsigned char registerAddr,
unsigned short length,
const unsigned char *data )
{
unsigned char *tmp_data;
tmp_data = data;
*(tmp_data+length) = NULL;
// this function takes a tmp_data which is a char* terminated with a NULL character ('\0')
if(EEPageWrite2(slaveAddr,registerAddr,tmp_data)==0)
return ML_SUCCESS;
else
return ML_ERROR;
}
I see there's a problem here: tha fact that I do not initialize tmp_data, but I cannot know it's length.
For starters, you are missing a bunch of declarations in your code. For example, what is lungh? Also, I'm assuming you initialized your two pointers so they point to memory you can use. However, maybe that's not a safe assumption.
Beyond that, you failed to terminate your from string. So getting the length of the string will not work.
There seems to be numerous errors here. It's hard to know where to start. Is this really what your actual code looks like? I don't think it would even compile.
Finally, there seems to be a bit of confusion in your terminology. Copying a pointer is different from copying the memory being pointed to. A pointer is a memory address. If you simply copy the pointer, then both pointers will refer to the same address.
I would create a copy of a string using code similar to this:
char *from_string = "ciao";
char *to_string;
int len;
len = strlen(from_string);
to_string = (char *)malloc(len + 1);
if (to_string != NULL)
strcpy(to_string, from_string);
Be fully aware that you do not want to copy a pointer. You want to copy the memory that is pointed to by the pointer. It does sound like you should learn more about pointers and the memory environment of your system before proceeding too much farther.
When you say tmp_data = data, you are pointing tmp_data to the same memory pointed to by data. Instead, you need to allocate a new block of memory and copy the memory from data into it.
The standard way to do this is with malloc. If you do not have malloc, your libraries may have some other way of acquiring a pointer to usable memory.
unsigned char * tmp_data = malloc(length + 1);
if(tmp_data != 0) {
memcpy(tmp_data, data, length);
tmp_data[length] = 0;
// ...
free(tmp_data);
}
You could also use a fixed-size array on the stack:
unsigned char tmp_data[256];
if(length >= sizeof(tmp_data)) length = sizeof(tmp_data) - 1;
memcpy(tmp_data, data, length); // or equivalent routine
tmp_data[length] = 0;
C99 introduced variable-length arrays, which may be what you seek here, if your compiler supports them:
unsigned char tmp_data[length];
memcpy(tmp_data, data, length); // or equivalent routine
tmp_data[length] = 0;
I am trying to read a large list of English words from a text file to array of strings. The number of words is 2016415, and maximum length of a word is 69 characters.
If I define array like "char data[2016415][70]; " then I get stack overflow when I run the program.
So I am trying to use calloc() instead, however I can't understand how should I type-cast it so that it becomes equivalent to "char data[2016415][70];".
The following program returns "passing arg 1 of `fgets' makes pointer from integer without a cast" warning during compiling. And when I execute it, it gets "Exception: STATUS_ACCESS_VIOLATION" problem.
Can you help me?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char *data; //data[2016415][70];
int i;
FILE *fsol;
fsol = fopen("C:\\Downloads\\abc\\sol2.txt","r");
data = (char*) calloc(2016415,70);
for(i=0;i<2016415;i++){
fgets(data[i] , 70 , fsol);
}
fclose(fsol);
return 0;
}
calloc just allocates a big swath of memory - not an array of pointers to other arrays.
fgets expects a pointer to the memory location it should dump it's stuff at.
So instead of giving it the contents of data[i], you want to give it the address of data[i] so it can put its stuff there.
fgets(&data[i], 70, fsol);
You'll probably also need to adjust your loop so that it goes up by 70-odd characters at a time rather than one.
Okay, sorry about the previous suggestion. I forgot how horrible arrays can be. This one is tested with a small data set of 10 words, but it should scale to your word count. Note that fgets() seems to pull in the line endings as part of the preceding word.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_CNT 2016415
#define MAX_WORD_LEN 70
int main(void)
{
char *data; //data[2016415][70];
int i;
FILE *fsol;
fsol = fopen("C:\\Downloads\\abc\\sol2.txt","r");
data = (char*) calloc(MAX_WORD_CNT, MAX_WORD_LEN);
// check for valid allocation
if (data == NULL)
{
return 1;
}
for(i=0; i<MAX_WORD_CNT; i++)
{
fgets(&data[i * MAX_WORD_LEN], MAX_WORD_LEN, fsol);
}
fclose(fsol);
return 0;
}
Here's how I would allocate the array
char **data = malloc(MAX_WORD_CNT * sizeof(char *));
for(int i = 0; i < MAX_WORD_CNT; i++)
data[i] = malloc(MAX_WORD_LEN);
you might want to add some error checking for malloc though.
data is a pointer to char (also addressable as an array of char), so data[i] is a single char. fgets expects a pointer to char but you're passing it a single char; that's why you're getting the warning, you're trying to use a char (integer) as a pointer.
When you run the program, it then takes that single char argument and interprets it as a pointer to char, hence the access violation because the value of that char is not a valid address.
So, in your loop you should pass fgets a pointer into data and increment that by 70 with each iteration. You can use the "pointer to an array element" form &data[i] and increment i, or the simple pointer form, with another pointer variable initially set to data, and itself incremented.
The answer is simple: you DON'T cast it. Casting the results of malloc/calloc/etc. has no purpose but can have the side-effect of hiding a major bug if you forgot to include stdlib.h. The return type of these allocation functions, which is void *, will automatically be cast to whatever you need.
If you really want to know the type, it's (char (*)[70]). But please don't actually obfuscate your program by writing that. (Unless you're actually writing C++, in which case you should have tagged your question C++ and not C, or better yet used new.)
#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.