Valhalla Legends Forums Archive | C/C++ Programming | C Question

AuthorMessageTime
FrOzeN
With the following code:
[code]#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]) {
    char strTemp[11];

    sGetMessage(strTemp);
    printf("%s\n", strTemp);

    system("PAUSE");
    return 0;
}

sGetMessage(char* Message) {
    strcpy(Message, "Hello World!");
}[/code]

Should the sGetMessage function have a data type scope?

Eg,
[code]int sGetMessage(char* Message) {
    strcpy(Message, "Hello World!");
    return 0;
}[/code]
May 29, 2006, 10:21 PM
Rule
Well, ISO C "forbids a definition without a datatype or storage class."

So, yes, you should definitely declare a return type for sGetMessage, even if it's void.  If you're compiling with gcc, it's good to use the flags "-ansi -Wall -pedantic" to check for such things.  Also, since you're using system, you should include stdlib.h. 

It seems strange that char strTemp[11] works to hold "Hello World!".... Doesn't it make sense that you should need a character array of size [13], to hold the
characters in "Hello World!" as well as the null terminating character?  I tried playing around with the size of strTemp; I don't get a segmentation fault (when copying "Hello World! into strTemp) unless strTemp is less than 3 in size. Why is this?!

Edit: if I declare char strTemp[0], the program still prints "Hello World!"
If I declare char strTemp[1], the program prints "Hello World!" and gives me a segmentation fault.

How can this be explained?


May 29, 2006, 10:52 PM
FrOzeN
I didn't pay much attention to the character array. I originally just typed strTemp[11] thinking it would work like:

[quote]strTemp[0] ="H"
strTemp[1] ="e"
strTemp[2] ="l"
strTemp[3] ="l"
strTemp[4] ="o"
strTemp[5] =" " // (Space)
strTemp[6] ="W"
strTemp[7] ="o"
strTemp[8] ="r"
strTemp[9] ="l"
strTemp[10] ="d"
strTemp[11] ="!"[/quote]

