Referring an array inside a C structure - c

I come from Java background and trying to understand C structures, pointers and arrays better. Here's the sample code that I am playing with:
If the following works:
#include <stdio.h>
int main(void) {
char string[] = "Hello";
printf("%c",string[0]);
return 0;
}
Why does the following return with an error?
#include <stdio.h>
int main(void) {
typedef struct{
int x;
char string[8];
}ST_DATA;
ST_DATA *my_data;
my_data->x = 100;
my_data->string = "Hello"; // issues a warning, described below
printf("%d",my_data->x); // works fine
printf("%c",my_data->string[0]);
return 0;
}
Following is the error that I am getting:
Compilation error time: 0 memory: 2292 signal:0
prog.c: In function ‘main’:
prog.c:12:18: error: incompatible types when assigning to type ‘char[8]’ from type ‘char *’
my_data->string = "Hello";
I tried with the following changes as well:
a)
my_data->string[] = "Hello";
This will give me the following error:
prog.c: In function ‘main’:
prog.c:12:18: error: expected expression before ‘]’ token
my_data->string[] = "Hello";
^
b)
my_data->string[8] = "Hello";
This returns with a runtime error. Presumably, the error occurs when I am printing the first character.
There must be something stupid that I am doing or expecting (being used to coding with other languages than C), but I can't seem to figure out why this is happening and how to get it to work. I'd greatly appreciate any pointers (ha! get it?)

In your first case, you are automatically allotting memory for char string[] = "Hello". The compiler takes care of memory management here.
In the second, my_data is a pointer and you need to allot memory to it manually, before you assign something to it.
You can:
ST_DATA *my_data = (ST_DATA *)malloc(sizeof(ST_DATA));
It'd be good you spend some time reading about automatic memory allocation and dynamic memory allocation.

strcpy() need to be used to copy strings into string members of structure ST_DATA.
strcpy(my_data->string, "Hello");
Before you have to allocate memory for your structure as,
ST_DATA *my_data = (ST_DATA *) malloc(sizeof(ST_DATA));
EDIT: The structure ST_DATA inside main() is just a declaration which tells compiler that it has members of what type they are. How can you use it until it is allocated memory. You can think ST_DATA as a data type similar to any other data types as int etc which has no meaning when they are not defined as int object which gets memory for i.

ST_DATA *my_data;
my_data->x = 100;
here my_data is a pointer so first allocate memory to it.
char string[] = "Hello";
here string is assigned value with declaration so it if fine. but in next code
my_data->string = "Hello";
is not ok since initialization can be done only with declaration. after declaration for string value has to be assigned using strcpy()

Related

warning C4090: 'function' : different 'const' qualifiers

I am observing error "warning C4090: 'function' : different 'const' qualifiers " because of below line of code. Going through other similar questions on SO I understand (not 100 percent) it is because of
--> const char* EmployeeList[] and my declaration in qsort of EmployeeList
#define Elements(array) (sizeof(array)/sizeof((array)[0]))
const char *EmployeeList[] =
{
"Larry Page", "Sergy Brin", "Sundar Pichai", "Merrisa Mayer"
};
// called from main
SortEmployee(EmployeeList, Elements(EmployeeList));
int Compare(const void *elemA, const void *elemB)
{
...
}
void SortEmployee(const char *EmployeeList[], size_t EmployeeCount)
{
qsort(EmployeeList, EmployeeCount, sizeof(EmployeeList[0]), Compare);
}
However I am unable to resolve it- Any pointers how to do it for array of strings.
The problem is qsort does not declare its argument as const, while your code does. That means qsort may (in theory) change data, pointed by EmployeeList. So, the compiler reports this error.
Here is the official example: https://msdn.microsoft.com/en-us/library/k77bkb8d.aspx
How ever, here is a simple version to demonstrate my idea:
void foo(char* a) {
*a = '1'; // I got pointer to char, and changed this char!
}
int main() {
const char *a = "A"; // I have "CONSTANT POINTER": it points to CONSTANT memory, that CAN NOT be changed (by the way, string constants can't in many environments).
foo(a); // I pass it to my function, that will change it.
return 0;
}
Image your compiler stores a in read-only memory (It can, because we told it "this is a pointer to READ ONLY data"). You then modify it (in main function). Something bad may happen. So, the compiler warns you "hey, you pass a pointer to constant data to some function, that does not know that this data is constant and may change it"

