Why do i get this stack smashing error in my program? - c

I am practicing my use of strcpy() in C and wrote this program.
#include <stdio.h>
#include <string.h>
int main(){
int array[4] = {3,7,1,5};
char str[4], temp[5];
for (int i = 0; i < 4; i++){
sprintf(&str[i],"%d", array[i]);
}
for (int i = 0; i < 4; i++){
strcpy(&temp[i],&str[i]);
printf("%c", temp[i]);
}
return 0;
}
~
Unfortunately i get a 'stack smashing' error why is this ?

Strings in C must be terminated by a NUL byte ('\0'), and you must account for that when you size your buffers.
Given the contents of array, the following code
for (int i = 0; i < 4; i++) {
sprintf(&str[i], "%d", array[i]);
}
will write bytes as follows, remembering that arrays are indexed from 0:
'3' to the 0th index, '\0' to the 1st index
'7' to the 1st index, '\0' to the 2nd index
'1' to the 2nd index, '\0' to the 3rd index
'5' to the 3rd index, '\0' to the 4th index
You write over the previously placed NUL with the current integer. Do you see the problem, though? There is not a 4th index in str[4]. You're going to write a byte to memory that you should not be accessing.
Even with str[5], so that there is room for the final NUL, the second part of your code would work in a very counter productive way.
The results of the first loop would have the contents of str be equal to "3714", such that
strcpy(&temp[i], &str[i]);
would then copy the strings as such:
"3714" to temp + 0
"714" to temp + 1
"14" to temp + 2
"4" to temp + 3
See how you're just walking along the same string, recopying the same tails to the same locations? printf("%c", temp[i]); is just going to print the first character of whichever tail you're on.
With enough room in str, this program is essentially a very round about way of writing:
int array[] = { 3, 7, 1, 5 };
for (int i = 0; i < 4; i++)
printf("%d", array[i]);
Additionally, if array were to contain any integers whose representation as a string required more than a single byte (e.g., -5, 32), this code would not scale at all.
You'll want to change str to be a 2d array, containing space for all the strings you will create from the integers in array
#include <stdio.h>
#include <string.h>
int main(void) {
int array[4] = {3, 7, 1, 5};
char str[4][12], temp[12];
for (int i = 0; i < 4; i++)
sprintf(str[i], "%d", array[i]);
for (int i = 0; i < 4; i++){
strcpy(temp, str[i]);
printf("[%d] %s\n", i, temp);
}
}
though this is still not a very interesting exercise for the use of strcpy, seeing as we could just print str[i] directly.
Here's an example to play around with of using strcpy when searching for the last integer in an array whose string representation is longer than than two characters.
#include <stdio.h>
#include <string.h>
int main(void) {
int array[] = { 3, 7, 123, 4, 13, -55, 29, 55 };
char string[12] = "0", temp[12];
for (int i = 0; i < (sizeof array / sizeof *array); i++)
if (sprintf(temp, "%d", array[i]) > 2)
strcpy(string, temp);
printf("Final value: %s\n", string);
}

Each str[i] can only hold a single character, not a string - when you write
sprintf( &str[i], "%d", array[i] );
you are attempting to write a 2-character string1 to a 1-character buffer; the string terminator is "spilling" into the array element str[i+1] until you get to str[3], in which case the terminator spills over the end of the array.
To store an array of strings, you need to set aside a 2D array of char:
char str[4][N+1]; // can hold 4 strings of length N, +1 for the string terminator
Then in your sprintf statement, you'd write
sprintf( str[i], "%d", array[i] ); // no & operator on str[i]
All the values in array are only one digit - for larger values, you would need more characters in your array. A string representation of a 32-bit int can have up to 10 digit characters, plus a sign character, plus the string terminator, so you need to set aside an array that can hold 12 elements, so ideally str should be declared as char str[4][12];

Related

Why my substring is not being saved in 'st1' in a for loop but when I'm trying to print each value of st1 in loop it is working?

