C Struct Compile Error - c

Why does the following code produce a compile-time error? I cannot seem to see why the types are mismatched.
typedef char f_string[MAX_CHARS+1] ; /* string for each field */
/*
* A parsed CSV line, with the number of fields and upto MAX_FIELDS themselves.
*/
typedef struct {
int nfields ; /* 0 => end of file */
f_string field[MAX_FIELDS] ; /* array of strings for fields */
} csv_line;
....
csv_line sut;
sut.field[0] = "Name, "; //Compile-time error.
Error being:
error: incompatible types in assignment

You are trying to assign a const char * to a char[], which is not quite the same thing. This would work if your f_string were defined as
typedef const char * f_string;
What you are looking for here is
strcpy ( sut.field[0], "Name, " );
Or use strncpy so that you can specify the size of the destination buffer ..
strncpy ( sut.field[0], "Name, ", MAX_CHARS )
That will keep you from overrunning your buffer.

You'll need to use something like:
strcpy( sut.field[0],"Name, ");
You can't assign strings like you tried other except as an initializater at declaration time.

the type of sut.field[0] is array-of-char of size MAX_CHARS+1 - you cannot assign a string pointer to an array of characters.
You'd either need to change the type of csv_line::field to a const char*, or just do a string copy of the literal "Name, " to the target array.
Note that both strcpy() and strncpy() alone are unsafe: the first might overflow your buffer, and the second might leave it without a NUL terminator. You must be aware of BOTH of these circumstances even if you "know" that your string in question won't ever overflow.
Use a helper function to do this safely:
char * strncopy(char *dst, const char *src, int dstsize)
{
strncpy(dst, src, dstsize-1);
dst[dstsize-1] = '\0';
return dst;
}
Then:
strncopy(sut.field[0], "Name, ", sizeof sut.field[0]);

sut.field[0] is a char[MAX_CHARS+1]
"Name, " is a const char*
Try this:
strcpy(sut.field[0], "Name, ");

The type of sut.field[0] is indeed char [MAX_CHARS+1]. However, most of the other answers have the type of "Name, " wrong - it is actually of type char [7] (use sizeof "Name, " for an easy demonstration of this).
Nonetheless, you still cannot directly assign a char [7] to a char [MAX_CHARS+1]. You cannot even directly assign a char [7] to another char [7] (initialisation is treated differently from assignment in this way).
The answer is probably just to use a coyping function - for example, if you are certain that MAX_CHARS >= 6, then you can just use strcpy(). If you cannot be sure about the length being correct, then you can use strncat() as as truncating string copy:
sut.field[0][0] = '\0';
strncat(sut.field[0], "Name, ", MAX_CHARS);
(Note that despite the name, strncpy() is not suitable for this, and in fact is very rarely the desired function at all).
It is worth pointing out, however, that you can indirectly assign arrays (of the same type) if they are wrapped up inside a struct. This means that the following will work (if you have a C99 compiler):
typedef struct { char s[MAX_CHARS+1] } f_string; /* string for each field */
csv_line sut;
sut.field[0] = (f_string){"Name, "};

Related

Strcpy from char* to char[] creating the wrong form

typedef struct Symbol{
char varName[16];
} Symbol;
...............
Symbol *newSymbol = malloc(sizeof(Symbol));
const char space[2] = " ";
char *String = "Name Test";
//break off the first word from String and put it into name
char *name;
name = strtok(String,space);
//convert the char * to char[16]
char nameArray[16];
strcpy(nameArray,name);
//set newSymbol->varName to the newly created char[16]
newSymbol->varName = nameArray
I have a char * called String. In my actual program, it is read from a file using fgets, I am just calling it "Name Test" for the purposes of this example. I want to take the first word of the string and assign it as the varName in a Symbol. So what should happen is newSymbol->varName is set to "Name". Because strtok returns a char * but I need a char[16] for the struct, I must convert the char * to a char[16].
However, I get this error:
"Error: incompatible types when assigning to type 'char[16]' from type 'char*'
newSymbol -> varName = nameArray;
So, it seems like strcpy it not actually converting the char * to a char[16]. Even after declaring a char[16] and telling strcpy to put the contents of the char * into it, I still have a char * instead of a char[16]. I need to make it work without changing the struct, so that is not an option here.
How can I convert a char * into a char[16]?
You cannot assign the contents of an array using the regular assignment operator in C.
You can use strcpy for strings and memcpy/memset for other data types. (You could use memcpy/memset for strings too but strcpy is simpler)
Instead of
newSymbol -> varName = nameArray;
use
strcpy(newSymbol -> varName, nameArray);
So, it seems like strcpy it not actually converting the char* to a char[16].
No, the problem is that C does not provide for assigning to (whole) arrays. newSymbol->varName is an array of 16 char. You can assign to elements of that array, and you can copy into it with strcpy() or a similar function, but you cannot assign to the whole array.
In your particular code, I'd dispense with variable nameArray, changing this ...
strcpy(nameArray,name);
... to this:
strcpy(newSymbol->varName, name);
(Or perhaps to a similar usage of strncpy(), to protect from overrunning the array bounds.)

