Objective C char array mismatch - objective-c

I am having an issue getting the correct format of a char array in Objective C
Correct sample:
unsigned char bytes[] = {2, 49, 53, 49, 3, 54};
When printing to the debug area I get this:
Printing description of bytes:
(unsigned char [6]) bytes = "\x02151\x0365"
Incorrect sample:
I then attempt to populate an unsigned char array with characters manually (via a for-loop that produces the below samples):
unsigned char bb[64];
bb[0] = 2;
bb[1] = 49;
bb[2] = 52;
bb[3] = 49;
bb[4] = 3;
bb[5] = 54;
When printing to the debug area I get this:
Printing description of bb: (unsigned char [64]) bb = "\x02151\x036";
Also when expanding the array while debugging I can see xcode is telling me that the 'bytes' array has int values and the 'bb' array has characters such as '\x02' in it.
This is just a high level piece of code that does not do much yet, but I need to match the array named 'bytes' before being able to proceed.
Any ideas? Thanks

You don't:
state what kind (local, instance, etc.) of variables bytes and bb are and that makes a difference;
show your for loop; or
state what you mean by "printing"
so this answer is going to be a guess!
Try the following code (it's a "complete" Cocoa app):
#implementation AppDelegate
unsigned char bytes[] = {2, 49, 53, 49, 3, 54};
char randomBytes[] = { 0x35, 0x0 };
unsigned char bb[64];
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
for(int ix = 0; ix < 6; ix++) bb[ix] = bytes[ix];
// breakpoint here
}
#end
Now in the debugger, at least on my machine/compiler combination, this result is not guaranteed:
(lldb) p bytes
(unsigned char [6]) $0 = "\x02151\x0365"
(lldb) p bb
(unsigned char [64]) $1 = "\x02151\x036"
I think this reproduces your result. So what is going on?
The variable bytes is an array but as it is characters the debugger is choosing to interpret it as a C string when displaying it - note the double quotes around the value and the \x hex escapes for non-printable characters.
A C string terminates on a null (zero) byte so when the debugger interprets your array as a C string it will display characters until it finds a null byte and stops. It just so happens that on your machine the two bytes following your bytes array have the values 0x35 and 0x0; I have reproduced that here by adding the randomBytes array; and those values are the character 5 and the null byte so the debugger prints the 5.
So why does bb only print 6 characters? Global variables are zero initialised, so bb has 64 null bytes before the for loop. After the loop the 7th of those null bytes acts as the EOS (end of string) marker and the print just shows the 6 characters you expect.
Finally why do I say the above results are not guaranteed? The memory layout order of global variables is not specified as part of the C Standard, which underlies Objective-C, so there is in fact no guarantee that the randomBytes array immediately follows the bytes array. If the global variable layout algorithm is different on your computer/compiler combination you may not get the same results. However the underlying cause of your issue is the same - the "printing" is running off the end of your bytes array.
HTH

Related

sprintf doesn't seem to grab zeroth string

I have the following code:
#include <stdio.h>
int main(void) {
char list[3][7] = { "One", "Two", "Three"} ;
char item[7]; // originally I had posted "char item[3];" by mistake
int i;
for( i=0; i<2; i++ ) {
sprintf(item, "%-7s", list[i]);
printf( "%d %s", i, item );
}
printf("\n\r");
for( i=0; i<2; i++ ) {
sprintf(item, "%-7s", list[i]);
printf( "%d %s", i, item );
}
printf("\n\r");
return 0;
}
I expect the following output
0 One 1 Two
0 One 1 Two
However, instead I get:
0 One 1 Two
0 1 Two
Note the missing text "One" the second time it prints.
Can someone explain what's happening here?
Thanks!
With item declared as:
char item[7];
the code exposes undefined behaviour because sprintf(item, "%-7s") attempts to write at least 8 characters into item.
The documentation of sprintf() explains (the emphasis is mine):
Writes the results to a character string buffer. The behavior is undefined if the string to be written (plus the terminating null character) exceeds the size of the array pointed to by buffer.
-7 in the format string "%-7s" is interpreted as:
(optional) integer value or * that specifies minimum field width. The result is padded with space characters (by default), if required, on the left when right-justified, or on the right if left-justified. In the case when * is used, the width is specified by an additional argument of type int. If the value of the argument is negative, it results with the - flag specified and positive field width. (Note: This is the minimum width: The value is never truncated.)
In order to avoid the undefined behaviour, the size of item must be at least 8 but keep in mind that if the string to format is longer than 7 characters it is not truncated, the result becomes longer than 8 characters and it overflows item again.
Why you get the output you get?
The calls to sprintf(item, "%-7s", list[i]); in the first loop write 8 characters in a buffer of 7 characters. The extra character (which is \0) incidentally happens to overwrite the first character of list[0] changing it into an empty string. This is just one random behaviour, compiling the code with a different compiler or different compiling options could produce a different behaviour.
When you do the sprintf(item, "%-7s", list[i]); you are, essentially, copying the string from list[i] into your char array item.
So list[2] -> "three" is 5 chars plus the nul terminator, but item is only 3 chars long -- you are overflowing item and writing over some other memory, which could very well be part of list.
Change item to be char item[7] so it matches the length of 7 declared in your 2nd dimension in list[3][7]. When I did that I got your expected output.
(I used https://repl.it/languages/C to test)

How can I transfer data from unsigned char * to char * safely?

I am willing to transfer data from unsigned char hash[512 + 1] to char res[512 + 1] safely.
My C hashing library MHASH returns a result so it can be printed as listed below.
for (int i = 0; i < size /*hash block size*/; i++)
printf("%.2x", hash[i]); // which is unsigned char - it prints normal hash characters in range [a-z,0-9]
printf("\n");
I am willing to do something like that (see below).
const char* res = (const char *)hash; // "hash" to "res"
printf("%s\n", res); // print "res" (which is const char*) - if i do this, unknown characters are printed
I know the difference between char and unsigned char, but I don't know how to transfer data. Any answer would be greatly appreciated, thanks in advance. But please do not recommend me C++ (STD) code, I am working on a project that is not STD-linked.
Given that the contents of the unsigned char array are printable characters, you can always safely convert it to char. Either a hardcopy with memcpy or a pointer reference as in the code you have already written.
I'm guessing that the actual problem here is that the unsigned char array contents are not actually printable characters, but integers in some format. You'll have to convert them from integer to ASCII letters. How to do this depends on the format of the data, which isn't clear in your question.
Assuming the following:
#define ARR_SIZE (512 + 1)
unsigned char hash[ARR_SIZE];
char res[ARR_SIZE];
/* filling up hash here. */
Just do:
#include <string.h>
...
memcpy(res, hash, ARR_SIZE);
Well, thank you guys for your answers, but unfortunately nothing worked yet. I am now sticking with the code below.
char res[(sizeof(hash) * 2) + 1] = { '\0' };
char * pPtr = res;
for (int i = 0; i < hashBlockSize; i++)
sprintf(pPtr + (i * 2), "%.2x", hash[i]);
return (const char *)pPtr;
Until there is any other much more performant way to get this done. It's right, my question is strongly related to MHASH Library.

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");
...
}

