How do you iterate through a pointer? - c

For example:
int *start;
start = (int*)malloc(40);
If I wanted to iterate through all 40 bytes, how would I do so?
I tried doing something like:
while(start != NULL){
start++;
}
but that iterates through a massive number of values, which is much greater than 40. Thus, how do you ensure that you iterate through all 40 bytes.
Thanks for all the help.

There are two issues here.
A single ptr++ skips as many bytes as the type of element it points to.
Here the type is int, so it would skip 4 bytes each time (assuming a 32 bit machine since integer is 4 bytes (32 bits) there).
If you want to iterate through all 40 bytes (one byte at a time), iterate using say a char data type (or type cast your int* to char* and then increment)
The other problem is your loop termination.
There is no one putting a NULL at the end here, so your loop would keep running (and pointer advancing forward) until it runs into may be a null or goes out of your allotted memory area and crashes. The behavior is undefined.
If you allocated 40 bytes, you have to terminate at 40 bytes yourself.
It is worth mentioning that type casting the result of malloc is not a good idea in C. The primary reason is that it could potentially tamper a failed allocation. It is a requirement in C++ though. The details can be found in the exact same question on SO. Search "casting return value of malloc"

First of all, you should be allocating ints correctly:
int* start = malloc( sizeof( int )*40 ) ;
Then you can use array subscripting:
for( size_t i = 0 ; i < 40 ; i++ )
{
start[i] = 0 ;
}
or a pointer to the end of the allocated memory:
int* end = start+40 ;
int* iter = start ;
while( iter < end )
{
*iter= 0 ;
iter++ ;
}

Arrays represent contiguous blocks of memory. Since the name of the array is basically a pointer to the first element, you can use array notation to access the rest of the block. Remember though, there is no error checking by C on the bounds of the array, so if you walk off the end of the memory block, you can do all kinds of things that you didn't intend and more than likely will end up with some sort of memory fault or segmentation error. Since your int can be variable size, I would use this code instead:
int *start;
int i;
start = malloc(40 * sizeof(int));
for (i = 0; i < 40; i++)
{
start[i] = 0;
}
Something like that will work nicely. The way that you are doing it, at least from the code that you posted, there is no way to stop the loop because once it exceeds the memory block, it will keep going until it runs into a NULL or you get a memory fault. In other words, the loop will only exit if it runs into a null. That null may be within the block of memory that you allocated, or it may be way beyond the block.
EDIT: One thing I noticed about my code. It will allocate space for 40 ints which can be either 4 bytes, 8 bytes, or something else depending on the architecture of the machine you are working on. If you REALLY only want 40 bytes of integers, then do something like this:
int *start;
int i;
int size;
size = 40/sizeof(int);
start = malloc(size);
for (i = 0; i < size; i++)
{
start[i] = 0;
}
Or you can use a char data type or an unsigned char if you need to. One other thing that I noticed. The malloc function returns a void pointer type which is compatible with all pointers, so there is no need to do a typecast on a malloc.

Well arrays in C aren't bounded so, a few options, the most common:
int *start;
int cnt = 0;
start = (int*)malloc(sizeof(int)*40);;
while(cnt<40)
{
start++;
cnt++;
}
Another option:
int *start;
int *ref;
start = ref = (int*)malloc(sizeof(int)*40);
while(start != ref+40)
start++;
And this last one is the closest to what you seem to mean to do:
int *start;
start = ref = (int*)malloc(sizeof(int)*41);
start[40] = -1;
while((*start) != -1)
start++;
I would suggest reading more on how pointers in C work. You don't appear to have a very good grasp of it. Also, remember that C takes off the training wheels. Arrays aren't bounded or terminated in a standard way, and a pointer (address in memory) will never be NULL after iterating through an array, and the contents a pointer is pointing to could be anything.

Related

Abort trap: 6 error with arrays in c