C Function returning an Array

I always thought that when you want to return an array from a function, the only way to do that was using pointers like so:
char * func();
But yesterday, while I was going through K & R, I noticed wrongly assumed that char x()[] is also a valid construct. So I went ahead to test this out and wrote up the following code:
#include <stdio.h>
#include <stdlib.h>
char string1[10] = "123456789";
char x(void)[10];
int main(void) {
printf("string returned by x() is %s",x());
return EXIT_SUCCESS;
}
char x(void)[10] {
return x;
}
Compiling using GCC on Windows, this threw the following errors:
..\src\07arrreturn.c:7:6: error: 'x' declared as function returning an array
..\src\07arrreturn.c: In function 'main':
..\src\07arrreturn.c:10:2: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat]
..\src\07arrreturn.c: At top level:
..\src\07arrreturn.c:14:6: error: 'x' declared as function returning an array
..\src\07arrreturn.c: In function 'x':
..\src\07arrreturn.c:15:2: warning: return makes integer from pointer without a cast [enabled by default]
What is happening? am I mis-understanding what the book says? How can you return more than one value (or address) from a function? Isn't that restricted by the fact that you only have a single limited size CPU register that can hold the return value? If you have to return a big chunk of data, you can do so only by returning the address to it right?
Whats the deal with char x()[]? Is such a thing even used?
EDIT: I DID in fact misread the stuff from K&R. See comment below.
char x()[] is also a valid construct
Not as-is, and not quite in this context.
You can use similar syntax to:
declare a pointer to array: char (*arrPtr)[20];
declare an array of function pointers: void (*foo[20])(void);
dereference the return value (pointer) of a function call: char *foo(); char c = foo()[0];
declare a function that returns a pointer to array: char (*foo())[20]
or the same thing with a function pointer: char (*(*foo)())[20]
Which one of these are you looking for?
The C standard (ISO/IEC 9899:2011) says unequivocally:
6.7.6.3 Function declarators (including prototypes)
Constraints
1 A function declarator shall not specify a return type that is a function type or an array
type.
Thus your code is invalid.
K&R C is quite old. In ANSI C (C89), functions returning arrays aren't allowed and what you see is the result of this. First, you get errors for the declaration of x() as a function returning an array and due to this error, x() is never correctly declared and thereby treated like a function returning an int (because this used to be the default return type). This returned int is then supposed to be interpreted as char * generating the final warning.
If you need to return an array, you can wrap it in a struct. Otherwise return a pointer (make sure that the memory it points to is valid after returning).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char string1[10] = "123456789";
struct ret_s {
char string1[10];
};
struct ret_s x(void);
int main(void) {
struct ret_s r = x();
printf("string returned by x() is %s\n", r.string1);
return EXIT_SUCCESS;
}
struct ret_s x(void) {
struct ret_s r;
strcpy(r.string1, string1);
return r;
}

Struggling with compiliation: Pointers in C