Reading Binary File

so I am trying to read a filesystem disk, which has been provided.
So, what I want to do is read the 1044 byte from the filesystem. What I am currently doing is the following:
if (fp = fopen("filesysFile-full", "r")) {
fseek(fp, 1044, SEEK_SET); //Goes to 1024th byte
int check[sizeof(char)*4]; //creates a buffer array 4 bytes long
fread(check, 1, 4, fp); //reads 4 bytes from the file
printf("%d",check); //prints
int close = fclose(fp);
if (close == 0) {
printf("Closed");
}
}
The value that check should be printing is 1. However I am getting negative values which keep changing everytime I run the file. I don't understand what I am doing wrong. Am I taking the right approach to reading bytes of the disk, and printing them.
What I basically want to do is read bytes of the disk, and read the values at certain bytes. Those bytes are fields which will help me understand the structure/format of the disk.
Any help would be appreciated.
Thank you.
This line:
int check[sizeof(char)*4];
allocates an array of 4 ints.
The type of check is therefore int*, so this line:
printf("%d",check);
prints the address of the array.
What you should do it allocate it as an int:
int check;
and then fread into it:
fread(&check, 1, sizeof(int), fp);
(This code, incidentally, assumes that int is 4 bytes.)
int check[sizeof(char)*4]; //creates a buffer array 4 bytes long
This is incorrect. You are creating an array of four integers, which are typically 32 bits each, and then when you printf("%d",check) you are printing the address of that array, which will probably change every time you run the program. I think what you want is this:
if (fp = fopen("filesysFile-full", "r")) {
fseek(fp, 1044, SEEK_SET); //Goes to 1024th byte
int check; //creates a buffer array the size of one integer
fread(&check, 1, sizeof(int), fp); //reads an integer (presumably 1) from the file
printf("%d",check); //prints
int close = fclose(fp);
if (close == 0) {
printf("Closed");
}
}
Note that instead of declaring an array of integers, you are declaring just one. Also note the change from fread(check, ...) to fread(&check, ...). The first parameter to fread is the address of the buffer (in this case, a single integer) into which you want to read the data.
Keep in mind that while integers are probably 32 bits long, this isn't guaranteed. Also, in most operating systems, integers are stored with the least significant byte first on the disk, so you will only read 1 if the data on the disk looks like this at byte 1044:
0x01 0x00 0x00 0x00
If it is the other way around, 0x00 00 00 01, that will be read as 16777216 (0x01000000).
If you want to read more than one integer, you can use an array as follows:
if (fp = fopen("filesysFile-full", "r")) {
fseek(fp, 1044, SEEK_SET); //Goes to 1024th byte
int check[10]; //creates a buffer of ten integers
fread(check, 10, sizeof(int), fp); //reads 10 integers into the array
for (int i = 0; i < 10; i++)
printf("%d ", check[i]); //prints
int close = fclose(fp);
if (close == 0) {
printf("Closed");
}
}
In this case, check (without brackets) is a pointer to the array, which is why I've changed the fread back to fread(check, ...).
Hope this helps!