The following code compiled fine yesterday for a while, started giving the abort trap: 6 error at one point, then worked fine again for a while, and again started giving the same error. All the answers I've looked up deal with strings of some fixed specified length. I'm not very experienced in programming so any help as to why this is happening is appreciated. (The code is for computing the Zeckendorf representation.)
If I simply use printf to print the digits one by one instead of using strings the code works fine.
#include <string.h>
// helper function to compute the largest fibonacci number <= n
// this works fine
void maxfib(int n, int *index, int *fib) {
int fib1 = 0;
int fib2 = 1;
int new = fib1 + fib2;
*index = 2;
while (new <= n) {
fib1 = fib2;
fib2 = new;
new = fib1 + fib2;
(*index)++;
if (new == n) {
*fib = new;
}
}
*fib = fib2;
(*index)--;
}
char *zeckendorf(int n) {
int index;
int newindex;
int fib;
char *ans = ""; // I'm guessing the error is coming from here
while (n > 0) {
maxfib(n, &index, &fib);
n -= fib;
maxfib(n, &newindex, &fib);
strcat(ans, "1");
for (int j = index - 1; j > newindex; j--) {
strcat(ans, "0");
}
}
return ans;
}
Your guess is quite correct:
char *ans = ""; // I'm guessing the error is coming from here
That makes ans point to a read-only array of one character, whose only element is the string terminator. Trying to append to this will write out of bounds and give you undefined behavior.
One solution is to dynamically allocate memory for the string, and if you don't know the size beforehand then you need to reallocate to increase the size. If you do this, don't forget to add space for the string terminator, and to free the memory once you're done with it.
Basically, you have two approaches when you want to receive a string from function in C
Caller allocates buffer (either statically or dynamically) and passes it to the callee as a pointer and size. Callee writes data to buffer. If it fits, it returns success as a status. If it does not fit, returns error. You may decide that in such case either buffer is untouched or it contains all data fitting in the size. You can choose whatever suits you better, just document it properly for future users (including you in future).
Callee allocates buffer dynamically, fills the buffer and returns pointer to the buffer. Caller must free the memory to avoid memory leak.
In your case the zeckendorf() function can determine how much memory is needed for the string. The index of first Fibonacci number less than parameter determines the length of result. Add 1 for terminating zero and you know how much memory you need to allocate.
So, if you choose first approach, you need to pass additional two parameters to zeckendorf() function: char *buffer and int size and write to the buffer instead of ans. And you need to have some marker to know if it's first iteration of the while() loop. If it is, after maxfib(n, &index, &fib); check the condition index+1<=size. If condition is true, you can proceed with your function. If not, you can return error immediately.
For second approach initialize the ans as:
char *ans = NULL;
after maxfib(n, &index, &fib); add:
if(ans==NULL) {
ans=malloc(index+1);
}
and continue as you did. Return ans from function. Remember to call free() in caller, when result is no longer needed to avoid memory leak.
In both cases remember to write the terminating \0 to buffer.
There is also a third approach. You can declare ans as:
static char ans[20];
inside zeckendorf(). Function shall behave as in first approach, but the buffer and its size is already hardcoded. I recommend to #define BUFSIZE 20 and either declare variable as static char ans[BUFSIZE]; and use BUFSIZE when checking available size. Please be aware that it works only in single threaded environment. And every call to zeckendorf() will overwrite the previous result. Consider following code.
char *a,*b;
a=zeckendorf(10);
b=zeckendorf(15);
printf("%s\n",a);
printf("%s\n",b);
The zeckendorf() function always return the same pointer. So a and b would pointer to the same buffer, where the string for 15 would be stored. So, you either need to store the result somewhere, or do processing in proper order:
a=zeckendorf(10);
printf("%s\n",a);
b=zeckendorf(15);
printf("%s\n",b);
As a rule of thumb majority (if not all) Linux standard C library function uses either first or third approach.

Copying unsigned char in C