I've been programming in java for over a year now but am slowly teaching myself C / objectiveC whilst studying at uni from the book: Cocoa and Objective C - Up and Running. I'm still going through the introductory chapters familiarising myself with syntactical differences in C with java and have come across a section on dynamic memory, specifically on pointers. The example it provides is this:
#include <stdio.h>
#include <stdlib.h>
int* numbers;
numbers = malloc ( sizeof(int) * 10);
//create a second variable to always point at the
//beginning of numbers memory block
int* numbersStart;
numbersStart = numbers;
*numbers = 100;
numbers++;
*numbers = 200;
//use the 'numbersStart' variable to free the memory instead
free( numbersStart );
I understand the code - create an integer pointer, allocate 10 blocks of memory for it, create a second pointer to point at the first dynamic memory block of numbers, set the first block to 100, increment to the 2nd block and set that to 200, then use free() to free memory.
However, when I try to compile I get a series of errors. The code is saved in a c class called Dynamic.c in a folder called dynamic.
here is a print of what occurs in terminal:
gcc Dynamic.c -o Dynamic
Dynamic.c:13: warning: data definition has no type or storage class
Dynamic.c:13: error: conflicting types for ‘numbers’
Dynamic.c:12: error: previous declaration of ‘numbers’ was here
Dynamic.c:13: warning: initialization makes integer from pointer without a cast
Dynamic.c:13: error: initializer element is not constant
Dynamic.c:15: warning: data definition has no type or storage class
Dynamic.c:15: error: conflicting types for ‘numbersStart’
Dynamic.c:14: error: previous declaration of ‘numbersStart’ was here
Dynamic.c:15: error: initializer element is not constant
Dynamic.c:16: warning: data definition has no type or storage class
Dynamic.c:16: warning: initialization makes pointer from integer without a cast
Dynamic.c:17: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘++’ token
Dynamic.c:18: warning: data definition has no type or storage class
Dynamic.c:18: error: redefinition of ‘numbers’
Dynamic.c:16: error: previous definition of ‘numbers’ was here
Dynamic.c:18: warning: initialization makes pointer from integer without a cast
Dynamic.c:19: warning: data definition has no type or storage class
Dynamic.c:19: warning: parameter names (without types) in function declaration
Dynamic.c:19: error: conflicting types for ‘free’
/usr/include/stdlib.h:160: error: previous declaration of ‘free’ was here
If someone could explain why these errors occur I would be much obliged, I don't see why they should be as its an example from a book.
Thanks.
That program is no good. You need at least a main() function. Add:
int main(void)
{
Right after the #include lines, and add:
return 0;
}
at the very end, and it will compile.
Wrap it in a main() function:
#import <stdio.h>
#import <stdlib.h>
int main()
{
int* numbers;
numbers = malloc ( sizeof(int) * 10);
//create a second variable to always point at the
//beginning of numbers memory block
int* numbersStart;
numbersStart = numbers;
*numbers = 100;
numbers++;
*numbers = 200;
//use the 'numbersStart' variable to free the memory instead
free( numbersStart );
return 0;
}
You need to define a main function:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* numbers;
numbers = malloc ( sizeof(int) * 10);
...
free( numbersStart );
return EXIT_SUCCESS;
}
numbers = malloc ( sizeof(int) * 10);
This is a statement and you cannot have a statement outside of a function in C.
Organize your program with functions and put the statements in the functions body. This is correct:
// This defines a function named foo that takes no argument and returns no value
void foo(void)
{
int* numbers;
numbers = malloc ( sizeof(int) * 10);
//create a second variable to always point at the
//beginning of numbers memory block
int* numbersStart;
numbersStart = numbers;
*numbers = 100;
numbers++;
*numbers = 200;
//use the 'numbersStart' variable to free the memory instead
free( numbersStart );
}

Problem with the following code

I want to the know the problems with the code presented below. I seem to be getting a segmentation fault.
void mallocfn(void *mem, int size)
{
mem = malloc(size);
}
int main()
{
int *ptr = NULL;
mallocfn(ptr, sizeof(ptr));
*ptr = 3;
return;
}
Assuming that your wrapper around malloc is misnamed in your example (you use AllocateMemory in the main(...) function) - so I'm taking it that the function you've called malloc is actually AllocateMemory, you're passing in a pointer by value, setting this parameter value to be the result of malloc, but when the function returns the pointer that was passed in will not have changed.
int *ptr = NULL;
AllocateMemory(ptr, sizeof(ptr));
*ptr = 3; // ptr is still NULL here. AllocateMemory can't have changed it.
should be something like:
void mallocfn(void **mem, int size)
void mallocfn(int **mem, int size)
{
*mem = malloc(size);
}
int main()
{
int *ptr = NULL;
mallocfn(&ptr, sizeof(ptr));
*ptr = 3;
return;
}
Because you need to edit the contents of p and not something pointed b p, so you need to send the pointer variable p's address to the allocating function.
Also check #Will A 's answer
Keeping your example, a proper use of malloc would look more like this:
#include <stdlib.h>
int main()
{
int *ptr = NULL;
ptr = malloc(sizeof(int));
if (ptr != NULL)
{
*ptr = 3;
free(ptr);
}
return 0;
}
If you're learning C I suggest you get more self-motivated to read error messages and come to this conclusion yourself. Let's parse them:
prog.c:1: warning: conflicting types for built-in function ‘malloc’
malloc is a standard function, and I guess gcc already knows how it's declared, treating it as a "built-in". Typically when using standard library functions you want to #include the right header. You can figure out which header based on documentation (man malloc).
In C++ you can declare functions that have the same name as already existing functions, with different parameters. C will not let you do this, and so the compiler complains.
prog.c:3: warning: passing argument 1 of ‘malloc’ makes pointer from integer without a cast
prog.c:3: error: too few arguments to function ‘malloc’
Your malloc is calling itself. You said that the first parameter was void* and that it had two parameters. Now you are calling it with an integer.
prog.c:8: error: ‘NULL’ undeclared (first use in this function)
NULL is declared in standard headers, and you did not #include them.
prog.c:9: warning: implicit declaration of function ‘AllocateMemory’
You just called a function AllocateMemory, without telling the compiler what it's supposed to look like. (Or providing an implementation, which will create a linker error.)
prog.c:12: warning: ‘return’ with no value, in function returning non-void
You said that main would return int (as it should), however you just said return; without a value.
Abandon this whole idiom. There is no way to do it in C without making a separate allocation function for each type of object you might want to allocate. Instead use malloc the way it was intended to be used - with the pointer being returned to you in the return value. This way it automatically gets converted from void * to the right pointer type on assignment.

