This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm trying to practice my C by creating arrays of equal size (determined by the user's input) and populating them with random numbers. I'm running into some issues. First, my creation and allocation of the arrays:
srandom((int)time(NULL)); /* initialize random seed for later use*/
unsigned long arraySize = strtoul(argv[1], NULL, 0);
int *originalArray = malloc(arraySize * sizeof(int));
int *ascendingOrderArray = malloc(arraySize * sizeof(int));
int *descendingOrderArray = malloc(arraySize * sizeof(int));
Next, the loop wherein I populate the arrays with random numbers:
int i = 0;
int randInt;
/* Seed each array with identical randomly generated numbers */
while(i++ < arraySize){
randInt = (int)random()%100;
*originalArray++ = randInt;
printf("original array assign: %d\n", originalArray);
*ascendingOrderArray++ = originalArray;
printf("ascending array assign: %d\n", ascendingOrderArray);
*descendingOrderArray++ = originalArray;
printf("descending array assign: %d\n", descendingOrderArray);
}
Here, things get weird. I'm expecting each array to have the same number as that assigned to originalArray for each index. Yet the output I get from the printf statement does not reflect that. Moreover, the numbers are gigantic but they all have a similar base, starting with a 2 and extending for many digits. Should that be happening?
Finally, when I'm done with everything and do a little inconsequential printing and formatting, I try to free my arrays:
free(originalArray);
originalArray = NULL;
free(ascendingOrderArray);
ascendingOrderArray = NULL;
free(descendingOrderArray);
descendingOrderArray = NULL;
return 0;
But I'm getting a pointer being freed was not allocated error.
I'm sure I'm screwing up on multiple levels here, but the question is: where?
You have the same fundamental problem with all 3 arrays, but let's look at just one. Here you allocate it:
int *originalArray = malloc(arraySize * sizeof(int));
So the variable originalArray points to the block of allocated memory. Then you start using it to assign to the array:
*originalArray++ = randInt;
This is bad. You just incremented originalArray, and now have no pointer to the beginning of the memory block. What you should do is
originalArray[i] = randInt;
printf("original array assign: %d\n", originalArray[i]);
This way you're using the index i to say where in the array the number should go, and originalArray itself is still the pointer to the block of allocated memory, i.e. the beginning of your array.
Since originalArray is unchanged through all of this, when you
free(originalArray);
then originalArray is still the value that was returned from malloc, which is what free wants to get back.
Summary: you should always free the exact pointer that malloc returns, and you should never discard/change the value of that pointer.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
When I try to run the following logic snippits, I get segmentation faults, why? Sometimes I don't get segmentation faults but instead I get odd output that does not make sense...
1. Changing a string's character
char *str = "Hello!";
str[0] = 'h'; // SIGSEGV
2. Modifying the value of a pointer
int *num_ptr;
*num_ptr = 6; // SIGSEGV
3. Using an array or pointer returned from a function
int *getPoint()
{
int cords[2] = {10, 20};
return cords;
}
/* ... */
int *point = getPoint();
int total = point[0] + point[1]; // SIGSEGV (or sometimes total = 0?)
4. Looping through n-sized array in function
void print_loop(int *array)
{
for(int i = 0; i < sizeof(array); i++)
printf("array[%d] = %d\n", i, array[i]); // SIGSEGV
}
/* ... */
int nums[3] = {1, 2, 3};
print_loop(nums);
What do I do to fix each of these and understand why they happen?
char *str;
int *num_ptr;
int *point;
^^ this code just creates a variable for you to then use which is a pointer to memory. Realize it never allocates or reserves memory.
so for 2 where you do *num_ptr = 6; you are trying to put the value of 6 into memory pointed to by num_ptr. But num_ptr does not point anywhere yet, it either points to NULL or is uninitialized and contains some random number value. If it contains some random number value odds are it is not valid memory location, hence the segmentation violation. And if it were NOT to result in a SIGSEV and the code ran then it would be by chance you got lucky; you would never want to program this way having basic concepts of programming happen by chance.
Same principle applies for all your other examples. It doesn't matter the data type. It's the basic problem of having a pointer to memory, and whether or not you have (by whatever means) reserved or allocated some valid range of storage space (RAM, disk, wherever).
str[0] = 'h'; is the same thing as *str = 'h';
str[1] = 'h'; would be the equivalent of *(str+1) = 'h';
str[2] is *(str+2)
and so on,
where str is a pointer to the starting location of a range of memory,
then because str is of data type CHAR, +1 moves 1 byte, +2 moves 2 byte.
If it were of type INT where int is 4 bytes, then +1 would be the
initial memory location + 4.
Using an array or pointer returned from a function
This doesnt't work, because you create a pointer and reserve a memory area inside a function, without malloc. When this function ends, you lose this reserved area.
So, you can't make a function that returns a pointer this way. Read a little about malloc() function.
Looping through n-sized array in function
This isn't the right way to loop through a n-sized array, sizeof return the number of bytes that you need tho allocate that structure, not how many elements you have in the array. A suggestion is by as a parameter how many elements you have, if it is a string, you can use strlen, from string.h.
these are common pit falls when someone tries migrate to C from a virtual language such as Java, C#, Python, or JavaScript. The problem is that they do not understand the concept of memory management because virtual languages take care of that now. Hopefully new programmers wanting to learn C can be directed to this answer and avoid these pitfalls -- and ultimately prevent these types of questions from filling the front page of c every day. I am going to be short worded as possible, as I know that 90% of you have already looked at this paragraph and said "lol tl;dr".
What is a Segmentation Fault (seg fault)
It's when you try to access memory that's not yours. Or you try to write to memory that is read only -- The operating system is the one responsible for enforcing this.
An analogy: address in memory are like house address on the streets. And the things inside the houses would be the data itself. If you own a house, you go to its address and add and remove furniture as you please. If you don't own the house, you're simply breaking an entry and the police (The OS) arrest you (seg fault).
Common ways to get it
P1. Changing a string's character
char *str = "Hello!";
str[0] = 'h'; // SIGSEGV
Problem: a string literal (declared within quotes, "LIKE SO") may not be modified. Attempting to do so causes undefined behavior.
Solution: allocate your string in an array.
char str[] = "Hello!";
str[0] = 'h';
P2. Modifying the value of a pointer
int *num_ptr;
*num_ptr = 6; // SIGSEGV
Problem: num is pointer, but its address has not been defined. You can't derreference a pointer unless you give it a valid address.
Solution: Make sure you point your pointers®.
int *num_ptr;
int num;
num_ptr = # // num_ptr equals the address of num
*num_ptr = 6;
P3. Using an array or pointer returned from a function
int *getPoint()
{
int cords[2] = {10, 20};
return cords;
}
/* ... */
int *point = getPoint();
int total = point[0] + point[1]; // SIGSEGV (or sometimes total = 0?)
Problem: cords is an array with automatic storage inside the function getPoint(). When this function returns, the array no longer exists, which means that point now points to invalid memory.
Solution #1: allocate coords with dynamic memory using, for example, malloc(). Dynamic memory exists as long as your program is running, or until you release it with free().
int *getPoint()
{
int *cords = malloc(2 * sizeof(int)); // get 2 ints on permanent (heap) memory
cords[0] = 10;
cords[1] = 20;
return cords;
}
/* ... */
int *point = getPoint();
int total = point[0] + point[1];
free(point); // manual destroy
Solution #2: declare the array outside the function and pass its address to getPoint(). Now instead of returning the array, it receives and modifies it.
int *getPoint(int *cords)
{
cords[0] = 10;
cords[1] = 20;
return cords;
}
/* ... */
int cords[2];
int *point = getPoint(chords);
int total = point[0] + point[1]
P4. Looping through n-sized array in function
void print_loop(int *array)
{
for(int i = 0; i < sizeof(array); i++)
printf("array[%d] = %d\n", i, array[i]); // SIGSEGV
}
/* ... */
int nums[3] = {1, 2, 3};
print_loop(nums);
Problem: In C, there is nothing holding your hand. This means you have to keep track of your own damn array lengths.
Solution: Whenever you pass an array into a function, you MUST also pass the size of the array.
void print_loop(int *array, int array_len)
{
for(int i = 0; i < array_len; i++)
printf("array[%d] = %d\n", i, array[i]);
}
/* ... */
int nums[3] = {1, 2, 3};
print_loop(nums, 3);
"My program does not have a seg fault and/or but it gives a strange result"
Seg faults and things that should cause seg faults are known as "undefined behavior". This means that the error will be different based on what compiler is used, what OS, what CPU, ect. Some cases there will not be an error at all, however that does not mean its OK. It's like saying "If OJ can get away with it then so can I" and then being surprised by the results.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I am working on a project in which I need to read CSV lines from a text file into my program. I was given a code skeleton, and asked to fill in functionality. I have a struct containing a variable for each type of value I am going to receive, but my char array is causing segmentation faults.
Here is an excerpt of my code.
None of the exerpt is part of the given code, this is all mine:
My error is a Segmentation Fault(Core Dumped), due to the code within the get timestamp space.
my test file contained only one line,
5, 10:00:10, 1, 997
/*
* YOUR CODE GOES HERE:
* (1) Read an input csv line from stdin
* (2) Parse csv line into appropriate fields
* (3) Take action based on input type:
* - Check-in or check-out a patient with a given ID
* - Add a new health data type for a given patient
* - Store health data in patient record or print if requested
* (4) Continue (1)-(3) until EOF
*/
/* A new struct to hold all of the values from the csv file */
typedef struct {
int iD;
char *time[MAXTIME + 1];
int value;
int type;
}csv_input;
/* Declare an instance of the struct, and assign pointers for its values */
csv_input aLine;
int *idptr;
char timeval[MAXTIME + 1];
int *valueptr;
int *typeptr;
/*Note: because the time char is already a pointer, I did not make another one for it but instead dereferenced the pointer I was given */
idptr = &aLine.iD;
int j; /* iterator variable */
for(j; j < MAXTIME; j++){
*aLine.time[j] = timeval[j];
}
valueptr = &aLine.value;
typeptr = &aLine.type;
/* Get the Patient ID */
*idptr = getchar();
printf("%c", aLine.iD); /* a test to see if my pointers worked and the correct value was read */
/*Skip the first comma */
int next;
next = getchar();
/* get the timestamp */
int i;
for(i = 0; i < MAXTIME; i++)
{
while ((next = getchar()) != ',')
{
timeval[i] = next;
//printf("%s", aLine.time[i]);
}
}
First:
int j; /* iterator variable */
for(j; j < MAXTIME; j++){
You need to set j to some value, j=0 makes sense. Without this you're accessing an array with an uninitialized value and you're going to get UB with that.
Second:
/*Note: because the time char is already a pointer,
No, time is an array of pointers to characters, there is a difference there.
This line:
*aLine.time[j] = timeval[j];
won't work because, for one thing, of your statement but instead dereference the pointer I was given is making an incorrect assumption. Yes, you were given an array of pointers, but they don't point to anything, they are uninitialized and as such you can't deference them until you initialize them to a valid non-NULL value.
I think you were trying to do something like this:
aLine.time[j] = &timeval; //set the pointer to the local static array
but that's only going to work in the local function scope. It'd be better if you malloc to your array of pointers.
char *time[MAXTIME + 1];
this is an array of pointers (pointer to char array) and not an array of chars
The crash come from this line
*aLine.time[j] = timeval[j];
Because as I said aLine.time[j] is a pointer and you have not allocated memory for this pointer before filling its content
here is a very small structure used for indexing words of a file. Its members are a string (the word), an array of integers (the lines this word is found at), and an integer representing the index of the first free cell in the lines array.
typedef struct {
wchar_t * word;
int * lines;
int nLine;
} ndex;
ndex * words;
I am trying to allocate (ndex)es nb_words = 128 at a time, and (lines) nb_lines = 8 at a time, using malloc and realloc.
First question, what is the difference between malloc(number * size) and calloc(number, size) when allocating *words and/or *lines? Which should I choose?
Second question, I gdbed this:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400cb0 in add_line (x=43, line=3) at cx17.3.c:124
124 words[x].lines[words[x].nLine] = line;
(gdb) p words[43].nLine
$30 = 0
In other words, it consistently fails at
words[43].lines[0] = 3;
Since I allocate words by 128, and lines by 8, there is no reason the indexing worked for the 42 previous words and fail here, except if my allocating was botched, is there?
Third question: here are my allocations, what is wrong with them?
words = malloc(sizeof(ndex *) * nb_words);
short i;
for (i = 0; i < nb_words; i++) {
words[i].lines = malloc(sizeof(int) * nb_lines);
words[i].nLine = 0;
}
Should I initialize lines in a for(j) loop? I don't see why leaving it uninitialized would prevent writing to it, so long as it as been allocated.
This C is a very mysterious thing to me, thanks in advance for any hints you can provide.
Best regards.
This looks suspicious:
sizeof(ndex *)
You probably don't want the size of a pointer - you want the size of a structure. So remove the star.
Here:
words = malloc(sizeof(ndex *) * nb_words);
You are allocating space for some number of pointers (i.e., 4 bytes * nb_words). What you really need is to allocate some number of ndex's:
words = malloc(sizeof(ndex) * nb_words);
Also, calloc 0 initializes the returned buffer while malloc does not. See this answer.
malloc will allocate the requested space only. calloc will allocate the space and initialize to zero.
In your example, the segmentation fault is observed here words[x].lines[words[x].nLine] = line;. There could be 2 possibilities viz., allocation is wrong which I don't feel is the case. The more probable case would be words[x].nLine didn't evaluate to 0. Please print this value and check. I suspect this is some huge number which is forcing your program to access a memory out of your allocated space.
Others have answered this part, so I will skip it.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have 2 questions.
I want to create an array of files in C. But I'm not sure whether I have to malloc the size before or not.Can I just use FILE** files as an array or do I have to malloc them before. And if I have to make space, do I need to reserve 4 bytes (x86)?
I have the variable "char extra[8] = { 0xAE00AF00B000B100 };" and I want to assign it to the end of another char array[24]. Is there a faster way of doing that without having to type in every value by hand or using a for loop.
char extra[8] = { 0xAE00AF00B000B100 };
// index is a random place in the string
name[index] = '\0';
i = 0;
if (index > 16) {
for (i = 24-index; i < 8; i++) {
index++;
name[index] = extra[i];
}
}
else {
name[17] = 0xAE;
name[18] = 0x00;
name[19] = 0xAF;
name[20] = 0x00;
name[21] = 0xB0;
name[22] = 0x00;
name[23] = 0xB1;
name[24] = 0x00;
}
I need to add those extra bytes btw.
I want to create an array of files in C. But I'm not sure whether I
have to malloc the size before or not.Can I just use FILE** files as
an array or do I have to malloc them before. And if I have to make
space, do I need to reserve 4 bytes (x86)?
If you need to have an array of files, it is possible to use an array of pointers as follow:
#include <stdio.h>
FILE *array[NB_FILES];
Or you can do it dynamically if NB_FILES is only known at runtime.
#include <stdio.h>
#include <stdlib.h>
FILE **array = malloc(nb_files * sizeof *array);
I have the variable "char extra[8] = { 0xAE00AF00B000B100 };" and I want to assign it to the end of another char array[24]. Is there a faster way of doing that without having to type in every value by hand or using a for loop.
The standard C library provides the function memcpy, which is a builtin on many compiler (so it will be faster than a for loop).
#include <string.h>
char array[24];
char extra[8];
memcpy(array + sizeof array - sizeof extra - 1, extra, sizeof extra);
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
(C) realloc array modifies data pointed by items
Hello,
A nice weird bug I feel like sharing ;-) Requires some preliminary explanations:
First, I have a type of strings PString which hold their size (and a hash value), followed by a flexible array member with the bytes. Here is the type and kind of constructor (the printfl statement at the end is debug):
typedef struct {
size_t size;
uint hash;
char bytes[];
} PString;
// offset from start of pstring struct to start of data bytes:
static const size_t PSTRING_OFFSET = sizeof(size_t) + sizeof(uint);
PString * pstring_struct (string str, size_t size, uint hash) {
// memory zone
char *mem = malloc(PSTRING_OFFSET + size * sizeof(char));
check_mem(mem);
// string data bytes:
memcpy(mem + PSTRING_OFFSET, str, size);
mem[PSTRING_OFFSET + size] = NUL;
// pstring struct:
PString * pstr = (PString *) mem;
pstr->size = size;
pstr->hash = hash;
printfl("*** str:'%s' (%u) --> pstr:'%s' (%u) 0x%X",
str, size, pstr->bytes, pstr->size, pstr); ///////////////////////
return pstr;
}
[Any comment on this construction welcome: I'm not sure at all to do things right, here. It's the first time I use flexible array members, and I could not find exemples of using them in allocated structs.]
Second, those pstrings are stored in a string pool, meaning a set implemented as hash table. As usual, "buckets" for collisions (after hash & modulo) are plain linked lists of cells, each holding a pstring pointer and a pointer to next cell. The only special detail is that the cells themselves are stored in an array, instead of beeing allocated anywhere on the heap [1]. Hope the picture is clear. Here is the definition of Cell:
typedef struct SCell {
PString * pstr;
struct SCell * next;
} Cell;
All seemed to work fine, including a battery of tests of the pool itself. Now, when testing a pstring routine (search), I noticed a string changed. After some research, I finally guessed the problem is related to pool growing, and endly could reduce the issue exactly around the growing of the array of cells (so, well before redistributing cells into lists). Here is the lines of debug prints around this growing, with copy of the show_pool routine producing the output (just shows the strings), and the output itself:
static void pool_grow (StringPool * pool, uint n_new) {
...
// Grow arrays:
show_pool(pool); /////////////////////
pool->cells = realloc(pool->cells, pool->n_cells * sizeof(Cell));
check_mem(pool->cells);
show_pool(pool); ////////////////////
...
static void show_pool (StringPool * pool) {
if (pool->n == 0) {
printfl("{}");
return;
}
printf("pool : {\"%s\"", pool->cells[0].pstr->bytes);
PString * pstr;
uint i;
for (i = 1; i < pool->n; i++) {
pstr = pool->cells[i].pstr;
printf(", \"%s\"", pstr->bytes);
}
printl("}");
}
// output:
pool : {"", "abc", "b", "abcXXXabcXXX"}
pool : {"", "abc", "b", "abcXXXabcXXXI"}
As you can see, the last string stored has an additional byte 'I'. Since in the meanwhile I'm just calling realloc, I find myself a bit blocked for further debugging; and thinking hard does not help in throwing light on this mystery. (Note that cells just hold pstring pointers, so how can growing the array of cells alter the string bytes?) Also, I'm bluffed by the fact there seems to be a quite convenient NUL just after the mysterious 'I', since printf halts there.
Thank you.
Can you help?
[1] There is no special reason for doing that here, with a string pool. I usually do that to get for free an ordered set or map, and in addition locality of reference. (The only overhead is that the array of cells must grow in addition to the array of buckets, but one can reduce the number of growings by predimensioning.)
Since size doesn't include the null terminator,
mem[PSTRING_OFFSET + size] = NUL;
is invalid. Every other issue stems from this.