I want to use memcpy but it seems to me that it's copying the array from the start?
I wish to copy from A[a] to A[b]. So, instead I found an alternative way,
void copy_file(char* from, int offset, int bytes, char* to) {
int i;
int j = 0;
for (i = offset; i <= (offset+bytes); i++) to[i] = from[j++];
}
I'm getting seg faults but I don't know where I am getting this seg fault from?
each entry holds 8 bytes so my second attempt was
void copy_file(char* from, int offset, int bytes, char* to) {
int i;
int j = 0;
for (i = 8*offset; i <= 8*(offset+bytes); i++) to[i] = from[j++];
}
but still seg fault. If you need more information please don't hesitate to ask!
I'm getting seg faults but I don't know where I am getting this seg fault from?
Primary Suggestion: Learn to use a debugger. It provides helpful information about erroneous instruction(s).
To answer you query on the code snippet shown on above question,
Check the incoming pointers (to and from) against NULL before dereferencing them.
Put a check on the boundary limits for indexes used. Currently they can overrun the allocated memory.
To use memcpy() properly:
as per the man page, the signature of memcpy() indicates
void *memcpy(void *dest, const void *src, size_t n);
it copies n bytes from address pointer by src to address pointed by dest.
Also, a very very important point to note:
The memory areas must not overlap.
So, to copy A[a] to A[b], you may write something like
memcpy(destbuf, &A[a], (b-a) );
it seems to me that memcpy copying the array from the start
No, it does not. In fact, memcpy does not have a slightest idea that it is copying from or to an array. It treats its arguments as pointers to unstructured memory blocks.
If you wish to copy from A[a] to A[b], pass an address of A[a] and the number of bytes between A[b] and A[a] to memcpy, like this:
memcpy(Dest, &A[a], (b-a) * sizeof(A[0]));
This would copy the content of A from index a, inclusive, to index b, exclusive, into a memory block pointed to by Dest. If you wish to apply an offset to Dest as well, use &Dest[d] for the first parameter. Multiplication by sizeof is necessary for arrays of types other than char, signed or unsigned.
Change the last line from
for (i = offset; i <= (offset+bytes); i++)
to[i] = from[j++];
to
for (i = offset; i <= bytes; i++,j++)
to[j] = from[i];
This works fine for me. I have considered offset as the start of the array and byte as the end of the array. ie to copy from[offset] to from[bytes] to to[].

Why do the values in the array change after exiting the loop?