C setting string equal to substring

In C, If I have:
char *reg = "[R5]";
and I want
char *reg_alt = "R5" (equal to the same thing, but without the brackets), how do I do this?
I tried
*char reg_alt = reg[1:2];
but this doesn't work.
There is no built-in syntax for dealing with substrings like that, so you need to copy the content manually:
char res[3];
memcpy(res, &reg[1], 2);
res[2] = '\0';
I suggest you need to read a basic text on C, rather than assuming techniques from other languages will just work.
First, char *reg = "[R5]"; is not a string. It is a pointer, that is initialised to point to (i.e. its value is the address of) the first character of a string literal ("[R5]").
Second, reg_alt is also a pointer, not a string. Assigning to it will contain an address of something. Strings are not first class citizens in C, so the assignment operator doesn't work with them.
Third, 1:2 does not specify a range - it is actually more invalid syntax. Yes, I know other languages do. But not C. Hence my comment that you cannot assume C will allow things it the way that other languages do.
If you want to obtain a substring from another string, there are various ways. For example;
char substring[3];
const char *reg = "[R5]"; /* const since the string literal should not be modified */
strncpy(substring, &reg[1], 2); /* copy 2 characters, starting at reg[1], to substring */
substring[2] = '\0'; /* terminate substring */
printf("%s\n", substring);
strncpy() is declared in standard header <string.h>. The termination of the substring is needed, since printf() %s format looks for a zero character to mark the end.
When using null-terminated strings (the default in C), you can indeed cheaply create a substring of another string by simply changing the starting character pointer, but you cannot make the new substring have a different null-terminator.
An option is to use a Pascal-string library. Pascal-strings are length-prefixed instead of C-strings which are null-terminated, which means Pascal-strings can share contents of a larger string buffer and substring generation is cheap (O(1)-cheap). A Pascal string looks like this:
struct PString {
size_t length;
char* start;
}
PString substring(const PString* source, size_t offset, size_t length) {
// Using C99 Designated Initializer syntax:
return PString { .length = length, .start = source.start + offset };
}
The downside is that most of the C library and platform libraries use null-terminated strings and unless your Pascal-string ends in a null character you'll need to copy the substring to a new buffer (in O(n) time).
Of course, if you're feeling dangerous (and using mutable character buffers) then you can hack it to temporarily insert a null-terminator, like so:
struct CStr {
char* start;
char* end;
char temp;
}
CStr getCStr(PString* source) {
char* terminator = (source.start + source.length);
char previous = *terminator;
*terminator = '\0';
return CStr { .start = source.start, .end = terminator, .temp = previous };
}
void undoGetCStr(CStr cstr) {
*cstr.end = cstr.temp;
}
Used like so:
PString somePascalString = doSomethingWithPascalStrings();
CStr temp = getCStr( somePascalString );
printf("My Pascal string: %s", temp.start ); // using a function that expects a C-string
undoGetCStr( temp );
...which then gives you O(1) PString-to-CString performance, provided you don't care about thread-safety.
Need to be a char?
Because that only work when is a "string"
So maybe you need this
char reg[] = "[R5]";
Then you can do the other thing
or just split the string like this question

Can the following be made simpler / more efficient?

