EXC_BAD_ACCESS when reading 9 characters, but works with less than 9 - objective-c

I'm developing a console app in Objective-C. I've got it working, but when manually testing edge cases, I found a strange behavior that I can't explain.
Basically, I've set up scanf() in a loop, and when the user types invalid info, it prints an "invalid option" message. Then, if the input is less than 9 characters long, it goes through the loop again as intended. But, if the input is 9 characters or longer, it gives a EXC_BAD_ACCESS error on a certain line.(This error doesn't happen if I comment out said line.)I can't figure out any reason why 8 vs 9 characters being read would cause this error. Any ideas?
Below are the two methods that I figure are relevant, with a comment on the line throwing the error. If you think other referenced code may be causing this, let me know and I'll add that code.
-(void)startMenu {
printf("\nGAME OPTIONS\n| WinningScore = %d (w) | Name = %s (n) | Back (b) |\n",
_options.winningScore, [_options.name UTF8String]);
}
-(void)start {
char selectedOption;
char w = 'w';
char n = 'n';
char b = 'b';
while(YES) {
[self startMenu]; // This line gets the EXC_BAD_ACCESS error
// if the user puts in 9 or more characters.
// If it is commented out, then no error is thrown.
scanf("%s", &selectedOption);
if(selectedOption == w) {
[self setWinningScore];
} else if(selectedOption == n) {
[self setName];
} else if(selectedOption == b) {
break;
} else {
printf("'%s' is not a valid option.\n", &selectedOption);
}
}
}

It this was C (and the post is tagged C) I'd suggest:
char selectedOption;
....
scanf(" %c", &selectedOption);
...
printf("'%c' is not a valid option.\n", selectedOption);
The failure showing up after a 9 charterer input is serendipity. scanf("%s", &selectedOption); is certainly wrong for reading a single character. Any input starts causing problems. Use the matching format specifier and variable.
[Edit]
A C-like solution.
If more than 1 char is desire for input, use the idea put forth by #Devolus. Example:
char selectedOption[10];
if (fgets(selectedOption, sizeof selectedOption, stdin) == NULL)
Handle_EOForIOerror();
// Get rid of potential trailing \n if desired.
size_t len = strlen(selectedOption);
if (len > 0 && selectedOption[len-1] == '\n') selectedOption[--len] = '\0';

You should use fgets instead of scanf here, as you can limit the number of characters in the buffer.
scanf is potentially unsafe because the buffer can be exceeded.

Related

Stange behavior with my C string reverse function