Why in the for loop the value of st1 is not saved ie: when I'm printing st1 nothing is being printed?
#include <stdio.h>
#include <stdlib.h>
int main() {
char s[40] = "Who are you to tell me that I can not code?";
char st1[15];
for (int i = 2; i < 9; i++) {
st1[i] = s[i];
printf("%c", s[i]);
}
printf("\n Now Printing the Whole at once \n");
printf("%s", st1);
return 0;
}
Here is the Output.....
o are y
Now Printing the Whole at once
Process returned 0 (0x0) execution time : 0.052 s
Press any key to continue.
In your code st[0] and st[1] are never set, so printing the string with printf has undefined behavior. st[0] probably happens to be a null byte, so printf prints nothing.
You should use a different index into st1 and set a null byte at the end.
Beware also that s is not null terminated either because it has exactly 40 characters so no space for a null terminator byte.
Here is a modified version:
#include <stdio.h>
int main() {
char s[] = "Who are you to tell me that I can not code?";
char st1[15];
int j = 0;
for (int i = 2; i < 9; i++) {
st1[j++] = s[i];
printf("%c", s[i]);
}
st1[j] = '\0';
printf("\nNow Printing the whole at once\n");
printf("%s\n", st1);
return 0;
}
This loop
for (int i = 2; i < 9; i++) {
st1[i] = s[i];
reads from s at indices [2, 8], but also writes to st1 at indices [2, 8]. This means indices [0, 1] and [9, 14] of st1 contain indeterminate values, having never been initialized. Reading these values is a form of undefined behaviour.
Use a separate index to place values from the start of st1, and make sure to null-terminate the result.
int j = 0;
for (int i = 2; i < 9; i++) {
st1[j++] = s[i];
printf("%c", s[i]);
}
st1[j] = '\0';
Aside: this initializer, being of type char [44], is too long for the array being initialized.
char str[40] = "Who are you to tell me that I can not code?";
XXX.c:5:18: warning: initializer-string for char array is too long
char s[40] = "Who are you to tell me that I can not code?";
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use an empty size declarator to have the array automatically sized to match its initializer.
char str[] = "Who are you to tell me that I can not code?";

C - how to add to the end of a char array after realloc()

I have a short char array called "array". I'm trying to realloc more space to it then add more chars onto the end. for some reason when I print the array, these extra characters don't show up, although they do display when I index them individually.
#include <stdio.h>
#include <stdlib.h>
int main(){
char *array = malloc(2);
array[0] = 'b';
array[1] = '\0';
char stringToAdd[] = "honey";
array = realloc(array, (16));
int pos;
//add stringToAdd into array one char at a time
for (pos = 0; pos < 5; pos++){
array[2+pos] = stringToAdd[pos];
printf("%d ", 2+pos);
printf("%c ", array[2+pos]);
printf("%s\n", array);
}
array[pos] = '\0';
int k = sizeof(array);
//should print out the string "bhoney" and its length
printf("%s, length = %d\n", array,k);
free(array);
return 0;
}
output is:
2 h b
3 o b
4 n b
5 e b
6 y b
b, length = 8
also the length of the array seems to be 8 no matter how much space I try to realloc to it?
You added the characters after the null terminator. Printing a string stops at the null.
Assign the new characters to array[1+pos] instead of array[2+pos]. This also goes for adding the new null terminator after the loop, it should be
array[1+pos] = '\0';
You could also use strcat() instead of the loop:
strcat(array, stringToAdd);
It will find the null terminator automatically so you don't have to know the offset, and add the new null terminator properly.
sizeof(array) is the size of the pointer (8 bytes), not the length of the string. If you want the string length, you should use strlen(array). See difference between sizeof and strlen in c
It should be:
for (pos = 0; pos < 5; pos++){
array[1+pos] = stringToAdd[pos];
printf("%d ", 1+pos);
printf("%c ", array[1+pos]);
printf("%s\n", array);
}
array[1+pos] = '\0';

Getting different lengths for the same operation with different number values in C

I have 2 for-loops which populate arrays with letters from the alphabet. I have a lowercase array set, and an uppercase array set. The problem is when I initialize the arrays with the letters, the lengths are coming back different.
char uppercase[26];
char lowercase[26];
int indexUpper = 0;
int indexLower = 0;
// Get uppercase array:
for(int a = 65; a <= 90; a++){
uppercase[indexUpper] = a;
indexUpper++;
}
// Get lowercase array:
for(int b = 97; b <= 122; b++){
lowercase[indexLower] = b;
indexLower++;
}
printf("UPPERCASE = %lu\n", strlen(uppercase));
printf("LOWERCASE = %lu\n", strlen(lowercase));
$=> UPPERCASE = 26
$=> LOWERCASE = 27
I apologize if this is a no brainer. I am truly trying to learn and comprehend the C language and its rules. Thanks to all who contribute.
strlen() reads the character array as long until it finds a NUL byte ('\0', numerical value zero). Your arrays don't contain any, since you haven't assigned one there.
That means that strlen will continue reading past the end of the array, which is illegal, and the resulting behaviour is not defined. Getting a 27 is rather mild, you could be getting arbitrary numbers, or your program could crash.
If you want to use strlen(), you should explicitly assign a NUL byte at the end of the string, and of course allocate space for it.
Perhaps something like this:
#include <stdio.h>
#include <string.h>
int main(void)
{
char upper[27];
int i;
for (i = 0 ; i < 26; i++) {
/* This only works in a character set where the letters
are contiguous */
upper[i] = 'A' + i;
}
/* i == 26 now */
upper[i] = '\0';
printf("len: %u\n", (unsigned) strlen(upper));
return 0;
}
(Though using strlen here at all seems somewhat pointless, since you already know the number of items in those arrays.)
When using strlen the char array must be nul terminated - but yours isn't so you have undefined behavior.
To print the size of the arrays try:
printf("UPPERCASE = %zu\n", sizeof uppercase);
printf("LOWERCASE = %zu\n", sizeof lowercase);

Issues with creating a copy of an argument in C

I am converting string arguments into ints I am having an issue where the first argument is not copying and converting to a string while the second argument is working just fine. I am removing the first character of the string array and printing out the rest of the string as an int.
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(int argc, char *argv[])
{
char numcpy1[sizeof(argv[1])-1];
char numcpy2[sizeof(argv[2])-1];
int i, len1, len2;
int result1=0;
int result2=0;
//Access first character for base
printf("%c \n", argv[2][0]);
printf("%c \n", argv[3][0]);
//Remove first character for number1 and number 2
if(strlen(argv[2]) > 0)
{
strcpy(numcpy1, &(argv[2][1]));
}
else
{
strcpy(numcpy1, argv[2]);
}
len1 = strlen(numcpy1);
if(strlen(argv[3]) > 0)
{
strcpy(numcpy2, &(argv[3][1]));
}
else
{
strcpy(numcpy2, argv[3]);
}
len2 = strlen(numcpy2);
//Turn remaining string characters into an int
for(i=0; i<len1; i++)
{
result1 = result1 * 10 + ( numcpy1[i] - '0' );
}
for(i=0; i<len2; i++)
{
result2 = result2 * 10 + ( numcpy2[i] - '0' );
}
printf("%d \n", result1);
printf("%d \n", result2);
return 0;
}
Output:
b
b
-4844
1010
What I want:
b
b
1000
1010
The sizeof operator does not give you the length of a string, as you seem to think it does. It tell you the size of the datatype. Since argv[2] is a char *, this evaluates to the size of this pointer, most likely 4 or 8 depending on the system.
If the string in question is longer than this value, you end up writing past the end of the array. This invokes undefined behavior, which in your case manifests as an unexpected result.
If you want the length of the string, use the strlen function instead. Also, you need to add one more byte. Strings in C are null terminated, so you need space for the null byte that marks the end of the string.
char numcpy1[strlen(argv[2])];
char numcpy2[strlen(argv[3])];
Also note that we don't need to add 1 to each of these since the first character in each string isn't copied.
You need to change
char numcpy1[sizeof(argv[1])-1];
to
char numcpy1[strlen(argv[1]) + 1];
Ditto for numcpy2
I think instead of copying the numbers you could work more easily with pointers. Thereby, you don't have to think about memory allocation and copying the values just for the sake of converting them into an integer value:
const char *numcpy1 = argv[2][0]=='\0' ? argv[2] : argv[2]+1;
...

How to convert a list to a string

Problem in C programming
I have following list:
int a[] = {0,0,1,0,0,1,0,2}
How do i convert following list items to char variable b?
Like this:
printf(%c, b)
OUTPUT: 00100102
I need this for printing the values of list in embedded system lcd screen where normal print options aren't available. Couldn't find similar example from www.stackoverflow.com. Vice versa there were many solutions to convert a string into a list.
#include <stdio.h>
#include <stdlib.h>
int main(){
int a[] = {0,0,1,0,0,1,0,2};
const char *table = "0123456789";
size_t size = sizeof(a)/sizeof(*a);
char *b = malloc(size+1);
int i;
for(i=0;i<size;++i)
b[i]=table[a[i]];
b[i]='\0';
printf("%s\n", b);
free(b);
return 0;
}
int a = [0,0,1,0,0,1,0,2]
That is not valid C. Perhaps you meant:
const int a[] = { 0, 0, 1, 0, 0, 1, 0, 2 };
Converting a decimal digit to a printable character in C is easy, just add '0':
printf("%c", '0' + a[0]);
will print 0.
You can iterate through the elements of your array, and printf() each one, considering it as an offset from '0':
/*
'0' + 0 = '0'
'0' + 1 = '1'
'0' + 2 = '2'
*/
const int a[] = {0,0,1,0,0,1,0,2};
const int count = sizeof(a) / sizeof(a[0]);
int i;
for (i = 0; i < count; i++) {
printf("%c", '0' + a[i]);
}
printf("\n");
When you convert each value in an array of int to a corresponding value in an array of char, you just have an array of char. When you append the null terminator \0 (or 0) to the array of char, it becomes a C string.
int a[] = {0,0,1,0,0,1,0,2}; //use curly braces to assign values to new array.
char b[sizeof(a)/sizeof(a[0])+1];//Accomodates any size of a. note extra space for terminating \0
int i;
//EDIT 5 following lines
b[0]=0; //ensure string is null terminated
for(i=0;i<sizeof(a)/sizeof(a[0]);i++)
{
sprintf(b, "%s%d", b, a[i]);//copy one char per loop to concatenate string with all elements of `a`
}
Now you have a string, sized according to number of array elements in a that looks like:
"00100102"
In memory you would see |48|48|49|48|48|49|48|50|0|
(the integer values of each character representation of the integers 0, 1, & 2, with the null character 0 in the last position to mark the end of string.)
Note also, the phrase sizeof(array)/sizeof(array[0]) is used to get the number of elements in an array.

Resources