I've written a program in C to create a basic stack using an array. It works as expected, but there is something I'm very confused about. On the first line of the push method, I increment the value of *top_ptr, which is a pointer to the variable top, using the syntax
*top_ptr = *top_ptr+1. When I try to replace this line with *top_ptr++, which I think is more concise and meant the same thing, I get a warning that says Wunused variable, and a segmentation fault error when running it. The warning message from my terminal, word for word, is
warning: expression result unused [-Wunused-value]
*top_ptr++;
^~~~~~~~~~
and my exact error message from the terminal is:
zsh: segmentation fault ./stacks/arrayi
When I run the program with the current program, my output is what I expect: 1 2 3 %
My code is below. Again, the line I'm confused about is the first line of the push method, which is line 17. If you answer this, then thank you for your time and consideration.
#include <stdio.h>
#define MAX_SIZE 101
void push(int *, int *, int);
void print(int *, int *);
int main() {
int top = -1;
int *top_ptr = ⊤
int arr[MAX_SIZE];
push(arr, top_ptr, 1);
push(arr, top_ptr, 2);
push(arr, top_ptr, 3);
print(arr, top_ptr);
}
void push(int *array, int *top_ptr, int x) {
*top_ptr = *top_ptr + 1;
array[*top_ptr] = x;
}
void print(int *array, int *top_ptr) {
for (int i = 0; i <= *top_ptr; i++) {
printf("%d ", array[i]);
}
}
*top_ptr++ is *(top_ptr++), which is wrong because it changes top_ptr, which is not what you want to do.
You want (*top_ptr)++.
The compiler warns you the expression result is unused because, after (top_ptr++), the * fetches the value that (top_ptr++) points to, but nothing is done with that value. That is suspicious, so the compiler warns you you have told it to get a value but not to do anything with it.
In contrast, with (*top_ptr)++, it does not warn you because the ++ modifies the thing that (*top_ptr) points to, so the expression finishes with a useful action.
you should be doing
(*top_ptr)++;
that bracket is important. if u don't give the bracket then basically it'll be executed like
*(top_ptr++);
i.e. at first the pointer top_ptr will be incremented and then it'd be deferenced. that's why it's giving you segmentation fault.
(and the value pointed by top_ptr won't be incremented)
Related
Below is the program:
#include <stdio.h>
#include<stdlib.h>
int *glob_var;
int* copy(void *a,int size)
{
int *t=(int *)calloc(1,sizeof(int));
int i;
int *glob_var=(int *)calloc(size,sizeof(int));
printf("glob_var=%p\n",glob_var);
printf("a=%p\n",a);
t=glob_var;
for(i=0;i<size;i++)
{
*glob_var=*(int *)a;
glob_var++;
(int *)a++;
// printf("a=%p\n",a);
}
glob_var=t;
for(i=0;i<10;i++)
{
printf("%d\t",*glob_var);
glob_var++;
}
glob_var=t;
printf("\n%p\n",glob_var);
return t;
}
int main() {
// Write C code here
int a=0x123456,i;
int *var=(int *)calloc(10,sizeof(int));
int *temp;
temp=var;
for(i=0;i<10;i++)
{
*var=i;
var++;
}
var=temp;
for(i=0;i<10;i++)
{
printf("%d\n",*var);
var++;
}
var=temp;
printf("var=%p\n",var);
glob_var=copy(var,10);
printf("%p\n",glob_var);
for(i=0;i<10;i++)
{
printf("%d\t",*glob_var);
glob_var++;
}
return 0;
}
However, the output I got is :
0 16777216 65536 256 1 33554432 131072 512 2 50331648
I was expecting: 0 1 2 3 4 5 6 7 8 9.
But, in the copy() function, if I replace (int *)a++; with a=(int *)a+1; it is working.
My question is: What is wrong with the current program?
Arithmetic on a pointer-to-void (void*) is not allowed in C1 and your compiler should warn you about that (at the very least) in the following line:
(int *)a++;
When I compile your code (using the clang-cl compiler in Visual Studio), I do, indeed, get two warnings for that line:
warning : arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
warning : expression result unused [-Wunused-value]
The first of these addresses the issue mentioned in my opening line (and discussed in the footnote) but it is the second that should be ringing alarm bells. That shows that the cast isn't working as intended – it is actually applied to the result of the a++ operation, because the cast has lower precedence than the post-increment.
However, when you use a = (int *)a + 1;, then all is working as intended, because the a pointer is cast to an int* before the arithmetic is performed (and then implicitly cast back to a void* for the assignment).
(There are other issues in your code, like the re-declaration of glob_var in your function, and the use of non-void pointers as arguments for the %p format specifier in several printf calls – but these are not really related to your reported problem. Also, this is worth a read: Do I cast the result of malloc?)
1 Some C compilers, such as GCC, do allow arithmetic on void* pointers, but I do not know what the 'base unit size' is for such operations. One would have to read the GCC manual to determine that, but it may very well by just 1, rather than the sizeof(int) required for your program, as presented, to work. Indeed, if that assumption is correct, and sizeof(int) is 4 on your platform, it would explain the three "garbage values" between successive 'real' data in your output.
The code given below is an exercise that our teacher gave to prepare us for exams.
We are supposed to find the errors that occur in this code and fully explain them .
#define SIZE 10
int start (void a,int k) {
const int size=10;
char array[size];
char string[SIZE];
mycheck(3,4);
array[0]=string[0]='A';
printf("%c %c\n", array[0], string[0]);
myRec(7);
}
int mycheck(int a , int b) {
if (a==0 || b==0 ) {
return 0;
}
else {
return (a*b);
}
}
int myRec(int x) {
if(x==0)
return 0;
else
printf("%d,",x);
myRec(x--);
}
I have found these errors so far:
1.int start (void a,int k)
explanation: We can't have a variable of type void, because void is an incomplete type
2.const int size=10;
explanation:we can't use variable to define size of array
(problem is when I run it in dev-c++ it doesn't show an error so I'm not sure about this)
3.mycheck(3,4);
explanation: prototype of function mycheck() is not declared, so the function mycheck is not visible to the compiler while going through start() function
4.A friend told me that there is an error in function myRec because of this statement myRec(x--);
(I don't really get why is this an error and how you can I explain it?)
5.Main() function doesn't exist.
I'm not sure about this but if i run the code (in dev-c++) without main function I get a compilation error
I'm not sure if the errors that I pointed out are 100% right or if I missed an error or if I explained them correctly.
Please correct me if any of the above is wrong!
a friend told me that there is an error in function myRec cuz of this
statement myRec(x--);
It will lead to stackoverflow. Due to post-decrement, the actual argument passed to function myRec(), never decreases and therefore the condition:
if(x==0)
return 0;
will never become true. Regarding your rest of the errors, it depends on the compiler version being used:
For example C99, you are allowed to have variable size arrays like this:
const int size=10;
char array[size];
char string[SIZE];
but pre C99, you would have to use malloc or calloc. For your functions used without prototype, most compilers would generate a warning and not error and also due to no #include<stdio.h> statement, your printf would also lead to a warning.i Again, lot of these things are compiler dependent.
1.int start (void a,int k)
explanation: We can't have a variable of type void ,because void is an
incomplete type
Correct.
2.const int size=10;
explanation:we can't use variable to define size of array (problem is
when i run it in dev-c++ it doesnt show an error?so im not sure about
this!)
This is also correct, that char array[size];, where size is not a compile-time constant, is invalid in C89. However, in C99 and newer, this is actually valid and would create a variable-length array. It is possible that your Dev-C++ IDE is using GCC with the language set to C99 or newer, or has GNU C extensions enabled to enable this feature.
3.mycheck(3,4);
explanation: prototype of function mycheck() is not declared.So the
function mycheck is not visible to the compiler while going through
start() function
Correct. This can be fixed either by declaring the function's prototype before the start() function, or just moving the whole function to the top of the file. As noted by Toby Speight in the comments, in C89, this should not actually be a compiler error, since functions are implicitly declared when they are used before any actual declaration as int (), i.e. a function returning int with any arguments, which is compatible with the declarations of mycheck and myRec. It is however bad practice to rely on this, and implicit function declaration does not work in C99 or newer.
4.a friend told me that there is an error in function myRec cuz of this statement myRec(x--);
(I don't really get why is this an error and how you can explain it?)
This function is a recursive function. This means it calls itself within itself in order to achieve a kind of looping. However, this function as it is currently written would run forever and cause an infinite loop, and since it is a recursive function, and needs a new stack frame each time it is called, it will most likely end in a stack overflow.
The function is written with this statement:
if(x==0)
return 0;
This is intended to terminate the recursion as soon as x reaches 0. However, this never happens, because of this line of code here:
myRec(x--);
In C, postfix -- and ++ operators evaluate to their original value before the addition or subtraction:
int x = 5;
int y = x--;
/* x is now 4; y is now 5 */
However, using the prefix version of these operators will evaluate to their new value after adding / subtracting 1:
int x = 5;
int y = --x;
/* x is now 4; y is now 4 */
This means that on each recursion, the value of x never actually changes and so never reaches 0.
So this line of code should actually read:
myRec(--x);
Or even just this:
myRec(x - 1);
5.Main() function doesn't exist ...again im not sure about this but if i run the code (in dev-c++) without main function i get a compilation
error
This one could either be right or wrong. If the program is meant to run on its own, then yes, there should be a main function. It's possible that the function start here should actually be int main(void) or int main(int argc, char *argv[]). It is entirely valid however to compile a C file without a main, for example when making a library or one individual compilation unit in a bigger program where main is defined in another file.
Another problem with the program is that myRec is used before it is declared, just like your point 3 where mycheck is used before it is declared.
One more problem is that the functions start and mycheck are declared to return int, yet they both do not contain a return statement which returns an int value.
Other than that, assuming that this is the entire verbatim source of the program, the header stdio.h isn't included, yet the function printf is being used. Finally, there's the issue of inconsistent indentation. This may or may not be something you are being tested for, but it is good practice to indent function bodies, and indentation should be the same number of spaces / tab characters wherever it's used, e.g.:
int myRec(int x) {
if(x==0)
return 0;
else
printf("%d,",x);
myRec(x--);
}
1) Hello friend your Recursive function myRec() will go infinite because it
call itself with post detriment value as per C99 standard it will
first call it self then decrements but when it call itself again it have
to do the same task to calling self so it will never decrements and new
stack is created and none of any stack will clear that recursion so
stack will full and you will get segmentation fault because it will go
beyond stack size.
2) printf("%d,",x); it should be printf("%d",x); and you should include #include library.
I think your another mistake is you are calling your mycheck() and you
returning multiplication of two integer but you are not catch with any
value so that process got west.So while you are returning something you
must have to catch it otherwise no need to return it.
3) In this you Program main() function missing. Program execution starts
with main() so without it your code is nothing. if you want to execute
your code by your own function then you have to do some process but
here main() should be present.or instead of start() main() should
be present.
4) you can also allocate any char buffer like this int j; char array[j=20];
your code should be like this.
#include<stdio.h>
#define SIZE 10
int mycheck(int a , int b) {
if (a==0 || b==0 ) {
return 0;
}
else {
return (a*b);
}
}
int myRec(int x) {
if(x==0)
return 0;
else
printf("%d",x);
myRec(--x);
}
void main (int argc, char** argv) {
const int size=10;
char array[size];
char string[SIZE];
int catch = mycheck(3,4);
printf("return value:: %d\n",catch);
array[0]=string[0]='A';
printf("%c %c\n", array[0], string[0]);
myRec(7);
printf("\n");
}
Enjoy.............
I currently am beginning at C programming, my long term objective being teaching myself reverse engineering, and I am following the excellent book by Denis M. Ritchie. I chose this book despite it being written in the 90s because of the great care the authors paid to explanations and examples throughout it.
Anyway, I was playing with the quicksort algorithm the authors described in section 5.6, and tried to rewrite it by recall, but had trouble because of a segmentation fault that I tried to debug with gdb. The code was :
#include <stdio.h>
#define MAX 10000
void sort(int **, int, int);
int main(){
int tab[MAX]={18,7,43,72,2365,743,234,3215,13,456}, i;
int *ptrtab[MAX];
for (i=0; i<MAX && tab[i]>0; i++){
ptrtab[i]=&tab[i];
}
sort(ptrtab, 0, i-1);
for (;i>0;i--) printf ("%d\n",*ptrtab[i]);
return 0;
}
void sort(int **ptrtab,int gauche,int droite){
int i, dernier;
void echanger(int **, int, int);
if (gauche>=droite) return;
dernier=gauche;
for (i=gauche+1; i<=droite; i++){
if (*ptrtab[i]< *ptrtab[gauche])
echanger(ptrtab, ++dernier, i);
}
echanger(ptrtab, gauche, dernier);
sort(ptrtab,dernier+1,droite);
sort(ptrtab,gauche, dernier);
}
void echanger(int **ptrtab,int a,int b){
int *temp=ptrtab[a];
ptrtab[a]=ptrtab[b];
ptrtab[b]=temp;
}
Long story short, after identifying the line in cause (for (;i>0;i--) printf ("%d\n",*ptrtab[i]);)I put a break on it, and the segmentation fault crashed the program on the first iteration of the for loop, and printf wasn't executed. So I just changed this line in my code to put a while loop instead :
#include <stdio.h>
#define MAX 10000
void sort(int **, int, int);
int main(){
int tab[MAX]={18,7,43,72,2365,743,234,3215,13,456}, i;
int *ptrtab[MAX];
for (i=0; i<MAX && tab[i]>0; i++){
ptrtab[i]=&tab[i];
}
sort(ptrtab, 0, i-1);
while (i>0) printf ("%d\n",*ptrtab[--i]);
return 0;
}
void sort(int **ptrtab,int gauche,int droite){
int i, dernier;
void echanger(int **, int, int);
if (gauche>=droite) return;
dernier=gauche;
for (i=gauche+1; i<=droite; i++){
if (*ptrtab[i]< *ptrtab[gauche])
echanger(ptrtab, ++dernier, i);
}
echanger(ptrtab, gauche, dernier);
sort(ptrtab,dernier+1,droite);
sort(ptrtab,gauche, dernier);
}
void echanger(int **ptrtab,int a,int b){
int *temp=ptrtab[a];
ptrtab[a]=ptrtab[b];
ptrtab[b]=temp;
}
And this code works now.
I know there must be quite a few errors throughout my code as I am just a beginner, but I can't grasp the reason why changing from a for to a while loop made a difference...
Note that I am using GCC on ubuntu 16.04.
Thank you all for your attention, and sorry for the rambling.
Kind regards,
S. A.
Your while loop is actually different to the for loop. The while loop decrements i before using it; the for loop does not.
In:
for (;i>0;i--) printf ("%d\n",*ptrtab[i]);
The loop starts with the last value of i from the previous loop, where either it reaches the end of the array (so i will be MAX), or indexes tab at a point where it is zero.
In the first case, ptrtab[MAX] will be indexed, which is invalid, in the second case an uninitialized entry of ptrtab will be used, which, being an automatic variable, will have a random value (points to a random memory location, which will likely be invalid (undefined behaviour).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
pointer arithmetic in C for getting a string
I am a newbie in C and I would like to get the elements of an array with a function, I have tried different options, but I still do not get the elements.
My function is:
void getelements(int *a, int cl)
{
int *p;
for (p=&a[0];p<&a[cl];p++)
{
printf("%d\n",*p);
}
}
I know that the solution should work like that, but it only prints the first element and then memory positions. I am calling my function with:
int v={10,12,20,34,45};
getelements(&v,5);
Any help? I need to use arithmetic of pointers.
Thanks
First, Please don't update code to fix bugs while a question is open. It makes most of the current answers meaningless, doesn't grant credit where it is due to the person(s) that solved one or more issues in your prior code, and makes the casual reader looking for a related problem to their own completely confused by both the question and the answers therein. If you want to amend an update do so in addition to the original problem, but if it an entirely different issue, then mark as answered, give credit where it is due, and open a new question with your new code and different problem(s) (ideally, anyway).
As written now, your function is fine. But your real issue is this:
// compile with -Wall -Werror and look at the warning here
int v={10,12,20,34,45}; // <== WRONG
getelements(&v,5); // <== Harmless, but bad form.
This should be like this instead, assuming you want to print all elements in the array:
int v[] = {10,12,20,34,45};
getelements(v, sizeof(v)/sizeof(v[0]));
Note the [] following your array. Without it, the &v was masking what would have been a big-fat warning or error from the compiler that int is being passed as an int *. Furthermore, if you compile your prior code with full warnings treated as errors (-Wall -Werror for gcc) you will get an error like the following on your v declaration line:
main.c:116:15: Excess elements in scalar initializer
In other words, everything past the first element was ignored, and thus your pointer was running off into undefined behavior land. Changing the declaration and invocation to what I have above will address this as well as ensure you don't make that mistake again, since sizeof(v[0]) won't even compile unless v is an array or pointer type. The latter can still cause headaches when you use a pointer rather than an array with such a calculation, but thats something you just have to discipline yourself against doing in C.
try this and let me know if that works.
void getelements(int *a)
{
int *p;
int l=5;
for (p=a;p<a+l;p++)
{
printf("%d\n",*p);
}
}
It's best to pass in the length of the array along with the array itself.
#include <stdlib.h>
#include <stdio.h>
void get_elements(int* values, int length)
{
int i;
for (i = 0; i < length; ++i)
{
printf("%d\n", values[i]);
}
}
int main(int argc, char** argv)
{
int vals[3];
vals[0] = 0;
vals[1] = 1;
vals[2] = 2;
get_elements(vals, 3);
getchar();
return 0;
}
Using the code similar to your original post (before the addition of the array length as a method parameter), you could do the follow (which is a bit convoluted if you ask me).
void get_elements(int* values, int length)
{
int *p;
for (p = &values[0]; p < &values[length]; p++)
{
printf("%d\n", *p);
}
}
Actually you are passing array address in
getelements(&v,5)
in function
getelements()
you are treating it like an array!!!
void getelements(int *a, int cl)
{
int *p;
for (p=a;p<a+cl;p++)
{
printf("%d\n",*p);
}
}
Let me know if you are cleared conceptually!!!
As per my knowledge and seeing your code.you have hardcoded the length of array to 5. I think you can also pass array length as a parameter to function; or you can use this function and see if it gives the desired result
void getelements(int *a)
{
int *p;
int i = 0;
int l=5;
p = a
for (i = 0;i<l;i++)
{
printf("%d\n",*(p + i));
}
}
So I have some code that looks like this:
int a[10];
a = arrayGen(a,9);
and the arrayGen function looks like this:
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
Right now the compilier tells me "warning: passing argument 1 of ‘arrayGen’ makes integer from pointer without a cast"
My thinking is that I pass 'a', a pointer to a[0], then since the array is already created I can just fill in values for a[n] until I a[n] == '\0'. I think my error is that arrayGen is written to take in an array, not a pointer to one. If that's true I'm not sure how to proceed, do I write values to addresses until the contents of one address is '\0'?
The basic magic here is this identity in C:
*(a+i) == a[i]
Okay, now I'll make this be readable English.
Here's the issue: An array name isn't an lvalue; it can't be assigned to. So the line you have with
a = arrayGen(...)
is the problem. See this example:
int main() {
int a[10];
a = arrayGen(a,9);
return 0;
}
which gives the compilation error:
gcc -o foo foo.c
foo.c: In function 'main':
foo.c:21: error: incompatible types in assignment
Compilation exited abnormally with code 1 at Sun Feb 1 20:05:37
You need to have a pointer, which is an lvalue, to which to assign the results.
This code, for example:
int main() {
int a[10];
int * ip;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
return 0;
}
compiles fine:
gcc -o foo foo.c
Compilation finished at Sun Feb 1 20:09:28
Note that because of the identity at top, you can treat ip as an array if you like, as in this code:
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Full example code
Just for completeness here's my full example:
int gen(int max){
return 42;
}
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Why even return arrAddr? Your passing a[10] by reference so the contents of the array will be modified. Unless you need another reference to the array then charlies suggestion is correct.
Hmm, I know your question's been answered, but something else about the code is bugging me. Why are you using the test against '\0' to determine the end of the array? I'm pretty sure that only works with C strings. The code does indeed compile after the fix suggested, but if you loop through your array, I'm curious to see if you're getting the correct values.
I'm not sure what you are trying to do but the assignment of a pointer value to an array is what's bothering the compiler as mentioned by Charlie. I'm curious about checking against the NUL character constant '\0'. Your sample array is uninitialized memory so the comparison in arrayGen isn't going to do what you want it to do.
The parameter list that you are using ends up being identical to:
int* arrayGen(int *arrAddr, int maxNum)
for most purposes. The actual statement in the standard is:
A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
If you really want to force the caller to use an array, then use the following syntax:
void accepts_pointer_to_array (int (*ary)[10]) {
int i;
for (i=0; i<10; ++i) {
(*ary)[i] = 0; /* note the funky syntax is necessary */
}
}
void some_caller (void) {
int ary1[10];
int ary2[20];
int *ptr = &ary1[0];
accepts_pointer_to_array(&ary1); /* passing address is necessary */
accepts_pointer_to_array(&ary2); /* fails */
accepts_pointer_to_array(ptr); /* also fails */
}
Your compiler should complain if you call it with anything that isn't a pointer to an array of 10 integers. I can honestly say though that I have never seen this one anywhere outside of various books (The C Book, Expert C Programming)... at least not in C programming. In C++, however, I have had reason to use this syntax in exactly one case:
template <typename T, std::size_t N>
std::size_t array_size (T (&ary)[N]) {
return N;
}
Your mileage may vary though. If you really want to dig into stuff like this, I can't recommend Expert C Programming highly enough. You can also find The C Book online at gbdirect.
Try calling your parameter int* arrAddr, not int arrAddr[]. Although when I think about it, the parameters for the main method are similar yet that works. So not sure about the explanation part.
Edit: Hm all the resources I can find on the internet say it should work. I'm not sure, I've always passed arrays as pointers myself so never had this snag before, so I'm very interested in the solution.
The way your using it arrayGen() doesn't need to return a value. You also need to place '\0' in the last element, it isn't done automatically, or pass the index of the last element to fill.
#jeffD
Passing the index would be the preferred way, as there's no guarantee you won't hit other '\0's before your final one (I certainly was when I tested it).