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 );
}
Related
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()
I know I will get many down grade regarding this question, but I still write following test code:
int *gPtr;
//I know I can NOT write below code line, but I need know WHY
gPtr = NULL;//or some other value which I want to init it
//int *gPtr = NULL; //this line should be OK
int main (void)
{
int *ptr;
ptr = NULL;
return 0;
}
The global *gPtr during compile will output error:
ptr.c:4:1: warning: data definition has no type or storage class [enabled by default]
ptr.c:4:1: error: conflicting types for ‘gPtr’
ptr.c:3:6: note: previous declaration of ‘gPtr’ was here
ptr.c:4:8: warning: initialization makes integer from pointer without a cast [enabled by default]
However, in the function, I did same code, but no compile error/warning, I would like to know:
what is the different between sign a value in global and function.
why compiler do NOT allow me sign value in global area.
what is different between int a = 0; and int a; a=0;//no other code between these two sentences
please give me advise for above three questions according to the compiler view(or you think it should have other explanation in some others view like coding standard?)
You can define a global variable with an initial value:
int *gPtr = NULL;
But you cannot do an assignment outside of a function scope.
The compiler (well, at least my clang compiler) actually interprets
gPtr = NULL;
in the global scope as
int gPtr = NULL;
which causes similar warnings and a conflicting types error:
warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
gPtr = NULL;
^~~~
error: redefinition of 'gPtr' with a different type: 'int' vs 'int *'
note: previous definition is here
int *gPtr;
Global variable without an explicit initial value are automatically initialized
to zero, therefore in your case
int *gPtr;
would be sufficient (as #WhozCraig already commented above).
This compiles fine:
#include <stdio.h>
/* int *gPtr; */
/* gPtr = NULL; */
int *gPtr = NULL;
int main (void)
{
int *ptr;
ptr = NULL;
return 0;
}
I suspect you had one of two problems. Firstly, you can't declare gptr, then assign NULL to it, and then do a int *gptr = NULL (which does the first two combined); hence I commented out the first two. You need one or the other. Secondly your line int *gPtr = NULL; was missing a semicolon.
vector_int.h is a header with self-made dynamic array (vector) structure.
test.c is a testing programm.
All code is bellow:
vector_int.h:
#include <stdio.h>
typedef struct
{
long int len; // Length
int *array; // Dynamic Array
} IntVector;
void ResizeIntVector(IntVector *vector, int size) // Resizing of vector
{
realloc(vector->array, size * sizeof(int));
vector->len = size; // Changing of length variable
}
void SetIntVectorCell(IntVector *vector, unsigned int cell_number, int cell_value) // Put cell_value in array[cell_number]
{
if (cell_number >= vector->len)
ResizeVectorInt(&vector, cell_number); // Grow size of memory if it's not enough
vector->array[cell_number] = cell_value;
}
test.c:
#include "vector_int.h"
#include <stdio.h>
int main()
{
IntVector vector;
int n;
scanf("%d", &n);
int i;
for (i = 0; i < n; i++) // testing
{
SetIntVectorCell(&vector, i, i);
printf("%d ", vector.array[i]);
}
return 0;
}
Logs:
1 0 D:\Work\Raspberry Pi\test.c In file included from D:\Work\Raspberry Pi\test.c
D:\Work\Raspberry Pi\vector_int.h In function 'ResizeIntVector':
11 2 D:\Work\Raspberry Pi\vector_int.h [Warning] incompatible implicit declaration of built-in function 'realloc' [enabled by default]
[Linker error] C:\Users\ALEXAN~1\AppData\Local\Temp\cccFKqxs.o:test.c:(.text+0x4a): undefined reference to `ResizeVectorInt'
collect2: ld returned 1 exit status
I think that there is error in using realloc function, but I thought that I did all right.
Please help me and find a mistake or mistakes.
You have a few problems:
The implicit declaration/realloc problem is because you need to include stdlib.h for the realloc signature. Without a function signature the compiler will make some assumptions about your function arguments and return value, then during linking, the linker complains about this if these assumptions don't match the actual function implementation.
You're passing realloc an address that hasn't been initialized. This is asking for trouble. Before using your vector variable, do some initialization:
vector->array = NULL;
vector->len = 0;
Furthermore, your usage of realloc is incorrect: it won't change the actual pointer that you give it, only the size of the memory block pointed to. You need to re-assign the pointer yourself. Note that realloc can return NULL upon failure, so do something like:
tmp = realloc(vector->array, size * sizeof(int));
if (tmp != NULL)
{
vector->array = tmp;
vector->len = size; // Changing of length variable
}
else handleAllocError();
Finally, don't define your functions in the header. This will work, but it's better to have an implementation file vector_int.c that defines the functions declared in the header.
You need a +1 in here:
ResizeVectorInt(&vector, cell_number + 1); // Grow size of memory if it's not enough
I'm trying to create a global array whose size is determined by an external parameter file at runtime.
I've seen other questions on this and tried:
int const Nt=1280;
double *Array = NULL;
Array = malloc(Nt * Nt * sizeof(double));
However, I get errors such as:
Error: Conflicting types for Array
Error: Initializer element is not constant
How can I create such a global array without needing to recompile every time I need to change its size?
Assignment is not allowed at global scope. You have to do it in a function instead.
int const Nt = 1280;
double *Array = NULL;
Assuming the above 2 statements are at global scope. They are examples of initialization because the statements assign value at the declaration itself. This is allowed at global scope and the initializers can be constant values, string literals or other variables accessible at this point.
const int Nt ; // Just declaration
Nt = 1280 ; // Error. Assignment is not allowed at global scope.
const char* myName = "CHP" ;
int a[] = { 11,22,33,44,55 } ;
And similarly in your example Array is just a declaration. Do the assignment in a function.
void assignArray() {
Array = malloc(Nt * Nt * sizeof(double));
// ...
printf("%d", sizeof(Array)/sizeof(Array[0]); // Size which is nothing but Nt*Nt
// 0 to (Nt * Nt) - 1
}
And regarding the segmentation fault, post more code.
Global function initializers have to be compiled directly into the executable. Therefore, they cannot contain any information that changes at runtime, and they cannot contain function calls. And the initializers must be in the same statement as the declaration.
WORKS:
int x = 1;
DOESN'T WORK:
int x;
x = 1;
You should move your initializer into a function if you can't fit it within those rules.
Do the initialization in a function (e.g. in main()):
int main() {
Array = malloc(dim1 * dim2 * sizeof(double));
...
}
double *Array = NULL;
This is fine (as long as you've included a header that defines NULL before you write it).
Array = malloc(dim1 * dim2 * sizeof(double));
You say this yields:
Error: Conflicting types for Array
Error: Initializer element is not constant
That is because the compiler is bending over backwards to accept your code, and manages to interpret the Array as an 'implicit int' variable, as if you wrote:
int Array = ...
Since int is not the same as double *, it gives you the conflicting types error.
The second message tells you that the initializer - the call to malloc() - is not a constant, and initializers outside functions must be constants. If you placed the line inside a function, then you'd have an assignment (not an initializer), and the code would be OK, though better written as:
if (Array == NULL)
Array = malloc(dim1 * dim2 * sizeof(double));
You should be compiling with more stringent compilation warnings. I get:
$ cat x.c
#include <stdlib.h>
double *Array = NULL;
Array = malloc(23 * 37 * sizeof(double));
$ gcc -g -std=c99 -pedantic -Wall -Werror -c x.c
x.c:3:1: error: data definition has no type or storage class [-Werror]
x.c:3:1: error: type defaults to ‘int’ in declaration of ‘Array’ [-Werror]
x.c:3:1: error: conflicting types for ‘Array’
x.c:2:9: note: previous definition of ‘Array’ was here
x.c:3:9: error: initialization makes integer from pointer without a cast [-Werror]
x.c:3:1: error: initializer element is not constant
cc1: all warnings being treated as errors
$
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.