I'm trying to convert some code from a dynamic-typed language to C. Please
bear with me as I have no practical experience yet with C.
I have a dispatcher function that decides how to convert it's input based on
the value of the flag argument.
void output_dispatcher(char *str, int strlen, int flag) {
char output[501];
char *result;
switch (flag) {
/* No conversion */
case 0:
result = str;
break;
case 1:
result = convert_type1(output, str, strlen);
len = strlen(result);
break;
/* ... */
}
/* do something with result */
}
I currently have 5 different output converters and they all (even future
ones) are guaranteed to only produce 300-500 characters. From my reading, it
is preferable to use a heap variable than dynamically allocate space on the
stack, if possible. The function declaration for one looks like:
static char * convert_type1(char *out, const char *in, int inlen);
I want to avoid the strlen in the dispatcher, since it is uncessary to
recalculate the output size because the output converters know it when they
construct the output. Also, since I'm passing in a pointer to the output
variable, I shouldn't need to return the result pointer, right? So I modify
it to the following, but get an 'incompatible type' compilation error.
void output_dispatcher(char *str, int strlen, int flag) {
char output[501];
switch (flag) {
/* No conversion */
case 0:
output = str; /* ERROR: incompatible type */
break;
case 1:
strlen = convert_type1(output, str, strlen);
break;
/* ... */
}
/* do something with result */
}
Can this approach work, or is there a better way to go?
To avoid the recalculation your output converters would need to have a prototype like this:
static char * convert_type1(char *out, const char *in, int *len);
called thus:
result = convert_type1(output, str, &strlen);
Internally the output converter would need to read the contents of the pointer now containing the string length, and overwrite the contents of that pointer before returning.
On the issue of heap vs stack, indeed you need to use the heap since variables allocated on the stack will disappear as soon as the function ends.
The line:
output = str;
is giving you problems because, while arrays and pointers are similar, they're not the same.
"output" is an array, not a pointer.
str = output;
will work, because a char ptr is much like an array variable.
But the opposite does not because the "output" variable is not just the pointer to the array, but the array itself.
For example, if you had:
char output[501];
char output1[501];
and you did:
output1 = output;
This would be ok, and C would copy the contents of the output array in to the output1 array.
So, you're just a little confused about arrays and ptrs.
char output[501];
output = str; /* ERROR: incompatible type */
=>
strncpy(output, str, sizeof(output));
Note, you should check if 'output' is big enough to hold 'str'
The error in this case makes sense. output is a buffer that will hold come char data, while str is a pointer to some other area in memory. You don't want to assign the address of what str is pointing to output, right? If you want to go with this approach I think would just copy the data pointed to by str into output. Better yet just use str if no conversion is required.
C does not allow arrays to be modified by direct assignment - you must individually modify the array members. Thus, if you want to copy the string pointed to by str into the array output, you must use:
strcpy(output, str);
or perhaps
memcpy(output, str, strlen + 1);
(In both cases, after first checking that strlen < sizeof output).
Note that naming a local variable strlen, thus shadowing the standard function of that name, is going to more than a little confusing for someone who looks at your code later. I'd pick another name.

Structure Problem in C

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

Copying a part of a string (substring) in C

