Why does it print random symbols when exceeding 44 characters - c

I'm learning C from a book C programming:Modern approach. Right now I'm going trough exercises about arrays. One of the exercises is to write a filter that prints the input message differently.
I've gotten so far (see the code below), everything works fine, until the character count exceeds 44, then it prints random symbols. If the character count is below 44 everything works fine. I have absolutely no clue why it does that. Where is the problem and what might be the solution?
int i = 0, k = 0;
char message[k],ch;
printf("Enter a message: ");
while(toupper(ch = getchar()) != '\n')
{
message[k] = ch;
k++;
}
printf("In B1FF-speak: ");
for (i = 0; i <= k - 1; i++)
{
switch(toupper(message[i]))
{
case 'A':
printf("4");
break;
case 'B':
printf("8");
break;
case 'E':
printf("3");
break;
case 'I':
printf("1");
break;
case 'O':
printf("0");
break;
case 'S':
printf("5");
break;
default:
printf("%c", toupper(message[i]));
break;
}
}

int i = 0, k = 0;
char message[k],ch;
You've defined message as a variable length array (VLA). (This is a feature that doesn't exist in the 1990 version of C; it was added by the 1999 standard and made optional by the 2011 standard.)
Since the value of k is 0, the length of message is 0. C does not support zero-length arrays. Defining an array with a constant length of zero is illegal (a constraint violation, requiring a diagnostic). Defining a variable length array with a length of zero has undefined behavior.
The length of a VLA is fixed when it's defined. Changing the value of k later on does not change the length of the array. Your code seems to assume that it will.
Your program seems to work for lengths up to 44. That's the nature of undefined behavior. The worst thing that can happen is that your program seems to work "correctly"; that just means that you have a bug that's difficult to detect.
If you want to store arbitrarily many elements in an array, you can either define it with a size that's big enough in the first place (it can be difficult or impossible to determine how big it has to be), or you can use realloc() to allocate the array dynamically and expand it as needed. (realloc() doesn't actually expand the array; it creates a new array with a larger size and copies the contents of the old array into the new array. And it can fail if there isn't enough available memory; always check the value it returns to determine whether it succeeded or failed.)

Related

C - "Run-Time Check Failure #2 - Stack around the variable 'cstringValue' was corrupted."

