I am having a confusing issue -- for me at least, this may be very simple and I am missing something. I am trying to initialize a 2D array of variable size, The array is a part of a struct. I am having no issue allocating memory for the array but when I try to assign characters to the array, or print them I receive unexpected results =/
My last attempt has shown that no matter when character I assign to the array, when I print a '[' will be printed... that was the first time I was actually able to print anything. My previous attempts returned seg faults. Here is the code, what am I missing. Thank you.
typedef struct world_map {
char ** map_array;
int X, Y;
} MAP_s;
//
MAP_s * map;
int init_map_array(void) {
int i; // temp
map = malloc(sizeof (MAP_s));
map->X = 20; // Columns
map->Y = 10; // Rows
//
map->map_array = malloc(map->Y * (sizeof (char *)));
//
if (map->map_array == 0) {
printf("ERROR: out of memory!");
return -1;
} else {
for (i = 0; i < map->Y; ++i) {
map->map_array[i] = malloc(map->X * sizeof (char));
if (map->map_array[i] == 0) {
printf("ERROR: out of memory!");
return -1;
}
}
}
int curr_pos_x, curr_pos_y;
int limit_x = map->X;
int limit_y = map->Y;
//
for (curr_pos_y = 0; curr_pos_y < limit_y; ++curr_pos_y) {
for (curr_pos_x = 0; curr_pos_x < limit_x; ++curr_pos_x) {
map->map_array[curr_pos_y][curr_pos_x] = "#";
}
}
return 1;
}
int draw_map(void) {
int curr_pos_x, curr_pos_y;
int limit_x = map->X;
int limit_y = map->Y;
//
for (curr_pos_y = 0; curr_pos_y < limit_y; ++curr_pos_y) {
for (curr_pos_x = 0; curr_pos_x < limit_x; ++curr_pos_x) {
printf("%c", map->map_array[curr_pos_y][curr_pos_x]);
}
printf("\n");
}
}
int main(void) {
init_map_array();
draw_map();
//
printf("STRUCT: %i\n", sizeof (map));
printf("X: %i\n", sizeof (map->X));
printf("Y: %i\n", sizeof (map->Y));
printf("ARRAY: %i\n", sizeof (map->map_array));
return (EXIT_SUCCESS);
}
As a side note, those 4 printf at the end all return "4", I'm fairly certain that if a struct contains 3 elements which are each 4 bytes that it should be larger than 4 bytes itself...
Seems to work fine for me, but there is one error (somehow my GCC was "smart" enough to handle it but it's still an error):
map->map_array[curr_pos_y][curr_pos_x] = "#";
That assigns a char * (pointer to a char in the data segment) instead of a char which will of course result in weird characters. Change "#" to '#' and it should work.
Also, regarding your printfs at the end: they should look like this:
printf("STRUCT*: %lu\n", sizeof (map)); // Prints sizeof(MAP_s *) == sizeof(void *) == 4;
printf("STRUCT: %lu\n", sizeof (*map)); // Prints sizeof(MAP_s) == 16 on my system (iMac w/ Mac OS X),
// alignment and native pointer size might give you different values.
printf("X: %d\n", map->X); // Prints the X dimension. No sizeof.
printf("Y: %d\n", map->Y); // Prints the Y dimension. No sizeof.
You can't print the size of the map->map_array as sizeof works at compile-time and can only return constants for types where the size is known at compile-time. The only way to determine the size of map_array is to save the size argument you gave to malloc in a variable.
Try
map->map_array[curr_pos_y][curr_pos_x] = '#';
instead of
map->map_array[curr_pos_y][curr_pos_x] = "#";
map->map_array[curr_pos_y][curr_pos_x] is of type char and you are assigning a string constant to it.
Related
I am getting a segmentation fault from the below program.
#include <stdio.h>
#include <string.h>
void removeProcess(int*, int);
void removeProcessN(char**, int, int);
void main() {
int numPro = 0, quanTime = 0, contTime = 0, i, elemNum, time = 0;
//Supply variables with user input
printf("Enter number of processes: ");
scanf("%d", &numPro);
printf("Enter context switch time: ");
scanf("%d", &contTime);
printf("Enter quantum of time: ");
scanf("%d", &quanTime);
//Create array of number of process time
int proTime[numPro];
//Create string array for better output
char *proNames[numPro];
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
sprintf(proNames[i], "p%d", i);
}
elemNum = 0;
//While a process remains active
while (numPro != 0) {
//Retrieves the element being worked with
elemNum = elemNum % numPro;
//Describe process working with
printf("Executing process %s\nStart time = %d\n", proNames[elemNum], time);
proTime[elemNum] -= quanTime;
//If process time complete, remove process
if (proTime[elemNum] <= 0){
removeProcess(proTime, elemNum);
removeProcessN(proNames, elemNum, numPro);
--numPro;
}
//Add amount of time with context time
time = time + quanTime + contTime;
elemNum++;
}
}
/**
*#param *array pointer to an array of integers
*#param elem int of the element to remove
* Removes an element 'elem' from the supplied integer array.
*/
void removeProcessN(char **array, int numElem, int elem) {
char *temparray[numElem - 1];
//Copy array to temparray except for elem to remove
int i;
for (i = 0; i < elem; i++) {
if (i == numElem) {
continue;
} else {
temparray[i] = array[i];
}
}
//End by setting the pointer of array to the temparray
array = temparray;
}
/**
*#param *array pointer to an array of integers
*#param elem int of the element to remove
* Removes an element 'elem' from the supplied integer array.
*/
void removeProcess(int *array, int elem) {
//Number of elements in the array
int numElem = sizeof(array) / sizeof(int);
int temparray[numElem - 1];
//Copy array to temparray except for elem to remove
int i;
for (i = 0; i < numElem; i++) {
if (i == elem) {
continue;
} else {
temparray[i] = array[i];
}
}
//End by setting the pointer of array to the temparray
array = temparray;
}
I know the segmentation fault is coming from sprintf. I am trying to simulate how an operating system would complete a process using round robin. I have tried using sprintf because that's what tutorials were saying online to use when trying to manipulate strings. The removeProcessN is just removing an index from the array proNames. I am mostly just concerned with the sprintf.
I have tried malloc when I do the sprintf but it would not even compile at that point. If someone could offer an explanation I'd be appreciative.
The problem here is that proNames is an array of pointers, but they are
uninitialized, so passing it to sprintf to write something, will crash. You
would have either use a double array or allocate memory with malloc. But as
you are only printing integers and the string representatuion of integers has a
maximal length, allocating memory with malloc will be more harder, because you
have to check that malloc doesn't return NULL, you have to free the memory
later, etc.
So I'd do:
char proNames[numPro][30]; // 28 characters for an int (usually 4 bytes long)
// should be more than enough
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
sprintf(proNames[i], "p%d", i);
}
Your removeProcessN would need to change as well:
void removeProcessN(int numElem, int elem, int dim, char (*array)[dim]) {
for(int i = elem; i < numElem - 1; ++i)
strcpy(array[i], array[i+1]);
array[numElem - 1][0] = 0; // setting last element to empty string
}
Note that I moved the array argument at the last position, otherwise numElem
is not known and the compiler would return an error.
And now you can call it like this:
removeProcessN(elemNum, numPro, 30, proNames);
The 30 comes from the char proNames[numProp][30]; declaration.
I'd like to comment on the last line of your function removeProcessN:
//End by setting the pointer of array to the temparray
array = temparray;
That is not correct, first because temparray is local variable and ceases to
exist when the function returns. And array is local variable in the function,
so changing it doesn't affect anybody.
The alternative with memory allocation would look like this:
char *proNames[numPro];
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
int len = snprintf(NULL, 0, "p%d", i);
proNames[i] = malloc(len + 1);
if(proNames[i] == NULL)
{
// error handling, free the previously allocated
// memory, and return/exit
}
sprintf(proNames[i], "p%d", i);
}
and removeProcessN:
void removeProcessN(char **array, int numElem, int elem) {
char *to_remove = array[elem];
for(int i = elem; i < numElem - 1; ++i)
array[i] = array[i+1];
free(to_remove);
array[numElem - 1] = NULL; // setting last element to NULL
// makes freeing easier as
// free(NULL) is allowed
}
And the way you originally called the removeProcessN would be OK.
If you eventually call removeProcessN for all processes, then all the memory
should be freed because removeProcessN frees it. If there are some elements
that remain in the array, then you have to free them later.
OP posted in the comments
My theory was that temparray would be a pointer to an array so I could just remove an index from the main array.
So when I say array = temparray, the pointer for array points to temparray. I know it worked for removeProcess. Is it different for strings?
The array = temparray also has no effect in removeProcess, array is still
a local variable and changing where it points to has no effect at all, because
you are changing a local variable only.
Besides the code is wrong:
int numElem = sizeof(array) / sizeof(int);
this only works for pure arrays, it does not work for pointers because
sizeof(array) returns you the size that a pointer of int needs to be stored.
Like the other function, you need to pass the site the array to the function.
If you say that this function worked, then just only by accident, because it
yields undefined behavior. By incorrectly calculating the number of elements,
temparray will have the wrong size, so here temparray[i] = array[i]; you may
access beyond the bounds which leads to undefined behaviour. Undefined behaviour
means that you cannot predict what is going to happen, it could be anything from
crashing to formatting your hard drive. Results that result from undefined
behaviour are useless.
And again array = temparray; just changes where the local variable array is
pointing, the caller of removeProcess doesn't see that.
The correct version would be:
int removeProcess(int *array, int elem, int numElem) {
if(array == NULL)
return 0;
// nothing to do if the elemnt to be removed is
// the last one
if(elem == numElem - 1)
return 1;
// overwriting the memory, because memory
// regions overlap, we use memmove
memmove(array + elem, array + elem + 1, numElem - elem - 1);
return 0;
}
So, to make it clear:
Let's look at this code:
void sum(int *array, size_t len);
{
int c[len];
array = c;
}
void bar(void)
{
int x[] = { 1, 3, 5 };
size_t len = sizeof x / sizeof *x;
sum(x, sizeof x / sizeof *x);
printf("x[0] = %d, x[1] = %d, x[2] = %d\n", x[0], x[1], x[2]);
}
sum has only a copy of the pointer you've passed in bar, so from bar's
point of view, sum changed the copy, so bar will print
x[0] = 1, x[1] = 3, x[2] = 5.
But if you want that the caller sees any change, then you to access through the
pointer:
void sum(int *array, size_t len)
{
int c[len];
for(size_t i = 0; i < len; ++i)
array[i] += 10;
array = c;
}
With this version bar would print x[0] = 11, x[1] = 13, x[2] = 15 and
and array = c will have no effect on bar.
I am scanning for values using function .
int **array(int * counter) {
int **vrat;
int max = 5;
int index = 0;
int i;
vrat = malloc(max*sizeof(int*));
for ( i = 0; i < max ; i++) {
vrat[i] = malloc(2 * sizeof(int));
}
int x;
int y;
char c;
while (scanf("%d%c%d", &x, &c, &y) != EOF) {
vrat[index][0] = x;
vrat[index][1] = y;
index++;
}
*counter = index;
return vrat;
}
and calling it in main to return the array, which works .
int main()
{
int counter=0;
int **mej;
int gg;
mej = array(&counter);
int i;
gg = pocet(mej, &counter);
return 0;
}
what is bothering my mnd is "pocet" function , i am passing an array in it and want to print its value . but it always print undefined numbers
Function looks like this
int pocet(int array[][2],int *counter) {
int poc = 0;
int i;
for ( i =0; i < *counter ;i++) {
printf("cislo = %d", array[i][0]);
}
return poc;
}
as you can see , it has static 2nd dimension , how can i make this work?
You are allocating space for 5 pointers, you should multiply by the size of a pointer and not the size of an int, like this
vrat = malloc(max * sizeof(int *));
/* ^ pointer */
Although you can completely avoid the mistake by multiplying by the size of the pointer type like this
vrat = malloc(max * sizeof(*vrat));
and ALWAYS check that malloc() has not returned NULL before actually using the pointer.
Also, don't compare scanf() to EOF since it's very unlikely to get an EOF before an input error because it requires explicit input from the user, instead do this
while(scanf("%d%c%d", &x, &c, &y) == 3)
The return type of your function should match that of the returned object, in this case int **, change the function signature to
int **array(int *content)
vrat = malloc(max*sizeof(int*));
How do you know whether the memory successfully got allocated or not?
Always check the pointer returned by malloc & family functions for equivalence with NULL to avoid possible SegFault.
while (scanf("%d%c%d", &x, &c, &y) != EOF)
What if there's matching failure for c? Then scanf will return 1 and while will still go for iteration even if scanf could not store values in c and y.
So always compare scanf return value with no. of arguments instead of EOF
while (scanf("%d%c%d", &x, &c, &y) != EOF) {
vrat[index][0] = x;
vrat[index][1] = y;
index++;
}
Here what if index >= max?
Since you have allocated memory for only max integer pointers you must not try to access the memory beyond the allocated chunk.
Solution: Change while condition to
while ((scanf("%d%c%d", &x, &c, &y) == 3) && (index < max))
So the correct code snippet would be:
vrat = malloc(max*sizeof(int*));
if(!vrat)
{
printf("vrat: malloc failed!\n");
exit(1);
}
for ( i = 0; i < max ; i++) {
vrat[i] = malloc(2 * sizeof(int));
if(!vrat[i])
{
printf("vrat[%d]: malloc failed!\n", i);
exit(1);
}
}
int x;
int y;
char c;
while ((scanf("%d%c%d", &x, &c, &y) == 3) && (index < max)) {
vrat[index][0] = x;
vrat[index][1] = y;
index++;
}
An int** is not an int[][2]. The first is a pointer to pointers to int while the second (as an argument) is a pointer to int[2]. You cannot convert between the two the way you tried. You should have gotten a compiler warning/error about this.
The easiest way to fix this is to have pocet take an int** as the first argument. Fix the issues others have mentioned as well.
You have defined int **vrat;
When you do malloc, you need to use int ** or int * and not int
/* program to accept and print 5 strings using pointers */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define SIZE 100
int main()
{
char **s;
int i;
s = (char *)malloc(sizeof(char)*5);
for(i=0;i<5;i++)
{
*(s+i) = (char *)malloc(sizeof(char)*SIZE);
}
printf("enter 5 strigs\n");
for(i = 0;i<5;i++)
{
fgets((s+i),SIZE,stdin);
}
//printing the strings
for(i = 0;i<5;i++)
{
puts((s+i));
}
return 0;
}
This program accepts 5 strings from keyboard and prints on screen.It works properly but shows many warnings.Is there any other ways to do same operation(using pointers only).please suggest me.
The biggest issue in your code is that you do not allocate enough memory to s:
s = malloc(sizeof(char*)*5);
// ^
// Add an asterisk here
Otherwise, it's undefined behavior.
Second biggest is that you are not freeing any of the memory that you allocated. This is a memory leak. To do it properly you need a loop that calls free on every element of s, and then on the s itself:
for(i = 0;i<5;i++) {
free(s[i]);
}
free(s);
Finally, you should not be casting the results of malloc.
As a point for style, consider defining a constant for the number of elements in s, in the same way that you defined SIZE instead of using 100 directly. It may also make sense to switch to array-style dereference, rather than doing pointer arithmetic manually, i.e. puts(s[i]); instead of puts((s+i));
int main()
{
char **s;
int i;
s = (char **)malloc(sizeof(char*)*5); //double pointer (char**)
for(i=0;i<5;i++)
{
*(s+i) = (char *)malloc(sizeof(char)*SIZE);
}
printf("enter 5 strigs\n");
for(i = 0;i<5;i++)
{
fgets(*(s+i),SIZE,stdin); // first location *(s+0)
}
//printing the strings
for(i = 0;i<5;i++)
{
puts(*(s+i)); // first location *(s+0)
}
return 0;
}
so I'm trying to write a function that concats a char**args to a char*args
What I have so far is":
char *concat(char **array)
{
int size = 0;
int i=0;
int j=0;
int z=0;
while (array[i]!=NULL)
{
printf(" %s \n", array[i]);
size = size + sizeof(array[i])-sizeof(char); //get the total size, minus the
//size of the null pointer
printf("%d \n",size);
i++;
}
size = size+1; //add 1 to include 1 null termination at the end
char *newCommand = (char*) malloc(size);
i=0;
while(i<sizeof(newCommand))
{
j=0;
z=0;
while (array[j][z]!='\0')
{
newCommand[i] = array[j][z];
i++;
z++;
}
j++;
}
newCommand[sizeof(newCommand)-1]='\0';
return newCommand;
}
this doesn't seem to work. Anyone know what's wrong?
I'd do it like this (untested):
int size = 0;
int count = 0;
while (array[count]) {
size += strlen(array[i]);
count++;
}
char *newCommand = malloc(size + 1);
char *p = newCommand;
newCommand[0] = 0; // Null-terminate for the case where count == 0
for (int i = 0; i < count; i++) {
strcpy(p, array[i]);
p += strlen(array[i]);
}
First, your size calculation was wrong. You wanted the size of the strings, but sizeof(array[i]) gives you the size of a single element in your array which is a pointer and thus 4 (32-bit) or 8 (64-bit). You need to use strlen instead.
Next, your manual copying was also off. It's easier to do it with a moving pointer and strcpy (which is to be avoided normally but we've calculated the sizes with strlen already so it's OK here). The use of strcpy here also takes care of null termination.
Main issue is that you keep using sizeof() with a pointer argument, whereas I think you are trying to get the size of the corresponding array.
sizeof() can only give you information that's available at compile time, such as the sizes of raw types like char and int, and the sizes of arrays with a fixed length such as a char[10]. The sizes of the strings pointed to by a char* is only computable at run time, because it depends on the exact values passed to your function.
For sizeof(newCommand) you probably need size, and for sizeof(array[i]), you probably need strlen(array[i]).
I'm getting some strange behaviour here. Any help would be great.
I start like this:
int *event_positions = (int *) malloc(1 * sizeof(int)); // let us start with 1 and then add more within the method. This should continue until we have all the flags we want.
int number_of_flags = event_extractor(vocal_data, size, event_positions);
// HERE I WOULD LIKE TO USE THE VALUES OF event_positions BUT THE ARE WEIRD I.E. THEY DON'T MATCH THE VALUES BEING PRINTED IN THE LAST METHOD.
Event extractor then passes on the variable to another method. Simplified this looks like this:
int event_extractor (int *audio_samples, unsigned int size_of_audio ,int *event_flags)
{
int number_of_flags = apply_threshold (lopass_samples, length, event_flags);
// PRINT ARRAY event_flags HERE
// VALUES ARE INCORRECT AND WEIRD
}
The last method:
int apply_threshold (int *audio_samples, unsigned int size_of_audio, int *event_flags)
{
// DO SOME STUFF HERE.
// PRINT THE ARRAY WHICH SHOW THE CORRECT VALUES.
}
I hope this is clear. Basically I have an array which I pass as an argument and am having trouble accessing those values after the method has finished.
EDIT 1
First File:
int *event_positions = (int *) malloc(1 * sizeof(int)); // let us start with 1 and then add more within the method. This should continue until we have all the flags we want.
int number_of_flags = event_extractor(vocal_data, size, event_positions);
Second File:
int apply_threshold (int *audio_samples, unsigned int size_of_audio, int *event_flags)
{
int flag = 0; // this will be the number of flags that I have
bool run = true; // this will make sure that a minimum amount of time passes before I grab another flag. It's a guard.
int counter = 0; // this is the counter for the above guard.
printf("\n\nCURRENT MINIMUM TIME: 20100 SAMPLES \n\n");
// event_flags[0] = 1; // this first one is a dud. within the loop we will automatically start adding flags
int threshold = calculate_threshold_value(audio_samples, size_of_audio);
printf("\n\n this is the threshold %d \n\n", threshold);
int length = (int)size_of_audio;
for (int i = 0; i < length; i++)
{
if (audio_samples[i] > threshold && run)
{
// ** is this realloc working ?
event_flags = (int*)realloc(event_flags, sizeof(int) * (flag+1)); // reallocate the size of the array
event_flags[flag] = i;
// printf("FLAG CREATED! %i\n ", i);
printf("EVENT FLAG %i %i\n",flag, event_flags[flag] );
flag++;
run = false;
}
if (!run) {
counter++;
if (counter > 20100) { // hardcode minimum size for now.
counter = 0;
run=true;
}
}
}
printf("\n\n\n NUMBER OF EVENTS --- %d\n", flag);
for (int i = 0; i < flag; i++) {
printf("FLAG %i -- %d\n", i, event_flags[i]);
}
printf("\nFIVE samples before and after my second flag: \n 0 should indicate a reach in the threshold\n");
for (int i = 0; i <10 ; i++) {
printf("VOCAL SAMPLE %i %i \n", i-5,audio_samples[event_flags[1]+i-5] );
}
return flag;
}
EDIT 2
I've updated my code according to Erik's model. My loop now looks like this
if (audio_samples[i] > threshold && run)
{
// ** is this realloc working ?
// event_flags = (int*)realloc(event_flags, sizeof(int) * (flag+1));
*event_flags = (int*)realloc(*event_flags, sizeof(int) * (flag+1)); // reallocate the size of the array
*event_flags[flag] = i;
// printf("FLAG CREATED! %i\n ", i);
printf("EVENT FLAG %i %i\n",flag, *event_flags[flag] );
flag++;
run = false;
}
And now I'm getting an error that looks like this. Any ideas?
Are you reallocating event_flags in apply_threshold? If so, you need to let the caller get the updated pointer back.
Something like:
int apply_threshold (int *audio_samples, unsigned int size_of_audio, int **event_flags) {
*event_flags = realloc ...
}
...
int number_of_flags = apply_threshold (lopass_samples, length, &event_flags);
EDIT: In response to updated question:
event_flags = (int*)realloc(event_flags, sizeof(int) * (flag+1)); // reallocate the size of the array
This changes the local copy of the event_flags pointer. Caller will not see the change. Use the method I described above.
EDIT2: More detailed sample.
void foo(int * v) {
v = 0; // The local copy of main's myvar is now 0. main's actual myvar is unchanged
}
void bar(int ** v) {
*v = 0; // Main's myvar is now 0, we have a pointer to it and can modify it.
}
int main() {
int * myvar = (int *) malloc(1); // Allocate 1 byte and make myvar point at this byte.
foo(myvar); // Call foo, passing a *copy of* myvar, which also points at the allocated byte
bar(&myvar); // Call bar, passing a *pointer to* myvar, which again points to the allocated byte
}
EDIT3: In response to new question.
Is your "length" the number of ints or number of bytes? You're treating it as number of ints, which could cause your error if it really is number of bytes.
You need to pass a pointer to pointer or a reference to pointer. A realloc might be moving your memory to another position and the caller won't notice.
realloc() changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged to the minimum of the old and new sizes; newly allocated memory will be uninitialized. If ptr is NULL, then the
call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to mal‐
loc(), calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.