I have a string:
char * someString;
If I want the first five letters of this string and want to set it to otherString, how would I do it?
#include <string.h>
...
char otherString[6]; // note 6, not 5, there's one there for the null terminator
...
strncpy(otherString, someString, 5);
otherString[5] = '\0'; // place the null terminator
Generalized:
char* subString (const char* input, int offset, int len, char* dest)
{
int input_len = strlen (input);
if (offset + len > input_len)
{
return NULL;
}
strncpy (dest, input + offset, len);
return dest;
}
char dest[80];
const char* source = "hello world";
if (subString (source, 0, 5, dest))
{
printf ("%s\n", dest);
}
char* someString = "abcdedgh";
char* otherString = 0;
otherString = (char*)malloc(5+1);
memcpy(otherString,someString,5);
otherString[5] = 0;
UPDATE:
Tip: A good way to understand definitions is called the right-left rule (some links at the end):
Start reading from identifier and say aloud => "someString is..."
Now go to right of someString (statement has ended with a semicolon, nothing to say).
Now go left of identifier (* is encountered) => so say "...a pointer to...".
Now go to left of "*" (the keyword char is found) => say "..char".
Done!
So char* someString; => "someString is a pointer to char".
Since a pointer simply points to a certain memory address, it can also be used as the "starting point" for an "array" of characters.
That works with anything .. give it a go:
char* s[2]; //=> s is an array of two pointers to char
char** someThing; //=> someThing is a pointer to a pointer to char.
//Note: We look in the brackets first, and then move outward
char (* s)[2]; //=> s is a pointer to an array of two char
Some links:
How to interpret complex C/C++ declarations and
How To Read C Declarations
You'll need to allocate memory for the new string otherString. In general for a substring of length n, something like this may work for you (don't forget to do bounds checking...)
char *subString(char *someString, int n)
{
char *new = malloc(sizeof(char)*n+1);
strncpy(new, someString, n);
new[n] = '\0';
return new;
}
This will return a substring of the first n characters of someString. Make sure you free the memory when you are done with it using free().
You can use snprintf to get a substring of a char array with precision:
#include <stdio.h>
int main()
{
const char source[] = "This is a string array";
char dest[17];
// get first 16 characters using precision
snprintf(dest, sizeof(dest), "%.16s", source);
// print substring
puts(dest);
} // end main
Output:
This is a string
Note:
For further information see printf man page.
You can treat C strings like pointers. So when you declare:
char str[10];
str can be used as a pointer. So if you want to copy just a portion of the string you can use:
char str1[24] = "This is a simple string.";
char str2[6];
strncpy(str1 + 10, str2,6);
This will copy 6 characters from the str1 array into str2 starting at the 11th element.
I had not seen this post until now, the present collection of answers form an orgy of bad advise and compiler errors, only a few recommending memcpy are correct. Basically the answer to the question is:
someString = allocated_memory; // statically or dynamically
memcpy(someString, otherString, 5);
someString[5] = '\0';
This assuming that we know that otherString is at least 5 characters long, then this is the correct answer, period. memcpy is faster and safer than strncpy and there is no confusion about whether memcpy null terminates the string or not - it doesn't, so we definitely have to append the null termination manually.
The main problem here is that strncpy is a very dangerous function that should not be used for any purpose. The function was never intended to be used for null terminated strings and it's presence in the C standard is a mistake. See Is strcpy dangerous and what should be used instead?, I will quote some relevant parts from that post for convenience:
Somewhere at the time when Microsoft flagged strcpy as obsolete and dangerous, some other misguided rumour started. This nasty rumour said that strncpy should be used as a safer version of strcpy. Since it takes the size as parameter and it's already part of the C standard lib, so it's portable. This seemed very convenient - spread the word, forget about non-standard strcpy_s, lets use strncpy! No, this is not a good idea...
Looking at the history of strncpy, it goes back to the very earliest days of Unix, where several string formats co-existed. Something called "fixed width strings" existed - they were not null terminated but came with a fixed size stored together with the string. One of the things Dennis Ritchie (the inventor of the C language) wished to avoid when creating C, was to store the size together with arrays [The Development of the C Language, Dennis M. Ritchie]. Likely in the same spirit as this, the "fixed width strings" were getting phased out over time, in favour for null terminated ones.
The function used to copy these old fixed width strings was named strncpy. This is the sole purpose that it was created for. It has no relation to strcpy. In particular it was never intended to be some more secure version - computer program security wasn't even invented when these functions were made.
Somehow strncpy still made it into the first C standard in 1989. A whole lot of highly questionable functions did - the reason was always backwards compatibility. We can also read the story about strncpy in the C99 rationale 7.21.2.4:
The strncpy function
strncpy was initially introduced into the C library to deal with fixed-length name fields in
structures such as directory entries. Such fields are not used in the same way as strings: the
trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter
5 names to null assures efficient field-wise comparisons. strncpy is not by origin a “bounded
strcpy,” and the Committee preferred to recognize existing practice rather than alter the function
to better suit it to such use.
The Codidact link also contains some examples showing how strncpy will fail to terminate a copied string.
I think it's easy way... but I don't know how I can pass the result variable directly then I create a local char array as temp and return it.
char* substr(char *buff, uint8_t start,uint8_t len, char* substr)
{
strncpy(substr, buff+start, len);
substr[len] = 0;
return substr;
}
strncpy(otherString, someString, 5);
Don't forget to allocate memory for otherString.
#include <stdio.h>
#include <string.h>
int main ()
{
char someString[]="abcdedgh";
char otherString[]="00000";
memcpy (otherString, someString, 5);
printf ("someString: %s\notherString: %s\n", someString, otherString);
return 0;
}
You will not need stdio.h if you don't use the printf statement and putting constants in all but the smallest programs is bad form and should be avoided.
Doing it all in two fell swoops:
char *otherString = strncpy((char*)malloc(6), someString);
otherString[5] = 0;
char largeSrt[] = "123456789-123"; // original string
char * substr;
substr = strchr(largeSrt, '-'); // we save the new string "-123"
int substringLength = strlen(largeSrt) - strlen(substr); // 13-4=9 (bigger string size) - (new string size)
char *newStr = malloc(sizeof(char) * substringLength + 1);// keep memory free to new string
strncpy(newStr, largeSrt, substringLength); // copy only 9 characters
newStr[substringLength] = '\0'; // close the new string with final character
printf("newStr=%s\n", newStr);
free(newStr); // you free the memory
Try this code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* substr(const char *src, unsigned int start, unsigned int end);
int main(void)
{
char *text = "The test string is here";
char *subtext = substr(text,9,14);
printf("The original string is: %s\n",text);
printf("Substring is: %s",subtext);
return 0;
}
char* substr(const char *src, unsigned int start, unsigned int end)
{
unsigned int subtext_len = end-start+2;
char *subtext = malloc(sizeof(char)*subtext_len);
strncpy(subtext,&src[start],subtext_len-1);
subtext[subtext_len-1] = '\0';
return subtext;
}

Resources