Objective c, Scanf() string taking in the same value twice

Hi all I am having a strange issue, when i use scanf to input data it repeats strings and saves them as one i am not sure why.
Please Help
/* Assment Label loop - Loops through the assment labels and inputs the percentage and the name for it. */
i = 0;
j = 0;
while (i < totalGradedItems)
{
scanf("%s%d", assLabel[i], &assPercent[i]);
i++;
}
/* Print Statement */
i = 0;
while (i < totalGradedItems)
{
printf("%s", assLabel[i]);
i++;
}
Input Data
Prog1 20
Quiz 20
Prog2 20
Mdtm 15
Final 25
Output Via Console
Prog1QuizQuizProg2MdtmMdtmFinal
Final diagnosis
You don't show your declarations...but you must be allocating just 5 characters for the strings:
When I adjust the enum MAX_ASSESSMENTLEN from 10 to 5 (see the code below) I get the output:
Prog1Quiz 20
Quiz 20
Prog2Mdtm 20
Mdtm 15
Final 25
You did not allow for the terminal null. And you didn't show us what was causing the bug! And the fact that you omitted newlines from the printout obscured the problem.
What's happening is that 'Prog1' is occupying all 5 bytes of the string you read in, and is writing a null at the 6th byte; then Quiz is being read in, starting at the sixth byte.
When printf() goes to read the string for 'Prog1', it stops at the first null, which is the one after the 'z' of 'Quiz', producing the output shown. Repeat for 'Prog2' and 'Mtdm'. If there was an entry after 'Final', it too would suffer. You are lucky that there are enough zero bytes around to prevent any monstrous overruns.
This is a basic buffer overflow (indeed, since the array is on the stack, it is a basic Stack Overflow); you are trying to squeeze 6 characters (Prog1 plus '\0') into a 5 byte space, and it simply does not work well.
Preliminary diagnosis
First, print newlines after your data.
Second, check that scanf() is not returning errors - it probably isn't, but neither you nor we can tell for sure.
Third, are you sure that the data file contains what you say? Plausibly, it contains a pair of 'Quiz' and a pair of 'Mtdm' lines.
Your variable j is unused, incidentally.
You would probably be better off having the input loop run until you are either out of space in the receiving arrays or you get a read failure. However, the code worked for me when dressed up slightly:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char assLabel[10][10];
int assPercent[10];
int i = 0;
int totalGradedItems = 5;
while (i < totalGradedItems)
{
if (scanf("%9s%d", assLabel[i], &assPercent[i]) != 2)
{
fprintf(stderr, "Error reading\n");
exit(1);
}
i++;
}
/* Print Statement */
i = 0;
while (i < totalGradedItems)
{
printf("%-9s %3d\n", assLabel[i], assPercent[i]);
i++;
}
return 0;
}
For the quoted input data, the output results are:
Prog1 20
Quiz 20
Prog2 20
Mdtm 15
Final 25
I prefer this version, though:
#include <stdio.h>
enum { MAX_GRADES = 10 };
enum { MAX_ASSESSMENTLEN = 10 };
int main(void)
{
char assLabel[MAX_GRADES][MAX_ASSESSMENTLEN];
int assPercent[MAX_GRADES];
int i = 0;
int totalGradedItems;
for (i = 0; i < MAX_GRADES; i++)
{
if (scanf("%9s%d", assLabel[i], &assPercent[i]) != 2)
break;
}
totalGradedItems = i;
for (i = 0; i < totalGradedItems; i++)
printf("%-9s %3d\n", assLabel[i], assPercent[i]);
return 0;
}
Of course, if I'd set up the scanf() format string 'properly' (meaning safely) so as to limit the length of the assessment names to fit into the space allocated, then the loop would stop reading on the second attempt:
...
char format[10];
...
snprintf(format, sizeof(format), "%%%ds%%d", MAX_ASSESSMENTLEN-1);
...
if (scanf(format, assLabel[i], &assPercent[i]) != 2)
With MAX_ASSESSMENTLEN at 5, the snprintf() generates the format string "%4s%d". The code compiled reads:
Prog 1
and stops. The '1' comes from the 5th character of 'Prog1'; the next assessment name is '20', and then the conversion of 'Quiz' into a number fails, causing the input loop to stop (because only one of two expected items was converted).
Despite the nuisance value, if you want to make your scanf() strings adjust to the size of the data variables it is reading into, you have to do something akin to what I did here - format the string using the correct size values.
i guess, you need to put a
scanf("%s%d", assLabel[i], &assPercent[i]);
space between %s and %d here.
And it is not saving as one. You need to put newline or atlease a space after %s on print to see difference.
add:
when i tried
#include <stdio.h>
int main (int argc, const char * argv[])
{
char a[1][2];
for(int i =0;i<3;i++)
scanf("%s",a[i]);
for(int i =0;i<3;i++)
printf("%s",a[i]);
return 0;
}
with inputs
123456
qwerty
sdfgh
output is:
12qwsdfghqwsdfghsdfgh
that proves that, the size of string array need to be bigger then decleared there.