Edit: this is actually a known bug.
original question
I would love some help on this, because I just don't get it. Hopefully it's just something I don't understand.
I have a few functions to initialize and free memory of two types : a singular foo type and a plural foos_list type. Here is a full program reduced to the essential:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void *
xalloc (size_t len)
{
void *mem = malloc (len);
if (!mem)
{
fprintf (stderr, "can't allocated memory");
exit (1);
}
return mem;
}
void *
xrealloc (void *mem, size_t msize)
{
mem = realloc (mem, msize);
if (!mem)
{
fprintf (stderr, "can't allocate %zu bytes of memory\n", msize);
exit (1);
}
return mem;
}
typedef struct {
char *name;
} foo;
typedef struct {
foo **foos;
size_t foos_len;
} foos_list;
foo *
new_foo ()
{
foo *f = xalloc (sizeof (foo));
f->name = NULL;
return f;
}
void
free_foo (foo *f)
{
if (!f) return;
if (f->name) free (f->name);
free (f);
}
foos_list *
new_foos_list ()
{
foos_list *l = xalloc (sizeof (foos_list));
l->foos = NULL;
l->foos_len = 0;
return l;
}
void
free_foos_list (foos_list *l)
{
if (!l) return;
if (l->foos)
{
for (size_t i = 0; i < l->foos_len; i++)
free_foo (l->foos[i]);
free (l->foos);
}
free (l);
}
int main()
{
}
If I try to compile this, gcc throws an error of analyzer-use-after-free and one of analyzer-double-free.
$ gcc -Wall -Werror -fanalyzer -o test main.c
main.c: In function ‘free_foo’:
main.c:56:8: error: use after ‘free’ of ‘f’ [CWE-416] [-Werror=analyzer-use-after-free]
56 | if (f->name) free (f->name);
| ~^~~~~~
‘free_foos_list’: events 1-8
|
| 72 | free_foos_list (foos_list *l)
| | ^~~~~~~~~~~~~~
| | |
| | (1) entry to ‘free_foos_list’
| 73 | {
| 74 | if (!l) return;
| | ~
| | |
| | (2) following ‘false’ branch (when ‘l’ is non-NULL)...
| 75 |
| 76 | if (l->foos)
| | ~~~~~~~~
| | | |
| | | (3) ...to here
| | (4) following ‘true’ branch...
| 77 | {
| 78 | for (size_t i = 0; i < l->foos_len; i++)
| | ~~~ ~
| | | |
| | | (5) ...to here
| | (6) following ‘true’ branch...
| 79 | free_foo (l->foos[i]);
| | ~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (7) ...to here
| | (8) calling ‘free_foo’ from ‘free_foos_list’
|
+--> ‘free_foo’: events 9-10
|
| 53 | free_foo (foo *f)
| | ^~~~~~~~
| | |
| | (9) entry to ‘free_foo’
|......
| 58 | free (f);
| | ~~~~~~~~
| | |
| | (10) freed here
|
<------+
|
‘free_foos_list’: events 11-14
|
| 78 | for (size_t i = 0; i < l->foos_len; i++)
| | ~~~
| | |
| | (12) following ‘true’ branch...
| 79 | free_foo (l->foos[i]);
| | ^~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (13) ...to here
| | (11) returning to ‘free_foos_list’ from ‘free_foo’
| | (14) calling ‘free_foo’ from ‘free_foos_list’
|
+--> ‘free_foo’: events 15-20
|
| 53 | free_foo (foo *f)
| | ^~~~~~~~
| | |
| | (15) entry to ‘free_foo’
| 54 | {
| 55 | if (!f) return;
| | ~
| | |
| | (16) following ‘false’ branch (when ‘f’ is non-NULL)...
| 56 | if (f->name) free (f->name);
| | ~~~~~~~~ ~~~~~~~
| | | | |
| | | | (19) ...to here
| | | (17) ...to here
| | (18) following ‘true’ branch...
| 57 |
| 58 | free (f);
| | ~~~~~~~~
| | |
| | (20) freed here
|
<------+
|
‘free_foos_list’: events 21-25
|
| 78 | for (size_t i = 0; i < l->foos_len; i++)
| | ~~~
| | |
| | (22) following ‘true’ branch...
| 79 | free_foo (l->foos[i]);
| | ^~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (23) ...to here
| | | (24) freed here
| | (21) returning to ‘free_foos_list’ from ‘free_foo’
| | (25) calling ‘free_foo’ from ‘free_foos_list’
|
+--> ‘free_foo’: events 26-29
|
| 53 | free_foo (foo *f)
| | ^~~~~~~~
| | |
| | (26) entry to ‘free_foo’
| 54 | {
| 55 | if (!f) return;
| | ~
| | |
| | (27) following ‘false’ branch (when ‘f’ is non-NULL)...
| 56 | if (f->name) free (f->name);
| | ~~~~~~~
| | |
| | (28) ...to here
| | (29) use after ‘free’ of ‘f’; freed at (24)
|
main.c:56:16: error: double-‘free’ of ‘<unknown>’ [CWE-415] [-Werror=analyzer-double-free]
56 | if (f->name) free (f->name);
| ^~~~~~~~~~~~~~
‘free_foos_list’: events 1-10
|
| 72 | free_foos_list (foos_list *l)
| | ^~~~~~~~~~~~~~
| | |
| | (1) entry to ‘free_foos_list’
| 73 | {
| 74 | if (!l) return;
| | ~
| | |
| | (2) following ‘false’ branch (when ‘l’ is non-NULL)...
| 75 |
| 76 | if (l->foos)
| | ~~~~~~~~
| | | |
| | | (3) ...to here
| | (4) following ‘true’ branch...
| 77 | {
| 78 | for (size_t i = 0; i < l->foos_len; i++)
| | ~~~ ~
| | | |
| | | (5) ...to here
| | (6) following ‘true’ branch...
| | (8) following ‘true’ branch...
| 79 | free_foo (l->foos[i]);
| | ~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (7) ...to here
| | | (9) ...to here
| | (10) calling ‘free_foo’ from ‘free_foos_list’
|
+--> ‘free_foo’: events 11-15
|
| 53 | free_foo (foo *f)
| | ^~~~~~~~
| | |
| | (11) entry to ‘free_foo’
| 54 | {
| 55 | if (!f) return;
| | ~
| | |
| | (12) following ‘false’ branch (when ‘f’ is non-NULL)...
| 56 | if (f->name) free (f->name);
| | ~~~~~~~~ ~~~~~~~
| | | | |
| | | | (15) ...to here
| | | (13) ...to here
| | (14) following ‘true’ branch...
|
<------+
|
‘free_foos_list’: events 16-19
|
| 78 | for (size_t i = 0; i < l->foos_len; i++)
| | ~~~
| | |
| | (17) following ‘true’ branch...
| 79 | free_foo (l->foos[i]);
| | ^~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (18) ...to here
| | (16) returning to ‘free_foos_list’ from ‘free_foo’
| | (19) calling ‘free_foo’ from ‘free_foos_list’
|
+--> ‘free_foo’: events 20-25
|
| 53 | free_foo (foo *f)
| | ^~~~~~~~
| | |
| | (20) entry to ‘free_foo’
| 54 | {
| 55 | if (!f) return;
| | ~
| | |
| | (21) following ‘false’ branch (when ‘f’ is non-NULL)...
| 56 | if (f->name) free (f->name);
| | ~~~~~~~~ ~~~~~~~~~~~~~~
| | | | | |
| | | | | (24) ...to here
| | | | (25) second ‘free’ here
| | | (22) ...to here
| | (23) following ‘true’ branch...
|
cc1: all warnings being treated as errors
If I understand correctly, it complains that I use f->name after freeing f, except that when I follow its instructions, the foo freed is l->foos[0] and the one the analyzer think is already freed is l->foos[1] (and it is not freed yet).
What puzzles me even more is that if I actually use those functions, the errors disappear. Here is a main function using them, and if I replace the main function with it in the previous file, it compiles just fine:
int main()
{
foos_list *l = new_foos_list ();
foo *f = new_foo ();
foo *f2 = new_foo ();
l->foos_len++;
l->foos = xrealloc (l->foos, sizeof(foo) * l->foos_len);
l->foos[0] = f;
l->foos_len++;
l->foos = xrealloc (l->foos, sizeof(foo) * l->foos_len);
l->foos[1] = f2;
free_foos_list (l);
}
My problem is that of course, I don't want to allocate and free foos, I hit that problem in a more complexe program where the functions are used in a different file they are declared, and the same fanalyzer errors are triggered.
So my question is : is this a fanalyzer bug (and if so, is there a workaround), or is it an error on my side (and how to fix it)? Thanks.
It seems to be an -fanalyzer issue.
I desk checked your code and found no leak.
My version of gcc doesn't seem to support -fanalyzer, so I couldn't test that.
I downloaded and built your program and ran it under valgrind. I did this for your original main and one I created with a more extensive diagnostic.
They both reported no errors of any kind.
Note that you're allocating too much space (wasteful, but harmless):
l->foos = xrealloc(l->foos,sizeof(foo) * l->foos_len);
Should be:
l->foos = xrealloc(l->foos,sizeof(foo *) * l->foos_len);
Or, better yet:
l->foos = xrealloc(l->foos,sizeof(*l->foos) * l->foos_len);
Here's my version:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void *
xalloc(size_t len)
{
void *mem = malloc(len);
if (!mem) {
fprintf(stderr, "can't allocated memory");
exit(1);
}
return mem;
}
void *
xrealloc(void *mem, size_t msize)
{
mem = realloc(mem, msize);
if (!mem) {
fprintf(stderr, "can't allocate %zu bytes of memory\n", msize);
exit(1);
}
return mem;
}
typedef struct {
char *name;
} foo;
typedef struct {
foo **foos;
size_t foos_len;
} foos_list;
foo *
new_foo()
{
foo *f = xalloc(sizeof(foo));
f->name = NULL;
return f;
}
void
free_foo(foo *f)
{
if (!f)
return;
if (f->name)
free(f->name);
free(f);
}
foos_list *
new_foos_list(void)
{
foos_list *l = xalloc(sizeof(foos_list));
l->foos = NULL;
l->foos_len = 0;
return l;
}
void
free_foos_list(foos_list *l)
{
if (! l)
return;
if (l->foos) {
for (size_t i = 0; i < l->foos_len; i++)
free_foo(l->foos[i]);
free(l->foos);
}
free(l);
}
int
main()
{
char name[100];
foos_list *l = new_foos_list();
for (int idx = 0; idx < 30; ++idx) {
foo *f = new_foo();
sprintf(name,"N%d",idx);
f->name = strdup(name);
size_t count = l->foos_len++;
l->foos = xrealloc(l->foos,sizeof(*l->foos) * (count + 1));
l->foos[count] = f;
}
int totlen = 0;
for (int idx = 0; idx < l->foos_len; ++idx) {
foo *f = l->foos[idx];
totlen += printf(" %s",f->name);
if (totlen > 70) {
printf("\n");
totlen = 0;
}
}
printf("\n");
free_foos_list(l);
return 0;
}
Here's the my version's output:
N0 N1 N2 N3 N4 N5 N6 N7 N8 N9 N10 N11 N12 N13 N14 N15 N16 N17 N18 N19 N20
N21 N22 N23 N24 N25 N26 N27 N28 N29
Related
The user should input the elements of an array(maximum 20 of them). The task is to draw a bar graph using |, *, and - by using these elements. A line of minuses should be drawn instead of zero, and * instead of last member of an array. If the number is 3 for example, two | and one * above them should be drawn. The problem that I have with my code is that it sometimes takes too long to execute, draws one instead of two minuses between the array elements, and sometimes doesn't draw the line with minuses.
#include <stdio.h>
int main() {
int n[20];
int i,j,counter=0,input=0,min,max;
printf("Elements of the array: \n");
while(input!=1000){
scanf("%d", &input);
n[counter]=input;
counter++;
}
counter--;
min=n[0];
max=n[0];
for(i=1;i<counter;i++){
if(n[i]>max) max=n[i];
if(n[i]<min) min=n[i];
}
for(i=0;i<max-min+1;i++){
for(j=0;j<2*counter;j++){
if(j%2==0 && n[j/2]==max-i) printf("*");
else if(i==max) printf("-");
else if(j%2==0 && n[j/2]>0 && i<max && n[j/2]>max-i) printf("|");
else if(j%2==0 && n[j/2]<0 && i>max && n[j/2]<max-i) printf("|");
else printf(" ");
}
printf("\n");
}
}// Input:4 -3 7 0 -1 1000 Expected output:
*
|
|
* |
| |
| |
| |
---------*-----
| *
|
*
My output:
*
|
|
* |
| |
| |
| |
------*---
| *
|
*
Input: 5 4 3 2 1 2 3 4 5 Expected output:
* *
| * * |
| | * * | |
| | | * * | | |
| | | | * | | | |
---------------------------
My output:
* *
| * * |
| | * * | |
| | | * * | | |
| | | | * | | | | //
Bear in mind this is an old version of the C compiler: CP/M for Z80.
#include<stdio.h>
main()
{
char i = 0;
do
{
printf("0x%04x | ", i);
} while (++ i);
}
Expected:
0x0000 | 0x0001 | 0x0002 | 0x0003 | 0x0004 | 0x0005 | 0x0006 | 0x0007 | 0x0008 | 0x0009 | 0x000A | 0x000B | 0x000C | 0x000D | 0x000E | 0x000F | 0x0010 | 0x0011 | 0x0012 | 0x0013 | 0x0014 | 0x0015 | 0x0016 | 0x0017 | 0x0018 | 0x0019 | 0x001A | 0x001B | 0x001C | 0x001D | 0x001E | 0x001F | 0x0020 | 0x0021 | 0x0022 | 0x0023 | 0x0024 | 0x0025 | 0x0026 | 0x0027 | 0x0028 | 0x0029 | 0x002A | 0x002B | 0x002C | 0x002D | 0x002E | 0x002F | 0x0030 | 0x0031 | 0x0032 | 0x0033 | 0x0034 | 0x0035 | 0x0036 | 0x0037 | 0x0038 | 0x0039 | 0x003A | 0x003B | 0x003C | 0x003D | 0x003E | 0x003F | 0x0040 | 0x0041 | 0x0042 | 0x0043 | 0x0044 | 0x0045 | 0x0046 | 0x0047 | 0x0048 | 0x0049 | 0x004A | 0x004B | 0x004C | 0x004D | 0x004E | 0x004F | 0x0050 | 0x0051 | 0x0052 | 0x0053 | 0x0054 | 0x0055 | 0x0056 | 0x0057 | 0x0058 | 0x0059 | 0x005A | 0x005B | 0x005C | 0x005D | 0x005E | 0x005F | 0x0060 | 0x0061 | 0x0062 | 0x0063 | 0x0064 | 0x0065 | 0x0066 | 0x0067 | 0x0068 | 0x0069 | 0x006A | 0x006B | 0x006C | 0x006D | 0x006E | 0x006F | 0x0070 | 0x0071 | 0x0072 | 0x0073 | 0x0074 | 0x0075 | 0x0076 | 0x0077 | 0x0078 | 0x0079 | 0x007A | 0x007B | 0x007C | 0x007D | 0x007E | 0x007F | 0x0080 | 0x0081 | 0x0082 | 0x0083 | 0x0084 | 0x0085 | 0x0086 | 0x0087 | 0x0088 | 0x0089 | 0x008A | 0x008B | 0x008C | 0x008D | 0x008E | 0x008F | 0x0090 | 0x0091 | 0x0092 | 0x0093 | 0x0094 | 0x0095 | 0x0096 | 0x0097 | 0x0098 | 0x0099 | 0x009A | 0x009B | 0x009C | 0x009D | 0x009E | 0x009F | 0x00A0 | 0x00A1 | 0x00A2 | 0x00A3 | 0x00A4 | 0x00A5 | 0x00A6 | 0x00A7 | 0x00A8 | 0x00A9 | 0x00AA | 0x00AB | 0x00AC | 0x00AD | 0x00AE | 0x00AF | 0x00B0 | 0x00B1 | 0x00B2 | 0x00B3 | 0x00B4 | 0x00B5 | 0x00B6 | 0x00B7 | 0x00B8 | 0x00B9 | 0x00BA | 0x00BB | 0x00BC | 0x00BD | 0x00BE | 0x00BF | 0x00C0 | 0x00C1 | 0x00C2 | 0x00C3 | 0x00C4 | 0x00C5 | 0x00C6 | 0x00C7 | 0x00C8 | 0x00C9 | 0x00CA | 0x00CB | 0x00CC | 0x00CD | 0x00CE | 0x00CF | 0x00D0 | 0x00D1 | 0x00D2 | 0x00D3 | 0x00D4 | 0x00D5 | 0x00D6 | 0x00D7 | 0x00D8 | 0x00D9 | 0x00DA | 0x00DB | 0x00DC | 0x00DD | 0x00DE | 0x00DF | 0x00E0 | 0x00E1 | 0x00E2 | 0x00E3 | 0x00E4 | 0x00E5 | 0x00E6 | 0x00E7 | 0x00E8 | 0x00E9 | 0x00EA | 0x00EB | 0x00EC | 0x00ED | 0x00EE | 0x00EF | 0x00F0 | 0x00F1 | 0x00F2 | 0x00F3 | 0x00F4 | 0x00F5 | 0x00F6 | 0x00F7 | 0x00F8 | 0x00F9 | 0x00FA | 0x00FB | 0x00FC | 0x00FD | 0x00FE | 0x00FF |
Actual:
0x0A00 | 0x0A01 | 0x0A02 | 0x0A03 | 0x0A04 | 0x0A05 | 0x0A06 | 0x0A07 | 0x0A08 | 0x0A09 | 0x0A0A | 0x0A0B | 0x0A0C | 0x0A0D | 0x0A0E | 0x0A0F | 0x0A10 | 0x0A11 | 0x0A12 | 0x0A13 | 0x0A14 | 0x0A15 | 0x0A16 | 0x0A17 | 0x0A18 | 0x0A19 | 0x0A1A | 0x0A1B | 0x0A1C | 0x0A1D | 0x0A1E | 0x0A1F | 0x0A20 | 0x0A21 | 0x0A22 | 0x0A23 | 0x0A24 | 0x0A25 | 0x0A26 | 0x0A27 | 0x0A28 | 0x0A29 | 0x0A2A | 0x0A2B | 0x0A2C | 0x0A2D | 0x0A2E | 0x0A2F | 0x0A30 | 0x0A31 | 0x0A32 | 0x0A33 | 0x0A34 | 0x0A35 | 0x0A36 | 0x0A37 | 0x0A38 | 0x0A39 | 0x0A3A | 0x0A3B | 0x0A3C | 0x0A3D | 0x0A3E | 0x0A3F | 0x0A40 | 0x0A41 | 0x0A42 | 0x0A43 | 0x0A44 | 0x0A45 | 0x0A46 | 0x0A47 | 0x0A48 | 0x0A49 | 0x0A4A | 0x0A4B | 0x0A4C | 0x0A4D | 0x0A4E | 0x0A4F | 0x0A50 | 0x0A51 | 0x0A52 | 0x0A53 | 0x0A54 | 0x0A55 | 0x0A56 | 0x0A57 | 0x0A58 | 0x0A59 | 0x0A5A | 0x0A5B | 0x0A5C | 0x0A5D | 0x0A5E | 0x0A5F | 0x0A60 | 0x0A61 | 0x0A62 | 0x0A63 | 0x0A64 | 0x0A65 | 0x0A66 | 0x0A67 | 0x0A68 | 0x0A69 | 0x0A6A | 0x0A6B | 0x0A6C | 0x0A6D | 0x0A6E | 0x0A6F | 0x0A70 | 0x0A71 | 0x0A72 | 0x0A73 | 0x0A74 | 0x0A75 | 0x0A76 | 0x0A77 | 0x0A78 | 0x0A79 | 0x0A7A | 0x0A7B | 0x0A7C | 0x0A7D | 0x0A7E | 0x0A7F | 0x0A80 | 0x0A81 | 0x0A82 | 0x0A83 | 0x0A84 | 0x0A85 | 0x0A86 | 0x0A87 | 0x0A88 | 0x0A89 | 0x0A8A | 0x0A8B | 0x0A8C | 0x0A8D | 0x0A8E | 0x0A8F | 0x0A90 | 0x0A91 | 0x0A92 | 0x0A93 | 0x0A94 | 0x0A95 | 0x0A96 | 0x0A97 | 0x0A98 | 0x0A99 | 0x0A9A | 0x0A9B | 0x0A9C | 0x0A9D | 0x0A9E | 0x0A9F | 0x0AA0 | 0x0AA1 | 0x0AA2 | 0x0AA3 | 0x0AA4 | 0x0AA5 | 0x0AA6 | 0x0AA7 | 0x0AA8 | 0x0AA9 | 0x0AAA | 0x0AAB | 0x0AAC | 0x0AAD | 0x0AAE | 0x0AAF | 0x0AB0 | 0x0AB1 | 0x0AB2 | 0x0AB3 | 0x0AB4 | 0x0AB5 | 0x0AB6 | 0x0AB7 | 0x0AB8 | 0x0AB9 | 0x0ABA | 0x0ABB | 0x0ABC | 0x0ABD | 0x0ABE | 0x0ABF | 0x0AC0 | 0x0AC1 | 0x0AC2 | 0x0AC3 | 0x0AC4 | 0x0AC5 | 0x0AC6 | 0x0AC7 | 0x0AC8 | 0x0AC9 | 0x0ACA | 0x0ACB | 0x0ACC | 0x0ACD | 0x0ACE | 0x0ACF | 0x0AD0 | 0x0AD1 | 0x0AD2 | 0x0AD3 | 0x0AD4 | 0x0AD5 | 0x0AD6 | 0x0AD7 | 0x0AD8 | 0x0AD9 | 0x0ADA | 0x0ADB | 0x0ADC | 0x0ADD | 0x0ADE | 0x0ADF | 0x0AE0 | 0x0AE1 | 0x0AE2 | 0x0AE3 | 0x0AE4 | 0x0AE5 | 0x0AE6 | 0x0AE7 | 0x0AE8 | 0x0AE9 | 0x0AEA | 0x0AEB | 0x0AEC | 0x0AED | 0x0AEE | 0x0AEF | 0x0AF0 | 0x0AF1 | 0x0AF2 | 0x0AF3 | 0x0AF4 | 0x0AF5 | 0x0AF6 | 0x0AF7 | 0x0AF8 | 0x0AF9 | 0x0AFA | 0x0AFB | 0x0AFC | 0x0AFD | 0x0AFE | 0x0AFF |
What am I doing wrong?
Assembly:
cseg
?59999:
defb 48,120,37,48,52,120,32,124,32,0
main#:
ld c,0
#0:
push bc
push bc
ld bc,?59999
push bc
ld hl,2
call printf
pop bc
pop bc
pop bc
inc c
jp nz,#0
ret
public main#
extrn printf
end
Golly. LONG time since I used a z80 C compiler, and most were buggy as [unprintable] back then.
I would suggest that you dump the assembler if the compiler allows. My GUESS is that internally the char is being promoted to a 16 bit INT with indeterminate upper bits set.
The problem is that %04X expects an integer - not a char.
You might try forcing the compiler to play nice by explicitly casting the char to an int - i.e.
printf("0x%04x | ", (int) i);
Most probable thing is that, as being an old 8 bit compiler, it is not converting the char typed i variable into an int and it is just pushing the bc register (assuming your function will not use the high part, which is simply not true, as your function (printf()) expects a whole int as parameter) which you don't know what it has in the b register. The compiler is using the full bc register to print, as you use %x format, which is for an int parameter, and this explains the presence of the high byte as 0x0a in the output (and which doesn't appear anywhere in your assembler listing). Later versions of the standard begun to convert every short and char arguments to int in order probably to avoid this kind of issue.
Try this code, and see if that solves the problem.
#include<stdio.h>
main()
{
char i = 0;
do
{
printf("0x%04x | ", (int) i);
} while (++ i);
}
(I cannot check here, as I have z80 computer, but not a C compiler for it)
Edit
After checking the assembler code, the compiler output just pushes the complete bc register into the stack, in which the lower part (thec register) comes from the character you want to print, but the b register was previously loaded with the high byte of the 59999 pointer to the array of characters of the format string, which happens to be 0xea. So, I got stranged at the output, that should be probably 0xea00, 0xea01, 0xea02, ... and not the output you have. Have you recompiled the source to get the assembler output and the output refers to a different compilation?
To dig a little more I'd need the code of the printf() function, which I assume you don't have. But that seems that converting the parameter to (int) before passing it to the printf() function should solve the problem.
#include <stdio.h>
#include<string.h>
void double_string(char ary[])
{
char *start = ary;
// dont exactly know what is happening here nothing is getting printed when consoled
char *end = ary + strlen(ary);
char *org = end;
while(start<org)
{
*end = *start;
start++;
end++;
}
*end = '\0';
}
int main(void) {
char word[255] = {"TACsasasa"};
double_string(word);
printf("%s",word);
return 0;
}
I am unable to understand what is getting stored in character array "*end", I tried printing it but I am not getting any output printed..
char *end = ary + strlen(ary);
This line of code is taking the starting address of the char array in memory, adding the number of bytes inside the array, returned by strlen(), and essentially moving the pointer to the end. The end of the array is the null terminator. Printing that will show nothing as it takes it as an empty string.
Adding an unsigned int (or even a signed int!) is known as pointer arithmetic. It's legal and quite common in C code. You do have to be very careful about going out of the bounds of your memory buffer, though, or you will experience undefined behavior. This is bad. Fortunately, this code appears to be quite well behaved as long as the original string is less than half the length of its memory buffer.
Allow me to try some ASCII art to see if I can make clear what's going on in the double_string function. It starts with this:
char *start = ary;
char *end = ary + strlen(ary);
char *org = end;
At this point, your pointers look like this:
start end
| |
| org
| |
v V
----------------------------------------------------------------------------------
ary | T | A | C | s | a | s | a | s | a |\0 | | | | | | | | | | | ...
----------------------------------------------------------------------------------
Then we have the loop.
while(start<org)
{
*end = *start;
start++;
end++;
}
After the first loop iteration, it looks like this:
start end
| |
| org |
| | |
v V V
----------------------------------------------------------------------------------
ary | T | A | C | s | a | s | a | s | a | T | | | | | | | | | | | ...
----------------------------------------------------------------------------------
Second iteration:
start end
| |
| org |
| | |
v V V
----------------------------------------------------------------------------------
ary | T | A | C | s | a | s | a | s | a | T | A | | | | | | | | | | ...
----------------------------------------------------------------------------------
And so on. The loop continues as long as start is less than (to the left of, in my illustration) org:
start end
| |
org |
| |
V V
----------------------------------------------------------------------------------
ary | T | A | C | s | a | s | a | s | a | T | A | C | s | a | s | a | s | a | | | ...
----------------------------------------------------------------------------------
Now start<org is no longer true, because they're equal. They point to the same location. The loop terminates. All that's left to do is terminate the string with *end = '\0';:
start end
| |
org |
| |
V V
----------------------------------------------------------------------------------
ary | T | A | C | s | a | s | a | s | a | T | A | C | s | a | s | a | s | a |\0 | | ...
----------------------------------------------------------------------------------
| |0|1|2|3|4|5|6|7|8|9|
|0| | | | | | | | | | |
|1| | | | | | | | | | |
|2| | | | | | | | | | |
|3| | | | | | | | | | |
|4| | | | | | | | | | |
|5| | | | | | | | | | |
|6| | | | | | | | | | |
|7| | | | | | | | | | |
|8| | | | | | | | | | |
|9| | | | | | | | | | |
I am trying to make a grid that looks like this. I currently keep getting Segmentation Fault Core dumped whenever I try to run the executable. The compiler is also not showing any errors. I am not sure how to print the numbers inside the grid either. Below is the code I currently have (just a part of the whole assignment). Any help is greatly appreciated.
void displayBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH], Player * player)
{
/* TODO */
int i,j;
char grid[BOARD_HEIGHT + 2][BOARD_WIDTH + 2];
for(i = 0; i < BOARD_HEIGHT; i++)
{
for(j = 0; j < BOARD_WIDTH; j++)
{
grid[BOARD_HEIGHT + 2][BOARD_WIDTH + 2] = '|';
printf("%c", grid[BOARD_HEIGHT + 2][BOARD_WIDTH + 2]);
printf("%s", EMPTY_OUTPUT);
}
printf("\n");
}
}
The BOARD_HEIGHT and BOARD_WIDTH are variables defined in a header file.
#ifndef BOARD_H
#define BOARD_H
#include "helpers.h"
#include "player.h"
#define BOARD_WIDTH 10
#define BOARD_HEIGHT 10
typedef enum cell
{
EMPTY,
BLOCKED,
PLAYER
} Cell;
#define EMPTY_OUTPUT " "
#define BLOCKED_OUTPUT "*"
Cell BOARD_1[BOARD_HEIGHT][BOARD_WIDTH];
Cell BOARD_2[BOARD_HEIGHT][BOARD_WIDTH];
typedef enum playerMove
{
PLAYER_MOVED,
CELL_BLOCKED,
OUTSIDE_BOUNDS
} PlayerMove;
void initialiseBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH]);
void loadBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH],
Cell boardToLoad[BOARD_HEIGHT][BOARD_WIDTH]);
Boolean placePlayer(Cell board[BOARD_HEIGHT][BOARD_WIDTH], Position position);
PlayerMove movePlayerForward(Cell board[BOARD_HEIGHT][BOARD_WIDTH],
Player * player);
void displayBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH], Player * player);
#endif
this second part is in the header file.
The full code can be found here a1
Your bug is on the line where you index grid beyond the end of the array:
grid[BOARD_HEIGHT + 2][BOARD_WIDTH + 2] = '|'; // Bug
This line writes beyond the end of the grid array defined locally as:
char grid[BOARD_HEIGHT + 2][BOARD_WIDTH + 2];
Note that the valid indexes into grid[][] go from 0 to BOARD_HEIGHT+1, and 0 to BOARD_WIDTH+1. Your code is accessible one past this in both dimensions.
This results in corrupting the stack, so when the displayBoard function returns, it has corrupted the stack and you get a segmentation fault. Removing this line eliminates the seg fault, but the code still needs work for function correctly.
You should reference the board array, and use indexes i and j, not hardcoded constants.
Here is a working version where I index into the board array, store the current cell value in currentCell, then display it based on a switch statement. This produces the following output given an empty board filled with zeroes:
scott> gcc -g -ogeraldTest -O0 board.c
scott> geraldTest
| |0|1|2|3|4|5|6|7|8|9|
|0| | | | | | | | | | |
|1| | | | | | | | | | |
|2| | | | | | | | | | |
|3| | | | | | | | | | |
|4| | | | | | | | | | |
|5| | | | | | | | | | |
|6| | | | | | | | | | |
|7| | | | | | | | | | |
|8| | | | | | | | | | |
|9| | | | | | | | | | |
Here is the code for main() and printBoard, both in board.c. Note that printBoard is passed the board by value, but it would be better to pass it by reference.
#include <stdio.h>
#include "board.h"
void displayBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH], Player * player)
{
int i,j;
// First display the header at the top.
printf("| |");
for(j=0; j<BOARD_WIDTH;j++)
printf("%d|",j);
printf("\n");
for(i = 0; i < BOARD_HEIGHT; i++)
{
// Display each row number
printf("|%d|",i);
for(j = 0; j < BOARD_WIDTH; j++)
{
// Bug: grid[BOARD_HEIGHT + 2][BOARD_WIDTH + 2] = '|';
Cell currentCell = board[i][j];
switch(currentCell) {
case BLOCKED:
printf("%s",BLOCKED_OUTPUT);
break;
case PLAYER:
printf("P");
break;
default:
printf("%s",EMPTY_OUTPUT);
break;
}
printf("|");
// This code is wrong
// printf("%c|", grid[BOARD_HEIGHT + 2][BOARD_WIDTH + 2]);
// printf("%s", EMPTY_OUTPUT);
}
printf("\n");
}
}
int main(int argc, char ** argv)
{
Cell myBoard[BOARD_HEIGHT][BOARD_WIDTH] = {0};
Player bob = 0;
displayBoard(myBoard, &bob);
}
I took your board.h and defined the missing types in order to get it to compile. You can likely just use your own headers as is.
#ifndef BOARD_H
#define BOARD_H
// #include "helpers.h"
// #include "player.h"
#define BOARD_WIDTH 10
#define BOARD_HEIGHT 10
typedef int Boolean; // Added
typedef int Player; // Added
typedef struct { // Added
int row;
int col;
} Position;
typedef enum cell
{
EMPTY,
BLOCKED,
PLAYER
} Cell;
#define EMPTY_OUTPUT " "
#define BLOCKED_OUTPUT "*"
Cell BOARD_1[BOARD_HEIGHT][BOARD_WIDTH];
Cell BOARD_2[BOARD_HEIGHT][BOARD_WIDTH];
typedef enum playerMove
{
PLAYER_MOVED,
CELL_BLOCKED,
OUTSIDE_BOUNDS
} PlayerMove;
void initialiseBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH]);
void loadBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH],
Cell boardToLoad[BOARD_HEIGHT][BOARD_WIDTH]);
Boolean placePlayer(Cell board[BOARD_HEIGHT][BOARD_WIDTH], Position position);
PlayerMove movePlayerForward(Cell board[BOARD_HEIGHT][BOARD_WIDTH],
Player * player);
void displayBoard(Cell board[BOARD_HEIGHT][BOARD_WIDTH], Player * player);
#endif
I've just started doing a unit of programming in C and my first assignment is to make a simple console version of the classic Battleship game.
A part of this - and the part I'm having trouble with at the moment - is displaying information to the player at each turn.
This is what we've been asked to have our display look like:
And, with a minimum of fuss, I've got mine looking like this:
(My Player grid is empty at the moment because its 2D array is empty, but if I use an array with something in it, it's fine.)
My header file:
/* Header files. */
#include <stdio.h>
#include <stdlib.h>
#define UNKNOWN ' '
#define SIZE 10
/* Function prototypes. */
void init(char playerHidden[SIZE][SIZE], char playerReveal[SIZE][SIZE],
char computHidden[SIZE][SIZE], char computReveal[SIZE][SIZE]);
void displayKnownInfo(char playerReveal[SIZE][SIZE],
char playerHidden[SIZE][SIZE],
char computReveal[SIZE][SIZE]);
My C source file:
#include "bship.h"
int main(void)
{
/* Stores player ship position information secret to opponent. */
char playerHidden[SIZE][SIZE];
/* Stores player ship position information known to opponent. */
char playerReveal[SIZE][SIZE];
/* Stores computer ship position information secret to opponent. */
char computHidden[SIZE][SIZE];
/* Stores computer ship position information known to opponent. */
char computReveal[SIZE][SIZE];
init(playerHidden, playerReveal,
computHidden, computReveal);
displayKnownInfo(playerReveal, playerHidden, computReveal);
return EXIT_SUCCESS;
}
/****************************************************************************
* Function init() initialises every cell in the four grids to a safe default
* value. The UNKNOWN constant is used for the initialisation value.
****************************************************************************/
void init(char playerHidden[SIZE][SIZE], char playerReveal[SIZE][SIZE],
char computHidden[SIZE][SIZE], char computReveal[SIZE][SIZE])
{
/*Variables i and j for each dimension of the Arrays*/
int x,y;
/*For each increment BETWEEN 0 and 'SIZE', firstly for i;*/
for(y=0; y<SIZE; y++)
{
/*And then for j;*/
for(x=0; x<SIZE; x++)
{
/*Populate that cell with the constant UNKNOWN*/
playerHidden[x][y]=UNKNOWN;
playerReveal[x][y]=UNKNOWN;
computHidden[x][y]=UNKNOWN;
computReveal[x][y]=UNKNOWN;
}
}
}
/****************************************************************************
* Function displayKnownInfo() presents revealed information about the game in
* the format below. In this example, both contestants have made five
* guesses.
* As you can see, the computer player got lucky with all five guesses and has
* sunk the human players' aircraft carrier. The identity of the ship was
* revealed when the aircraft carrier was HIT the fifth time.
* The human player has been less lucky. The first four guesses were a MISS.
* However, the fifth guess was a HIT on the computer players' submarine. The
* human player does not yet know the identity of this ship yet as it is still
* afloat.
* All other squares are still UNKNOWN.
*
* Player | Computer
* 1 2 3 4 5 6 7 8 9 0 | 1 2 3 4 5 6 7 8 9 0
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* a |A| | | | | | | | | | | a | | | | | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* b |A| | | | | | | | | | | b | | | | | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* c |A| | | | | | | | | | | c | | | | | | |=| | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* d |A| | | | | | | | | | | d | | |x| | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* e |A| | | | | | | | | | | e | | | | | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* f | | | | | | | | | | | | f | | | | |=| | | | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* g | | | | | | | | | | | | g | | | | | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* h | | | | | | | | | | | | h | |=| | | | |=| | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* i | | | | | | | | | | | | i | | | | | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* j | | | | | | | | | | | | j | | | | | | | | | | |
* +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+
* Aircraft Carrier (5/5) | 0/5 ships sunk.
* Battleship (0/4) | 1 hits.
* Destroyer (0/3) | 4 misses.
* Frigate (0/3) |
* Submarine (0/2) |
****************************************************************************/
void displayKnownInfo(char playerReveal[SIZE][SIZE],
char playerHidden[SIZE][SIZE],
char computReveal[SIZE][SIZE])
{
/*Ints for stepping through the arrays*/
int i,j;
/*First row identifier*/
char row='a';
/*Printing first few lines.*/
printf(" Player | Computer\n");
printf(" 1 2 3 4 5 6 7 8 9 0 | 1 2 3 4 5 6 7 8 9 0\n");
printf(" +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+\n");
printf(" %c |", row);
/*Loop through the arrays*/
for(i=0; i<SIZE; i++)
{
for(j=0; j<SIZE; j++)
{
/*Print the char at [i][j] with a '|' afterwards.*/
printf("%c|",playerReveal[i][j]);
}
/*After reaching column '0' on the display, increment the row identifier*/
row++;
/*And print the 'spacer' row.*/
printf("\n +-+-+-+-+-+-+-+-+-+-+ | +-+-+-+-+-+-+-+-+-+-+");
/*If the current row identifier is less than 'k', we want to print it*/
if(row<'k')
{
printf("\n %c |",row);
}
else
{
printf("\n");
}
/*And continue until the array has been printed in full.*/
}
}
}
Eventually, the PlayerHidden array will be overlaid on the PlayerReveal array when a player's ship has been sunk and its identity 'revealed', but for now I'm just wanting to get the computer half of the display working.
Just add this to your code after the second loop where you prints stuff:
printf(" %c |", row);
for(j=0; j<SIZE; j++)
{
/*Print the char at [i][j] with a '|' afterwards.*/
printf("%c|",computReveal[i][j]);
}
So your code looks like:
//...
/*Loop through the arrays*/
for(i=0; i<SIZE; i++)
{
for(j=0; j<SIZE; j++)
{
/*Print the char at [i][j] with a '|' afterwards.*/
printf("%c|",playerReveal[i][j]);
}
printf(" %c |", row);
for(j=0; j<SIZE; j++)
{
/*Print the char at [i][j] with a '|' afterwards.*/
printf("%c|",computReveal[i][j]);
}
//...
Your problem is that you're only printing out the player portion. Take a look at the code:
for(i=0; i<SIZE; i++)
{
for(j=0; j<SIZE; j++)
{
/*Print the char at [i][j] with a '|' afterwards.*/
printf("%c|",playerReveal[i][j]);
}
// ...
}
You need to have another loop where you print out the computerReveal array
for(i=0; i<SIZE; i++)
{
for(j=0; j<SIZE; j++)
{
/*Print the char at [i][j] with a '|' afterwards.*/
printf("%c|",playerReveal[i][j]);
}
for(j=0; j<SIZE; j++)
{
/*Print the char at [i][j] with a '|' afterwards.*/
printf("%c|",computReveal[i][j]);
}
// ...
}
That should do it. You're printing out the full width row separators, but not the portion of the array that creates the cell separators