Initialization of a pointer array

I'm facing a problem initializing an array with pointers to members of a structure. The structure members have to be accessed through a structure pointer. The reason for this is we initialize the pointer at runtime to a memory mapped address location. The following code snippet is an example of the problem;
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
long* lp;
}T;
typedef struct
{
long l;
}F;
F* f;
T t[] =
{
{ &f->l }
};
void init (void)
{
f = (F*) 0x08000100;
}
int main (void)
{
init();
return EXIT_SUCCESS;
}
The compiler output is the following;
gcc -O0 -g3 -Wall -c
-fmessage-length=0 -osrc\Test.o ..\src\Test.c ..\src\Test.c:18:
error: initializer element is not constant
..\src\Test.c:18: error: (near initialization for `t[0].lp')
..\src\Test.c:18: error: initializer element is not constant
..\src\Test.c:18: error: (near initialization for `t[0]')
Build error occurred, build is stopped
The problem here is we initialize the pointer at runtime, the compiler doesn't know where it can find the structure members. We cannot work around the structure pointer as we don't wan't to use the linker script for this.
Any ideas how to get around this one?
T t[] =
{
{ &f->l }
};
The address of an element (e.g. &f->l) is only known at run-time.
Such a value cannot be used for compile-time initialization (which is what's being done here).
The t[] array cannot be filled out until runtime - because the address of F isn't known until runtime.
You could initialize T[] to {NULL} and patch it in post-init.
Another approach is to initialize the members of T to just simply be the offset within the structure, and after you init f, to walk through the array and adjust the pointer locations by adding the address of f. This technique is similar to what is often used in linking.
Something like this:
#define MEMBER_OFFSET_OF(a,b) &(((a*)0)->b)
T t[] =
{
{(long*)MEMBER_OFFSET_OF(F, l)}
};
const int numElementsInT = sizeof(t) / sizeof(t[0]);
void init()
{
f = (F*) 0x08000100;
for (int i= 0; i < numElementsInT; i++)
{
t[i].lp += (unsigned int)f;
}
}
Lets imagine that you could use non-constant data to initialize a global: you still have a huge problem.
When t is initialized, f still has an indeterminate value: this happens before init() executes and assigns your magic address. Because of this, even if you could use &f->l, you'd have to reset all places it's been used, anyway.
Technically speaking for a C90 compiler there is no way around this. For the initialization idiom,
declarator = initialization sequence
the initialization sequence needs to be a constant expression, i.e. one which can be computed at compile-time or at link-time. So,
int a;
int *b[] = { &a };
works, while
void foo() {
int a;
int *b[] = { &a };
}
will not because the address of the automatic a isn't computable before runtime.
If you switch to C99, the latter will work. Your code however still is beyond what a C99 compiler can precompute. If you switch to C++ your code would work, at least Comeau doesn't object.
Edit: of course Roger is correct in that this doesn't solve your problem of having an incorrect dereferencing through a NULL pointer.

Resources