I'm just an amateur programmer...
And when reading, for the second time, and more than two years apart, kochan's "Programming in Objective-C", now the 6th ed., reaching the pointer chapter i tried to revive the old days when i started programming with C...
So, i tried to program a reverse C string function, using char pointers...
At the end i got the desired result, but... got also a very strange behavior, i cannot explain with my little programming experience...
First the code:
This is a .m file,
#import <Foundation/Foundation.h>
#import "*pathToFolder*/NSPrint.m"
int main(int argc, char const *argv[])
{
#autoreleasepool
{
char * reverseString(char * str);
char *ch;
if (argc < 2)
{
NSPrint(#"No word typed in the command line!");
return 1;
}
NSPrint(#"Reversing arguments:");
for (int i = 1; argv[i]; i++)
{
ch = reverseString(argv[i]);
printf("%s\n", ch);
//NSPrint(#"%s - %s", argv[i], ch);
}
}
return 0;
}
char * reverseString(char * str)
{
int size = 0;
for ( ; *(str + size) != '\0'; size++) ;
//printf("Size: %i\n", size);
char result[size + 1];
int i = 0;
for (size-- ; size >= 0; size--, i++)
{
result[i] = *(str + size);
//printf("%c, %c\n", result[i], *(str + size));
}
result[i] = '\0';
//printf("result location: %lu\n", result);
//printf("%s\n", result);
return result;
}
Second some notes:
This code is compiled in a MacBook Pro, with MAC OS X Maverick, with CLANG (clang -fobjc-arc $file_name -o $file_name_base)
That NSPrint is just a wrapper for printf to print a NSString constructed with stringWithFormat:arguments:
And third the strange behavior:
If I uncomment all those commented printf declarations, everything work just fine, i.e., all printf functions print what they have to print, including the last printf inside main function.
If I uncomment one, and just one, randomly chosen, of those comment printf functions, again everything work just fine, and I got the correct printf results, including the last printf inside main function.
If I leave all those commented printf functions as they are, I GOT ONLY BLANK LINES with the last printf inside main block, and one black line for each argument passed...
Worst, if I use that NSPrint function inside main, instead of the printf one, I get the desired result :!
Can anyone bring some light here please :)
You're returning a local array, that goes out of scope as the function exits. Dereferencing that memory causes undefined behavior.
You are returning a pointer to a local variable of the function that was called. When that function returns, the memory for the local variable becomes invalid, and the pointer returned is rubbish.

Flush stdin using fgets

Trying to make a registration page through the console.
I need several inputs for it, and I'm using fgets, so I need to flush stdin.
Lots of similar questions on Stack Overflow redirected here: http://c-faq.com/stdio/stdinflush2.html.
I got the code below using that link. However, this doesn't actually work. It says Username:, and then when I type in a username, and press enter, it just goes to a new, empty line in console where I can type in more.
Why is this happening?
How can I fix it?
EDIT: Added code
NSLog(#"Do you have an account already?(1 for Yes, 0 for no)");
fgets(cnumb1, 2, stdin);
int c;
while((c = getchar()) != '\n' && c != EOF);
size_t length = strlen(cnumb1);
if (cnumb1 [length-1] == '\n'){ // In case that the input string has 1 character plus '\n'
cnumb1 [length-1] = '\0';} // Plus '\0', the '\n' isn't added and the if condition is false.
NSString* string = [NSString stringWithUTF8String: cnumb1];
if (string == 0) {
while(numb4 == 1) {
numb3 = 1;
while( numb3 == 1){
NSLog(#"Username:");
fgets(usercheck1, 13, stdin);
int c2;
while((c2 = getchar()) != '\n' && c2 != EOF);
size_t length1 = strlen(usercheck1);
if (usercheck1 [length1-1] == '\n'){ // In case that the input string has 12 characters plus '\n'
usercheck1 [length1-1] = '\0';} // Plus '\0', the '\n' isn't added and the if condition is false.
Completely rewrote my answer, looks like I didn't understand the problem well enough.
The line that is supposed to empty the input buffer will not get anything until the user presses return again - unless the user enters more characters than the input buffer can hold.
You should first check the length of string read by fgets and if the last character (before the \0) is a \n, don't try to read more characters. Otherwise empty the input buffer like you did.

EXC_BAD_ACCESS in attempt to rewrite NSString ComponentsSeparatedByString:

I'm writing an objective-C program to deal with trajectories of Biomolecules with XCODE 4.3.1 and ARC. I need to read PDB files, i.e. parse large quantities of text formatted data. I'm very disappointed by NSString inefficiency and was trying to write a C-equivalent of componentsSeparatedByString:. The algorithm works just fine with NSString and NSMutableArrays, but i'm having a hard time using char* and char**.
Unfortunately, I'm getting an EXC_BAD_ACCESS error. The strange thing is that i get the error for i=68103 and j=68049 (does these number ring a bell for you ?), which means it worked for some time before crashing. The error is "static" (always block at the same (i,j) numbers). The array seems to work just fine(NSLog on its values before crash).
As it seems, I'm not very experienced with C-code and the subtlety behind pointers, but I would definitely be glad to hear your suggestions to make it work ! Thanks !
Heres the code :
+(char**) componentsSeparedByNewLineCEQUIV:(const char*)aChar:(int*)numWord
{ // char* aChar : my file, is typically 3 millions characters
int j=-1; //Last non space character
int i; //Scanned character
int len=strlen(aChar);
char** stringArray=malloc((*numWord)*sizeof(char*));
for (i=0;i<len; i++)
{ if (aChar[i]==10)
{
if ( j!=-1)
{
char* buffer2=malloc(i-j+1);
strcpy(buffer2, strndup(aChar+j, i-j));
stringArray[i]=malloc(sizeof(char)*strlen(buffer2)+1); //EXC_BAD_ACCESS HERE
strcpy(stringArray[i], buffer2);
}
j=-1;
}
else if (j==-1)
{j=i;}
}
if (j!=-1)
{ char* buffer2=malloc(i-j+1);
strcpy(buffer2, strndup(aChar+j, i-j));
stringArray[i]=malloc(strlen(buffer2)+1);
strcpy(stringArray[i], buffer2);
}
return stringArray;
}
You're probably not the first person to have this problem :)
Why not just use strtok?
PS What analysis showed that NSString was your problem?
I don't know why the error is at the line above of where it should be.However you are copying a string that is not allocated.
stringArray[i] is not allocated when you copy on it buffer2, allocate it:
if ( j!=-1)
{
char* buffer2=malloc(i-j+1);
strcpy(buffer2, strndup(aChar+j, i-j));
stringArray[i]=malloc(sizeof(char)*strlen(buffer2)+1); //EXC_BAD_ACCESS HERE
stringArray[i]=(char*)malloc( (strlen(buffer2)+1)*sizeof(char)); // Allocate the string
strcpy(stringArray[i], buffer2);
}
First: if Im not totaly wrong, but i think you are consuming at least 4-times as much memory as you need to:
You are using malloc for creating buffer2 and also using strndup for getting the wanted chars. strndup does exactly what you want, but in one step. char* buffer2 = strndup(aChar+j, i-j) should be your first step. Even worse in the next two line you are essential doing the same again. So i think what you are really want is stringArray[i] = strndup(aChar+j, i-j). To look at memory Problems: all the functions use errno to indicate memory allocating failure.
Second: Your functions does not return the number of components, so your stringArray may contain some garbage without knowing.
Third: strlen is expensive and you do not need it, just use for(int i = 0; aChar[i] != '\0'; i++)
Update for everyone who might be interested : this is a working version, using strtok which can be useful, although i'm still interested in response on my code.
This code have been tested 5 times faster (125ms vs 581ms) than [astring componentsSeparatedByString:#"\n"] ...
+(char**)componentsSeparatedByNewLine:(const char*)aChar:(int*)numWord
{
int i;
int j=0;
int len = strlen(aChar);
*numWord=1;
for (i=0;i<len; i++)
{
if (aChar[i]==10) *numWord=*numWord+1; //change 10 for any other character (ASCII for space)
}
char** stringArray=malloc((*numWord)*sizeof(char*));
char* pch;
char* aChar2=malloc(len+1);
strcpy(aChar2,aChar);
pch = strtok(aChar2,"\n");
while (pch != NULL)
{
stringArray[j]=(char*)malloc( (strlen(pch)+1)*sizeof(char));
strcpy(stringArray[j], pch);
//NSLog(#"%s",stringArray[j]);
j=j+1;
pch = strtok (NULL, "\n");
}
return stringArray;
}

scanf is not waiting for input within my loop?

I'm new to Objective-C, and this is really my first program that is interactive. I've been learning for about 2 weeks now.
So, my question is: typically I've noticed when you have multiple scanf's in a row, they each wait for input - however in this situation, where I ask for account owner name, and balance - it fires both NSLog functions instead of waiting for the first input.
Here is my main:
int main(int argc, char* argV[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
bank *columbiaBank = [[bank alloc] init];
int iteration = 0;
while (true) {
int selection = 0;
NSLog(#"\n1. Add Account \n2. Remove Account \n3. Modify Account \nWhat would you like to do?:");
scanf("%i", &selection);
if (selection == 1) {
NSLog(#"\nEnter account owner:");
char accountOwner;
scanf("%c", &accountOwner);
NSLog(#"\nEnter opening balance:");
float openingBalance;
scanf("%f", &openingBalance);
// create and add new account
bankAccount *newAccount = [[bankAccount alloc] initWithProps:[NSString stringWithFormat:#"%c", accountOwner] :[NSString stringWithFormat:#"%i", iteration] :openingBalance];
[columbiaBank addAccount:newAccount];
[newAccount release];
NSLog(#"\nAccount successfully added!");
} else if (selection == 2) {
NSLog(#"\nEnter account id:");
int accountId;
scanf("%i", &accountId);
// remove account
[columbiaBank removeAccount:[NSString stringWithFormat:#"%i", accountId]];
NSLog(#"\nAccount successfully removed!");
} else if (selection == 3) {
NSLog(#"\nThe bank currently has %i accounts.", columbiaBank.totalAccounts);
NSLog(#"\nThe bank's current balance from all accounts is $%f", columbiaBank.totalBankBalance);
NSLog(#"\n-- Output of all account info --");
[columbiaBank printAccounts];
} else {
NSLog(#"You did not enter a valid action.");
}
iteration++;
}
[columbiaBank release];
[pool drain];
return false;
}
Other users already said everything about it. The scanf inserts a new line "\n" automatically in the buffer that is passed to the next scanf. This is because any unwritten data is written in the next stream.
I want to add that you can use fflush to clear the stream buffer, in this case you want to use
scanf("%i", &selection);
fflush(stdin)
to clear the buffer of stdin (the console input) after every scanf.
Edit: I didn't know that, but As #Peter Kowalski said the use of fflush(stdin), for input stream, should be avoided because it has an undefined behaviour for input streams.
Cprograming.com FAQ > Why fflush(stdin) is wrong.
But it seems that there is not a guaranteed method to flush the input stream in C.
Cprograming.com FAQ > Flush the input stream
I know that in C++ a standard way is to use cin.ignore() after cin >> selection but I don't know how this can be done in C. Maybe some more experienced user can give some insight on what is happening with fflush(stdin).
*[Note: If you are going to use Objective-C you might wish to use input conversion methods from Cocoa rather than mix Cocoa (NSLog) and stdio (scanf). But that doesn't answer your question...]
When parsing integers, floats and even strings scanf skips whitespace - e.g. spaces, tabs, end of line, etc. - and every input line ends with at least an end of line (which may be a carriage return, line feed, or both depending on the system). This means that after reading your first integer there is still, at least, an end of line in the input and the attempt to read a character will return it - hence no wait for input. To discard the remaining, unused, input you can use fpurge. E.g.:
#include <stdio.h>
int main(int argc, char* argV[])
{
int selection = 0;
fputs("\n1. Add Account \n2. Remove Account \n3. Modify Account \nWhat would you like to do?: ", stdout);
scanf("%i", &selection);
if (selection == 1)
{
fputs("\nEnter account owner: ", stdout);
fpurge(stdin); // skip any input left in the buffer as %c takes the very next character and does not skip whitespace
char accountOwner;
scanf("%c", &accountOwner);
fputs("\nEnter opening balance: ", stdout);
float openingBalance;
scanf("%f", &openingBalance);
printf("%c - %f\n", accountOwner, openingBalance);
}
}
Note that reading in character strings does skip whitespace, so if your account owner was a string you would not need the fpurge.
Presumably you want the account owner name to be more than a single character, but you're only reading a single character in that scanf. If you're trying to enter more than a single character there, the first scanf will read the first character, and since there's more in the input buffer, the next scanf will try to read immediately without waiting for your numeric input. If you are only using a single character for the owner name, then you'll need to consume the newline from the input buffer.
If you want to read a string as the account owner name, you'll need to allocate space for more than one character, and use %s rather than %c as your scanf format string. Also remember to check the return value for scanf. The function will return the number of items successfully scanned, or 0 if no items were scanned, typically due to invalid input, or return EOF.
char accountOwner[26];
// ...
// note that you can specify a width (max length) for a string using scanf
scanfReturn = scanf("%25s", accountOwner);

printf(), fprintf(), wprintf() and NSlog() won't print on XCode

I'm doing a small app for evaluating and analyzing transfer functions. As boring as the subject might seem to some, I want it to at least look extra cool and pro and awesome etc... So:
Step 1: Gimme teh coefficients! [A bunch of numbers]
Step 2: I'll write the polynomial with its superscripts. [The bunch of numbers in a string]
So, I write a little C parser to just print the polynomial with a decent format, for that I require a wchar_t string that I concatenate on the fly. After the string is complete I quickly try printing it on the console to check everything is ok and keep going. Easy right? Welp, I ain't that lucky...
wchar_t *polynomial_description( double *polyArray, char size, char var ){
wchar_t *descriptionString, temp[100];
int len, counter = 0;
SUPERSCRIPT superscript;
descriptionString = (wchar_t *) malloc(sizeof(wchar_t) * 2);
descriptionString[0] = '\0';
while( counter < size ){
superscript = polynomial_utilities_superscript( size - counter );
len = swprintf(temp, 100, L"%2.2f%c%c +", polyArray[counter], var, superscript);
printf("temp size: %d\n", len);
descriptionString = (wchar_t *) realloc(descriptionString, sizeof(wchar_t) * (wcslen(descriptionString) + len + 1) );
wcscat(descriptionString, temp);
counter++;
}
//fflush(stdout); //Already tried this
len = wprintf(L"%ls\n", descriptionString);
len = printf("%ls**\n", descriptionString);
len = fprintf(stdout, "%ls*\n", descriptionString);
len = printf("FFS!! Print something!");
return descriptionString;
}
During the run we can see temp size: 8 printed the expected number of times ONLY WHILE DEBUGGING, if I run the program I get an arbitrary number of prints each run. But after that, as the title states, wprintf, printf and fprintf don't print anything, yet len does change its size after each call.
In the caller function, (application:(UIApplication *)application didFinishLaunchingWithOptions:, while testing) I put an NSLog to print the return string, and I dont get ANYTHING not even the Log part.
What's happening? I'm at a complete loss.
Im on XCode 4.2 by the way.
What's the return value from printf/wprintf in the case where you think it's not printing anything? It should be returning either -1 in the case of a failure or 1 or more, since if successful, it should always print at least the newline character after the description string.
If it's returning 1 or more, is the newline getting printed? Have you tried piping the output of your program to a hex dumper such as hexdump -C or xxd(1)?
If it's returning -1, what is the value of errno?
If it turns out that printf is failing with the error EILSEQ, then what's quite likely happening is that your string contains some non-ASCII characters in it, since those cause wcstombs(3) to fail in the default C locale. In that case, the solution is to use setlocale(3) to switch into a UTF-8 locale when your program starts up:
int main(int argc, char **argv)
{
// Run "locale -a" in the Terminal to get a list of all valid locales
setlocale(LC_ALL, "en_US.UTF-8");
...
}