This code is to check whether the length of the user input is within the range of the lower and the upper limit. Or if upper limit and the lower limt are equal, testing whether the string length equal to variable 'equal'. For now, I am trying to return the string STEVEN to the main function but it keep on pops up "Run-Time Check Failure #2 - Stack around the variable 'cstringValue' was corrupted." The code works fine when the number of length does not equal to variable 'equal'.
I've tried the following:
The function code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "core.h"
#include <string.h>
void inputCString(char *charPointer[], int lower, int upper)
{
int count, equal;
if (upper != lower)
{
goto notEqual;
}
else if (upper == lower)
{
goto upperEqualLower;
}
notEqual:
do
{
scanf("%s%n", *charPointer, &count);
count--;
if (count > upper || count < lower)
{
printf("ERROR: String length must be between %d and %d chars: ", lower, upper);
}
else
{
return *charPointer;
}
} while (count > upper || count < lower);
upperEqualLower:
do
{
equal = upper;
scanf("%s%n", &*charPointer, &count);
count--;
if (count != equal)
{
printf("ERROR: String length must be exactly %d chars: ", upper);
}
else if (count == equal)
{
return *charPointer;
}
} while (count != equal);
The main:
char cstringValue[7] = { '\0' };
printf("TEST #6: - Instructions:\n"
"1) Enter the word 'horse' [ENTER]\n" // too short
"2) Enter the word 'chicken' [ENTER]\n" // too long
"3) Enter the word 'STEVEN' [ENTER]\n" // just right
":>");
inputCString(cstringValue, 6, 6);
printf("////////////////////////////////////////\n");
printf("TEST #6 RESULT: ");
printf("%s (expected result: STEVEN)\n", cstringValue);
printf("////////////////////////////////////////\n\n");
Thanks in advance.
The type of your charPointer parameter is char** – while you dereference it correctly for first scanf (inequality case), you don't do so for second one (equality case: &*somePointer is equivalent to just somePointer). This is undefined behaviour, as the pointer type does not meet the format specifier.
Additionally, you need to create a pointer to pointer of cstringValue to be passed to the function – and simply doing &cstringValue will provide a pointer to array, which again is of bad type. So you need: char* ptr = cstringValue; inputCString(&ptr, ...);. The compiler should have warned you about mismatching pointer types (if not, increase warning level!), and you absolutely should listen to! (You might potentially get away with in the equality case as you provide mismatching pointers twice and the errors might compensate each other – still that remains undefined behaviour, the code working is pure luck).
Much simpler, though, is just turning the parameter in an ordinary char* pointer, then you can pass it to scanf directly without dereferencing and passing the input array to the function as is now gets correct again as well.
Depending on your input, you risk undefined behaviour by writing beyond array bounds as well – consider input like "dragonfly", which does not fit into the array! scanf still will try to write to, as you do not limit the input length – the length check (count) only occurs after the data has already been written to the array!
Providing a longer buffer reduces the risk of, but does not eliminate it. To be safe, you need to limit scanf to scan only up to some maximum. Unfortunately the maximum cannot be provided by passing an additional argument to scanf as with printf, so you need to adjust your format string accordingly, either using a constant string:
#define MAX_INPUT 7
#define ARRAY_SIZE (MAX_INPUT + 1) // need space for a null-terminator!
#S(TEXT) S_(TEXT) // stringifying macro
#S_(TEXT) #TEXT // need indirection for
scanf("%" S(MAX_INPUT) "s", ...);
// quite a lot of work to be safe, I know...
or dynamically:
char format[8];
sprintf(format, "%%%ds%%n", length - 1);
// - 1: need to leave space for the null terminator
// (assuming you provide length as an additional parameter)
scanf(format, ...);
There are quite a number of further issues in your code:
You try to return *charPointer;, but return type of the function is void.
if(condition) {} else if(complementary condition) { } – if the initial condition has not been met then the complementary one must – so if getting into the else branch the second if is always met and you should just drop it: if(condition) {} else {}.
There are valid use cases for goto (like exiting from nested loops), but this one here isn't. You could just place the respective code blocks into the body of the if and else branches. Apart from, you do not have to differentiate between lower and upper differing at all, as if both values are equal one of count < lower or count > upper will apply if count is not equal to any of them (they are equal, remember?). Well, the error message differs, but you could select it before the loop: `char const* errorMsg = upper == lower ? "exactly" : "between;".
More interesting would be an additional check for lower <= upper, combined with appropriate error handling if not, as this would definitely lead to an endless loop.
count-- – why are you reducing it? "%n" provides the number of characters read, not the number of characters written to the array (the latter includes a null-terminator, the former not). So if 3 characters have been read for "abc", you end up with 2 and I doubt that is what you really want...
Labels do not produce any scope – they are just a marker where to continue execution in case of a goto but are otherwise ignored. That means that if you complete the code after notEqual it will just continue with the code after upperEqualLower. It appears unclear to me if you are aware of that, so noticing – in your specific case the fall-through is prevented by returning from the function before reaching the next label, so not an issue here. You won't run into this at all if you follow the recommendation to goto above, though (moving into the if/else blocks).
Your loops don't need to check any condition: You check exactly the same condition already within and break the loop by returning, so if reaching the end of the loop body the condition is true and you continue anyway. You could instead simply have a for(;;) loop.
Fixing all these issues your code like look like this:
void inputCString(char charPointer[], size_t length, size_t lower, size_t upper)
// size_t: correct type for specifying array or object sizes; aditionally
// it's unsigned, as negative values for lower and upper are meaningless anyway
{
if(upper < lower)
{
// error handling!
}
char const* errorMsg = lower == upper ? "exactly" : "in between"; // examples
char format[8];
sprintf(format, "%%%ds%%n", length - 1);
int count;
for(;;)
{
scanf(format, charPointer, &count);
// personal preference of mine: place the return into the if block
// -> invert condition
if (lower <= count && count <= upper)
{
return;
}
// surplus argument in case of equality is no problem:
printf(errorMsg, lower, upper);
}
}

C for loop failing

So I'm new in C language and I'm trying to do a histogram with the length of the words the user typed, I have a solution but my second for loop always fail, I code like 5 for loop and every of them just stop after the second or third iteration, Am I missing something please help. Here's my code.
#include<stdio.h>
int main(){
int i,x,c,r,size;
int wa[10];
size=0;
for(i=0;i<10;i++){
wa[i]=0;
}
while((c=getchar())!=EOF){
switch(c){
case' ':{
wa[size]++;
size=0;
break;}
case'\n':{
wa[size]++;
size=0;
break;}
case'\t':{
wa[size]++;
size=0;
break;}
default:{
size++;
break;
}
}
}
for(r=0;r<=10;++r){
printf("%d",r);
for(x=0;x<wa[r];x++){
printf("*");
}
printf("\n");
}
return 0;
}
first, for testing purposes when running from Linux commandline Ctrl+d emulates EOF
second, your for loop iterates between ( 0 -10 inclusive ), your wa array index however is ranging from (0 - 9 inclusive ) which means:
for(x=0;x
call may cause SEGFAULT
third, you are missing a simple case where the input is just one word with no whitespace after, something like
abcdEOF
fourth, following the second paragraph when entering valus to the array your indexing is wrong
as far as the assumption that the longest words is 10char long thats fine but you must verify that the size never exceeds the value of 9 or if you will correct the wa update then 10 exceeding this value will cause segfault due to updating un-allocated index in the array
Hope this helps
The first for loop will start from 1, and in the second for loop replace wa[4] with wa[r].
Your code also assume that no word will be longer than 10 char.

Char** array first element being modified magically

I am sorry for the vague title, but I am having a very hard time figuring out how to describe this issue. I am trying to add data to an array and somehow it is all getting written to index 0 despite my explicitly indicating otherwise. I have created a minimal sample.
Expected Behavior
With command line arguments as -u rwx -g rw -o r:
bins[0] == "111"
bins[1] == "110"
bins[2] == "100"
Actual Behavior
Indices 0, 1 and 2 all end up as "100". If you put a printf() to check their value inside the various case statements, you will find that, for instance, when case 'g': runs, bins[1] == "110" AND bins[0] == "110". When case 'o': runs, all three indices will will hold the value "100".
Minimal functional sample
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void processPerms(char *targets, char **perms, char **bins, const size_t arrSize) {
for(int i = 0; i < arrSize; i++) {
//This string will be modified
//so that the right bits will
//be set.
char binDig[] = "000";
//We decide which, if any, bit
//to set based upon the current
//letter being considered.
for(int k = 0; k < strlen(perms[i]); k++) {
switch(perms[i][k]) {
case 'r':
binDig[0] = '1';
break;
case 'w':
binDig[1] = '1';
break;
case 'x':
binDig[2] = '1';
break;
}
}
//Here, we check the target
//whose index corresponds to
//the index of the permissions
//string we just accessed.
//They will always be in
//an order where the related
//target and perm str are in
//the same array position.
switch(targets[i]) {
case 'u':
bins[0] = binDig;
//bins[0] == "111"
break;
case 'g':
bins[1] = binDig;
//bins[0] == "110"
break;
case 'o':
bins[2] = binDig;
//bins[0] == "100" && bins[1] == "100"
break;
}
}
}
int main(int argc, char *argv[]) {
const size_t arrSize = (argc-1)/2;
char *targets = (char*)calloc(arrSize, sizeof(char));
char **perms = (char**)calloc(arrSize, sizeof(char*));
//Copying just the letters
//of the args into these
//arrays.
for(int i = 0; i < arrSize; i++) {
targets[i] = argv[i+(i+1)][1];
}
for(int i = 0; i < arrSize; i++) {
perms[i] = argv[i*2+2];
}
//This array should hold three
//strings which shall be binary
//representations of the
//permissions
char **bins = (char**)calloc(3, sizeof(char*));
processPerms(targets, perms, bins, arrSize);
return 0;
}
bins[2] = binDig;
This will make you point to a variable which has automatic storage duration. This is a gateway to undefined behavior when you are returning it from the function. The life time of the variable is over as in this case and accessing it is UB.(Dereferencing a pointer to variable beyond its lifetime is Undefine d behavior).
A easy solution would be to use (This is part of POSIX standard but it is common enough) (In case you don't have this, you can allocate memory and copy to it the content of the array binDig).
bins[2] = strdup(binDig);
(Make the same changes for bins[0] and bins[1]).
Making this change as mentioned gives the expected behavior of being bins[0] equal to "111" and so on. The only thing is that, you need to free the dynamically allocated memory (including as that of returned by strdup
when you are done working with it). Similarly, don't cast the return value of malloc,calloc etc(because void* to char* is an implicit conversion). And check the return value of malloc/calloc.
The lifetime of you binDig array is limited by one iteration of the outer for cycle. This binDig array gets destroyed at the end of each iteration and created anew at the beginning of the next iteration.
This means that everything you do during each iteration of the outer cycle is lost when that iteration ends. The value of bins[] that you assigned during that iteration begins to point to some indeterminate location in memory where nothing exists anymore. Any attempts to access data through the corresponding bins[] entries lead to undefined behavior.
In real life each iteration of the cycle will typically recreate binDig at exactly the same location in memory, which creates an illusion of all of your bins[] pointers remaining valid but pointing to the same value. But this is a mere illusion. The behavior is already undefined at that point.
When the outer cycle ends the binDig array disappears forever and all your bins[] pointers become hopelessly invalid for good. But that's just the last straw. Your program died well before that moment.

Remove an element from an array of structures in C?

I'm new to C, and honestly have no idea where to start with removing a particular element from an array of structures.
If you wish, you can view and copy my code in its entirety here: http://pastebin.com/Zbrm2xyL
Mostly I'm concerned with the function 'rmv_student', which is supposed to remove the struct with a matching id number from the array 'st_array' without messing with the other elements of that array after prompting the user for confirmation. Function 'rmv_student' is as follows:
void rmv_student(long id) // BROKEN
{
int i; // iterator
char response; // used to confirm deletion
for( i = 0; i < MAX; i++){
if ( st_array[i].id == id){
printf("Are you sure you want to delete %s %s, %d?\n", st_array[i].first_name, st_array[i].last_name, st_array[i].id);
puts("You will not be able to undo the deletion.");
puts("Enter 'y' to delete or 'n' to return to the main menu.");
response = getchar();
switch (response){
case 'y':
// delete
case 'Y':
// delete
case 'n':
main();
case 'N':
main();
default:
puts("Please enter 'y' or 'n'.");
rmv_student(id);
}
}
}
if ( i == MAX ){
printf("\nThere are no students with ID %d.\n\n", id);
main();
}
}
I have two questions.
Are my switch cases correct? Will this test the user's input character correctly?
How do I go about deleting the struct?
Before you ask. Yes, this is homework. As such, I'm not looking for a handout, just a point in the right direction. Any other suggestions are welcome.
Note: I am aware that I don't really need the function 'menu_test_input', but I'm leaving it for now.
Use loops and return statements instead of recursive calling! Remember that when the called function returns the code will continue after the call.
Instead do something like the following pseudo-code
do
{
print_prompt()
get_response()
} while (response is not legal)
if (response is yes)
do_the_actual_deletion
If you want to remove element X of array A, then move the element X + 1 to X, move element X + 2 to X + 1, etc. When done then decrease the size by one. No actual "removing" involved.
There are two possible solutions to your problem, which one you should use depends on whether the order of the array elements is important to you.
The fast solution: Copy the last element in the array to the position of the element you want to delete, then simply decrement your count of elements in the array.
int* array = ...;
int elementCount = ...;
...
int deletionIndex = ...;
array[deletionIndex] = array[--elementCount]; //the deletion is actually a one liner :-)
This solution is the preferred one whenever you are operating with an unsorted array, it takes only a constant amount of time, regardless of where you do the deletion.
The long solution: Move all elements behind the deleted element one position to the front.
//setup is the same as for the fast solution
elementCount--;
for(int i = deletionIndex; i < elementCount; i++) array[i] = array[i+1];
Not exactly difficult, but considerably more complex than the fast solution.
You need to use this whenever you need to preserve the relative order of the array elements. The price for the ordering is that the runtime depends on the amount of elements that need to be moved.
you have to use break;
case 'y':
//your code
break;
case 'Y':
//your code
break;
case 'n':
break;
...
......
or the code will run all your cases.
proper use - http://www.tutorialspoint.com/cprogramming/switch_statement_in_c.htm

Counting the number of elements in an array - C

I am trying to count the number of elements in an array using C. I tried out the following code. But it just returns 83 every time I run the program. What I mean by to count the number of elements is that I need to know the number of elements that we have entered and not the size of the array.
#include<stdio.h>
#include<stdlib.h>
main(){
int a[100], j = 0, i;
a[0] = '0';
a[1] = '1';
a[2] = '2';
a[3] = '3';
a[4] = '4';
a[5] = '5';
for(i=0; i<100; i++){
if(a[i] == '\0'){
}
else
j = j + 1;
}
printf("%d", j);
system("pause");
}
Arrays in C are a fixed size. They do not expand. Your array has two entries; writing to array[2], array[3], etc. invokes undefined behaviour. In other words, it's invalid code.
If you want to be able to insert an arbitrary number of elements, you will need to use dynamically-allocated memory, manually track how many elements you've inserted, and use realloc when you need to resize.
Since the OP amended his code, here is a more correct reply:
This code works 'by chance', since you didn't initialize the array previously.
It's just 'luck', that somewhere in there, the value 0 comes up.
The declaration of an array does NOT zero it.
Use:
memset(a, 0, 100);
For that. That way, the first 'not overwritten' byte will return '0'.
Reference: http://www.cplusplus.com/reference/clibrary/cstring/memset/
Alternatively, you have to set the 'delimited' manually by adding a[x] = 0;
Now, I know you specifically asked for a 'C' solution, but if you would like to consider using a C++-Compiler, I suggest looking at the stl of C++.
Here's a link to get you started: http://www.cplusplus.com/reference/stl/list/
It's initialized as:
list<char>List;
List.push_back(1);
List.push_back(2);
List.push_back('a');
int j = List.size(); //Returns '3'
do this instead:
main(){
int a[100] = {0};
int j = 0;
int i = 0;
// other stuff
Update based on new code:
In general, you will need a way to identify the end of your array in order to do a correct count. For strings the '\0' is used generally. For other data types you have to come up with your own value to check.
For your specific code example above:
You need to insert a \0 yourself into your array in the last position so that your count will work. (When you create a string like "hello", the '\0' gets automatically put in for you at the end of the string, but not if you create a string character by character).
Alternatively, check for the character '5' to find the end of your current array of characters.
Also, you should break out of the loop once you found the last character, otherwise you are going past the end of the array and will most likely crash (again, if you don't it's sheer luck). I.e., something like:
if(a[i] == '\0'){
break;
}
will work if you do:
a[6] = '\0';
before.
Since C doesn't check array bounds, it might appear that with your current code you seemingly get away with this, but it's sheer luck that the program doesn't crash and may change from run to run. In other words, this is undefined behavior.
Finally, you can of course also use strlen() if you are dealing with strings.

Resources