After exiting the while loop for some reason the values in the array change but I'm not why. Inside the loop the values are correct and they store inside the array (a) normally. This is in c!
int * readFile()
{
char file_name[50];
printf("Enter the name of the file to open:\n");
scanf("%s",file_name);
FILE *fp;
fp = fopen(file_name,"r");
if(fp == NULL )
{
printf("Sorry but the File you entered cannot be opened\n");
int *b;
b[0] = -1;
return b;
}
int *a;
int j=0;
long int value=0;
while (fscanf(fp,"%d",&value)!=EOF) {
if((a =malloc(sizeof(long int))) == NULL)
printf("not enough memory\n");
a[j]=value;
j++;
}
printf("%d %d %d\n",a[0],a[1],a[2]);
int i=0;
for(i=0; i<j;i++)
{
printf("array[%d] = %d\n",i,a[i]);
}
fclose(fp);
return a;
}
Any help would be greatly appreciated!
When you do if((a =malloc(sizeof(long int))) == NULL) you are only allocating enough memory for a single long int ( 32 bits in size), but you need to allocate memory for each int that you plan to store. Because malloc allocates a single block of memory, you need to know how many ints you plan to store before hand. If you don't mind the overhead, you can do a preliminary run through the file being read and count the number of ints you will read (basically your j variable) , then you can do
a =malloc( intCounter * sizeof(long int))) == NULL , where intCounter would be the total number of integers in the file (j).
Another option would be to use a linked list,(which is close to what your trying to do) where you can allocate memory for each int on the fly, but you will need to store pointer information to the next node in the array.
The malloc call in the while loop overwrites the data that was stored in the single allocation of an Int. For example if you read 1 2 3 from the text file it would store 1 in the a, malloc different memory adress to a, store 2, malloc yet another memory address and store 3. Resulting in 0 , 0 , 3 to be printed.
You have used a mix of int and long int throughout your code. You need to settle on a consistent type; for my answer I've gone with int. (You could easily go through and change all occurrences of int to long though, so long as you also change the fscanf format string to %ld).
Currently you allocate a new block of one long int each time around the loop. As well as leaking memory from previous loop iterations, you access out of bounds of this. Also, when malloc fails you print a message and keep going!
Instead you need to allocate a single block which will hold several integers. One way to do this is by using the realloc function to make the existing allocation bigger.
Also, when checking the return value of fscanf, you should check for == 1 here. It will return 0 if they typed in some letters but did not trigger EOF condition, and so your program will go on forever.
Here is how that loop could look like:
int *a = NULL;
size_t j = 0;
while ( fscanf(fp,"%d",&value) == 1 )
{
int *ptr = realloc( a, (j+1) * sizeof *a );
if ( !ptr )
{
printf("not enough memory\n");
break;
}
a = ptr;
a[j]=value;
j++;
}
By using a separate variable ptr for the new allocation, we can recover from out-of-memory condition (the program can continue working with the number of ints that were input so far).
If you intend to handle out-of-memory by immediately exiting the program (e.g. by calling exit(EXIT_FAILURE); instead of break; then you could shorten your code a bit by using a = realloc( a, etc. instead of ptr.
The earlier code int *b; b[0] = -1; has a problem: b doesn't point anywhere but you write through it.
This function has a design problem in that the caller has no way of knowing what j was. One solution to this would be to always put -1 on the end of the input (this idea is called "sentinel value" - and remember to allocate space for it); another option would be to have an "out" parameter to the function.

Segmentation fault in C while declaring large pointer array

I run in a problem with a program and I'm not sure how to solve it. I'm processing a file and to do so I get the size with ftell and store it in M_size. After that I declare a unsigned char pointer array with N. The array is then used in two functions a() and b().
...
unsigned long N = (M_size/ x);
int LstElemSize = M_size % x;
if(LstElemSize != 0){
N += 1;
}
unsigned char *ptr_M[N]
a(ptr_M)
b(ptr_M)
...
Function a() actually initializes each element of ptr_M in a for loop:
a(){
int i;
for(i = 0; i < N-1; i ++){
ptr_M[i] = malloc(sizeof(unsigned char) * x);
}
}
Function b() iterates then over each element and calculates stuff and at the end each element is freed.
My problem is now that when I try to process a file e.g. 1 GB the array size will be around 4 000 000 and a Segmentation error occurs (In the line i declare my array). If I calculated it correctly that is 8 byte (char pointer) times 4 000 000 = 32MB. The server running the program has enough memory to hold the file, but i guess as mentioned in Response 1 the stack space is not enough.
What can I do to solve my problem? Increase my stack space? Thanks!
The problem is that you're defining ptr_M in the stack, which has a small size limit. The heap does not have such a small size limit and is able to use more of your system's memory. You need to use malloc() to allocate ptr_M just like you allocate the subarrays. (Make sure to free it at some point too along with all those subarrays!)
unsigned char **ptr_M = malloc(sizeof(unsigned char*) * N);
Also, your a() has an off-by-one error. It ignores the last item of the array. Use this:
for(i = 0; i < N; i ++){
unsigned char *ptr_M[N] is a variable-length array declaring N number of unsigned char on the stack in your case. You should dynamically allocate the space for the array as well.
unsigned char **ptr_M = malloc(sizeof(unsigned char*) * N);
a(ptr_M);
b(ptr_M);
...
//After you free each element in ptr_M
free(ptr_M);
malloc allocates space from heap, not from stack. You may try increasing your heapsize looking at the compiler option. Check the upper limit of heapsize that is supported there.

C using malloc and duplicating array

I am supposed to follow the following criteria:
Implement function answer4 (pointer parameter and n):
Prepare an array of student_record using malloc() of n items.
Duplicate the student record from the parameter to the array n
times.
Return the array.
And I came with the code below, but it's obviously not correct. What's the correct way to implement this?
student_record *answer4(student_record* p, unsigned int n)
{
int i;
student_record* q = malloc(sizeof(student_record)*n);
for(i = 0; i < n ; i++){
q[i] = p[i];
}
free(q);
return q;
};
p = malloc(sizeof(student_record)*n);
This is problematic: you're overwriting the p input argument, so you can't reference the data you were handed after that line.
Which means that your inner loop reads initialized data.
This:
return a;
is problematic too - it would return a pointer to a local variable, and that's not good - that pointer becomes invalid as soon as the function returns.
What you need is something like:
student_record* ret = malloc(...);
for (int i=...) {
// copy p[i] to ret[i]
}
return ret;
1) You reassigned p, the array you were suppose to copy, by calling malloc().
2) You can't return the address of a local stack variable (a). Change a to a pointer, malloc it to the size of p, and copy p into. Malloc'd memory is heap memory, and so you can return such an address.
a[] is a local automatic array. Once you return from the function, it is erased from memory, so the calling function can't use the array you returned.
What you probably wanted to do is to malloc a new array (ie, not p), into which you should assign the duplicates and return its values w/o freeing the malloced memory.
Try to use better names, it might help in avoiding the obvious mix-up errors you have in your code.
For instance, start the function with:
student_record * answer4(const student_record *template, size_t n)
{
...
}
It also makes the code clearer. Note that I added const to make it clearer that the first argument is input-only, and made the type of the second one size_t which is good when dealing with "counts" and sizes of things.
The code in this question is evolving quite quickly but at the time of this answer it contains these two lines:
free(q);
return q;
This is guaranteed to be wrong - after the call to free its argument points to invalid memory and anything could happen subsequently upon using the value of q. i.e. you're returning an invalid pointer. Since you're returning q, don't free it yet! It becomes a "caller-owned" variable and it becomes the caller's responsibility to free it.
student_record* answer4(student_record* p, unsigned int n)
{
uint8_t *data, *pos;
size_t size = sizeof(student_record);
data = malloc(size*n);
pos = data;
for(unsigned int i = 0; i < n ; i++, pos=&pos[size])
memcpy(pos,p,size);
return (student_record *)data;
};
You may do like this.
This compiles and, I think, does what you want:
student_record *answer4(const student_record *const p, const unsigned int n)
{
unsigned int i;
student_record *const a = malloc(sizeof(student_record)*n);
for(i = 0; i < n; ++i)
{
a[i] = p[i];
}
return a;
};
Several points:
The existing array is identified as p. You want to copy from it. You probably do not want to free it (to free it is probably the caller's job).
The new array is a. You want to copy to it. The function cannot free it, because the caller will need it. Therefore, the caller must take the responsibility to free it, once the caller has done with it.
The array has n elements, indexed 0 through n-1. The usual way to express the upper bound on the index thus is i < n.
The consts I have added are not required, but well-written code will probably include them.
Altought, there are previous GOOD answers to this question, I couldn't avoid added my own. Since I got pascal programming in Collegue, I am used to do this, in C related programming languages:
void* AnyFunction(int AnyParameter)
{
void* Result = NULL;
DoSomethingWith(Result);
return Result;
}
This, helps me to easy debug, and avoid bugs like the one mention by #ysap, related to pointers.
Something important to remember, is that the question mention to return a SINGLE pointer, this a common caveat, because a pointer, can be used to address a single item, or a consecutive array !!!
This question suggests to use an array as A CONCEPT, with pointers, NOT USING ARRAY SYNTAX.
// returns a single pointer to an array:
student_record* answer4(student_record* student, unsigned int n)
{
// empty result variable for this function:
student_record* Result = NULL;
// the result will allocate a conceptual array, even if it is a single pointer:
student_record* Result = malloc(sizeof(student_record)*n);
// a copy of the destination result, will move for each item
student_record* dest = Result;
int i;
for(i = 0; i < n ; i++){
// copy contents, not address:
*dest = *student;
// move to next item of "Result"
dest++;
}
// the data referenced by "Result", was changed using "dest"
return Result;
} // student_record* answer4(...)
Check that, there is not subscript operator here, because of addressing with pointers.
Please, don't start a pascal v.s. c flame war, this is just a suggestion.

Resources