Though, now that I think of it. Declaring [11] would make [10] the highest as it starts for zero. Wasn't really thinking about it at the time because it worked when I compiled it. (I have no idea why it works either, maybe strcpy resizes the array?)
[hr]I'm using Dev-Cpp and in the IDE I just click the "Compile and Run" option on the toolbar, so I'm not exactly sure which compiler it's using (I think it's MingW/GCC).
May 30, 2006, 12:23 AM
Rule
[quote author=FrOzeN link=topic=15087.msg153408#msg153408 date=1148948589]
I didn't pay much attention to the character array. I originally just typed strTemp[11] thinking it would work like:

[quote]strTemp[0] ="H"
strTemp[1] ="e"
strTemp[2] ="l"
strTemp[3] ="l"
strTemp[4] ="o"
strTemp[5] =" " // (Space)
strTemp[6] ="W"
strTemp[7] ="o"
strTemp[8] ="r"
strTemp[9] ="l"
strTemp[10] ="d"
strTemp[11] ="!"[/quote]

Though, now that I think of it. Declaring [11] would make [10] the highest as it starts for zero. Wasn't really thinking about it at the time because it worked when I compiled it.
[/quote]
You'd need 12 places for the characters, and 1 space for the null terminating character, '\0'.
Try:
printf("%d\n", sizeof("Hello World!"));

[quote author=FrOzeN link=topic=15087.msg153408#msg153408 date=1148948589]
(I have no idea why it works either, maybe strcpy resizes the array?)
[/quote]
Nope, I checked this...

[quote author=FrOzeN link=topic=15087.msg153408#msg153408 date=1148948589]
I'm using Dev-Cpp and in the IDE I just click the "Compile and Run" option on the toolbar, so I'm not exactly sure which compiler it's using (I think it's MingW/GCC).
[/quote]
In that case you can probably turn on some helpful compiling/debugging options that will provide you with warnings in certain situations.
May 30, 2006, 12:38 AM
Kp
The compiler is placing the array on the stack in such a way that there's some slack space between the last cell you requested ([10]), and the last cell which can be overwritten without destroying something important.  When you make strTemp small enough, the padding is no longer sufficient and writing into the array smashes the return address.
May 30, 2006, 2:19 AM
Rule
[quote author=Kp link=topic=15087.msg153415#msg153415 date=1148955570]
The compiler is placing the array on the stack in such a way that there's some slack space between the last cell you requested ([10]), and the last cell which can be overwritten without destroying something important.  When you make strTemp small enough, the padding is no longer sufficient and writing into the array smashes the return address.
[/quote]

Makes sense, although why would strTemp[0] not cause a segmentation fault (and work fine), yet strTemp[a] (where 0<a<4) does (but still works properly)?
I imagine the memory that had those last characters stored in it previously (e.g. in the padding space) is still being called, and that is why both work.  Although it's puzzling why strTemp[0] would not cause a segmentation fault and strTemp[1] would.

 


May 30, 2006, 2:43 AM
Kp
That is best answered by examining the code generated by the compiler.  Run gcc -S str.c and post the results.  The output of gcc -v may also be enlightening.
May 30, 2006, 3:40 AM
Rule
Diffs of .s files at end of post.

frq1.c:
[code]
#include <stdio.h>
#include <string.h>

void sGetMessage(char* Message);

int main(int argc, char* argv[]) {
    char asdf[1];

    sGetMessage(asdf);
    printf("%s\n", asdf);
   
    return 0;
}

void sGetMessage(char* Message) {
    strcpy(Message, "Hello World!");
}
[/code]

Output:
[quote]
Hello World!
Segmentation fault
[/quote]

frq1.s:
[code]
.file "frq1.c"
.section .rodata
.LC0:
.string "%s\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
subl $12, %esp
leal -1(%ebp), %eax
pushl %eax
call sGetMessage
addl $16, %esp
subl $8, %esp
leal -1(%ebp), %eax
pushl %eax
pushl $.LC0
call printf
addl $16, %esp
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.LC1:
.string "Hello World!"
.text
.globl sGetMessage
.type sGetMessage, @function
sGetMessage:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
subl $8, %esp
pushl $.LC1
pushl 8(%ebp)
call strcpy
addl $16, %esp
leave
ret
.size sGetMessage, .-sGetMessage
.section .note.GNU-stack,"",@progbits
[/code]

Modified frq.c so that strTemp is declared to be size 0.  (char strTemp[0])

Output:
[quote]
Hello World!
[/quote]

New frq.s:
[code]
.file "frq.c"
.section .rodata
.LC0:
.string "%s\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
subl $12, %esp
leal -24(%ebp), %eax
pushl %eax
call sGetMessage
addl $16, %esp
subl $8, %esp
leal -24(%ebp), %eax
pushl %eax
pushl $.LC0
call printf
addl $16, %esp
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.LC1:
.string "Hello World!"
.text
.globl sGetMessage
.type sGetMessage, @function
sGetMessage:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
subl $8, %esp
pushl $.LC1
pushl 8(%ebp)
call strcpy
addl $16, %esp
leave
ret
.size sGetMessage, .-sGetMessage
.section .note.GNU-stack,"",@progbits
[/code]

frq100.s      (changed strTemp to size 100):
[code]
.file "frq100.c"
.section .rodata
.LC0:
.string "%s\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $120, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
subl $12, %esp
leal -120(%ebp), %eax
pushl %eax
call sGetMessage
addl $16, %esp
subl $8, %esp
leal -120(%ebp), %eax
pushl %eax
pushl $.LC0
call printf
addl $16, %esp
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.LC1:
.string "Hello World!"
.text
.globl sGetMessage
.type sGetMessage, @function
sGetMessage:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
subl $8, %esp
pushl $.LC1
pushl 8(%ebp)
call strcpy
addl $16, %esp
leave
ret
.size sGetMessage, .-sGetMessage
.section .note.GNU-stack,"",@progbits
[/code]

Differences between frq.s and frq1.s
[code]
diff frq.s frq1.s
1c1
<      .file  "frq.c"
---
>      .file  "frq1.c"
11c11
<      subl    $24, %esp
---
>      subl    $8, %esp
20c20
<      leal    -24(%ebp), %eax
---
>      leal    -1(%ebp), %eax
25c25
<      leal    -24(%ebp), %eax
---
>      leal    -1(%ebp), %eax
[/code]

Differences between frq1.s and frq100.s:
[code]
diff frq1.s frq100.s
1c1
<      .file  "frq1.c"
---
>      .file  "frq100.c"
11c11
<      subl    $8, %esp
---
>      subl    $120, %esp
20c20
<      leal    -1(%ebp), %eax
---
>      leal    -120(%ebp), %eax
25c25
<      leal    -1(%ebp), %eax
---
>      leal    -120(%ebp), %eax
[/code]


It looks as though strTemp[0] has an effective size  of "24" (bytes?) , while strTemp[1] has 8?    Why leal -1(%ebp), %eax for strTemp[1] though, and leal -24... for strTemp[0],
-120 for strTemp[100]?

Note: only differences between frq1.s and frq2.s (strTemp size 2),
[code]
diff frq2.s frq1.s
1c1
<      .file  "frq2.c"
---
>      .file  "frq1.c"
20c20
<      leal    -2(%ebp), %eax
---
>      leal    -1(%ebp), %eax
25c25
<      leal    -2(%ebp), %eax
---
>      leal    -1(%ebp), %eax
[/code]

e.g. no subl difference
May 30, 2006, 6:02 PM

Search