Checking the length of an array of characters in Objective-C - ios

I'm translating a small Java library for using in an Objective-C application I'm writing.
char[] chars = sentence.toCharArray();
int i = 0;
while (i < chars.length) { ... }
Where sentence is an NSString.
I'd like to translate the above Java code to Objective-C. Here's what I have so far:
// trims sentence off white space
sentence = [sentence stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
const char *chars = [sentence UTF8String];
How do I the above while condition? I'm not sure of how I'm supposed to check the length of the the string after it was converted to a character array.

Your Objective-C string already holds a measure of its length, it's just a matter of retrieving it:
// trims sentence off white space
sentence = [sentence stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSUInteger length = sentence.length;
const char *chars = [sentence UTF8String];
But I would like to remember that even if you didn't know the length, you could use the C strlen function:
// trims sentence off white space
sentence = [sentence stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
const char *chars = [sentence UTF8String];
size_t length = strlen(chars);

Even there is already an accepted answer I want to warn of using strlen(), even in this case it might be without any problem. There are a differences between NSString and C-Strings.
A. -length (NSString) and strlen() has different semantics:
NSString is not(!) \0-terminated, but length based. It can store \0 characters. It is very easy to get different length, if there is a \0 character in the string instance:
NSString *sentence = #"Amin\0Negm";
NSLog( #"length %ld", [sentence length]); // 9
const char *chars = [sentence cStringUsingEncoding:NSUTF8StringEncoding];
size_t length= strlen(chars);
NSLog(#"strlen %ld", (long)length); // 4
length 9
strlen 4
But -UTF8String and even the used -cStringUsingEnocding: (both NSString) copy out the whole string stored in the string instance. (I think in case of -cStringUsingEncoding it is misleading, because standard string functions like strlen() always uses the first \0 as the termination of strings.)
B. In UTF8 a character can have multibytes. A char in C is one byte. (With byte not in the meaning of 8 bits, but smallest addressable unit.)
NSString *sentence = #"Αmin Negm";
NSLog( #"length %ld", [sentence length]);
const char *chars = [sentence UTF8String];
size_t length= strlen(chars);
NSLog(#"strlen %ld", (long)length);
length 9
strlen 10
WTF happened here? The "A" of Amin is no latin capital letter A but a greek capital letter Alpha. In UTF8 this takes two bytes and for pure C's strlen there are two characters!
NSLog(#"%x-%x %x-%x", 'A', 'm', (unsigned char)*chars, (unsigned char)*(chars+1) );
41-6d ce-91
The first two numbers are the codes for 'A', 'm', the second two numbers are the UTF8 code for greek capital letter Alpha (CE 91).
I do not think, that it is a good idea to simply change from NSString to char * without good reason and a complete understanding of the problems. If you do not expect such characters, use NSASCIIStringEncoding. If you expect such characters check your code again and again … or read C.
C. C supports wide characters. This is similiar to Mac OS' unichar, but typed wchar_t. There are string functions for wchar_t in wchar.h.
NSString *sentence = #"Αmin Negm";
NSLog( #"length %ld", [sentence length]);
wchar_t wchars[128]; // take care of the size
wchar_t *wchar = wchars;
for (NSUInteger index = 0; index < [sentence length]; index++)
{
*wchar++ = [sentence characterAtIndex:index];
}
*wchar = '\0';
NSLog(#"widestrlen %ld", wcslen(wchars));
length 9
widestrlen 9
D. Obviously you want to iterate through the string. The common pattern in pure C is not to use an index and to compare it to the length and definitly not to to strlen() in every loop, because it produces high costs. (C strings are not length based so the whole string has to be scanned over and over.) You simply increment the pointer to the next char:
char letter;
while ( (letter = *chars++) ) {…}
or
do
{
// *chars points to the actual char
} while (*char++);

int lenght = sizeof(chars) / sizeof(char)
might work, but it will (inte the best case) return same thing as
sentence.lenght
in worst case 0 because the whole pointer / sizeof thing i don't remember now

Related

NSString to char* with greek characters

I am using the following code to store the data of a string in a char*.
NSString *hotelName = [components[2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
hotelInfo->hotelName = malloc(sizeof(char) * hotelName.length + 1);
strncpy(hotelInfo->hotelName, [hotelName UTF8String], hotelName.length + 1);
NSLog(#"HOTEL NAME: %s",hotelInfo->hotelName);
The problem is with the Greek characters that are printed strangely. I have also tried to use another encoding (e.g NSWindowsCP1253StringEncoding -it crashes- )
I tried even that:
hotelInfo->hotelName = (const char *)[hotelName cStringUsingEncoding:NSUnicodeStringEncoding];
but it also produces strange characters.
What do I miss?
EDIT:
After some suggestions I tried the following:
if ([hotelName canBeConvertedToEncoding:NSWindowsCP1253StringEncoding]){
const char *cHotelName = (const char *)[hotelName cStringUsingEncoding:NSWindowsCP1253StringEncoding];
int bufSize = strlen(cHotelName) + 1;
if (bufSize >0 ){
hotelInfo->hotelName = malloc(sizeof(char) * bufSize);
strncpy(hotelInfo->hotelName, [hotelName UTF8String], bufSize);
NSLog(#"HOTEL NAME: %s",hotelInfo->hotelName);
}
}else{
NSLog(#"String cannot be encoded! Sorry! %#",hotelName);
for (NSInteger charIdx=0; charIdx<hotelName.length; charIdx++){
// Do something with character at index charIdx, for example:
char x[hotelName.length];
NSLog(#"%C", [hotelName characterAtIndex:charIdx]);
x[charIdx] = [hotelName characterAtIndex:charIdx];
NSLog(#"%s", x);
if (charIdx == hotelName.length - 1)
hotelInfo->hotelName = x;
}
NSLog(#"HOTEL NAME: %s",hotelInfo->hotelName);
}
But still nothing!
First of all, it is not guaranteed that any NSString can be represented as a C character array (so-called C-String). The reason is that there is just a limited set of characters available. You should check if the string can be converted (by calling canBeConvertedToEncoding:).
Secondly, when using the malloc and strncpy functions, they rely on the length of the C-String, not on the length of the NSString. So you should first get the C-String from the NSString, then get it's length (strlen), and use this value to the function calls:
const char *cHotelName = (const char *)[hotelName cStringUsingEncoding:NSWindowsCP1253StringEncoding];
int bufSize = strlen(cHotelName) + 1;
hotelInfo->hotelName = malloc(sizeof(char) * bufSize);
strncpy(hotelInfo->hotelName, cHotelName, bufSize);

Sending int data to BLE device

I have 4 distinct int values that I need to send to a BLE device (connection established OK).
I'll call the int values A,B,C,D for clarity. A and B range between 0-100, C has a range of 0-2000 and D has a range of 0-10000. All values are determined by user input.
I need to send these four values to the BLE device in quick succession, and package each of them differently: A and B (8 bits), C (16 bits) and D (32 bits). I'm unsure as to how to package the values correctly.
Below are three methods I've tried with varying degrees of success.
Convert int to data and send, e.g. for A (8 bit) int:
const unsigned char CHR = (float)A;
float size = sizeof(CHR);
NSData * aData = [NSData dataWithBytes:&CHR length:size];
[p writeValue:aData forCharacteristic:aCHAR type:CBCharacteristicWriteWithResponse];
Convert to string first, e.g. for (16 bit) C:
NSString * cString = [NSString stringWithFormat:#"%i",C];
NSData * cData = [cString dataUsingEncoding:NSUTF16StringEncoding];
[p writeValue:cData forCharacteristic:cCHAR type:CBCharacteristicWriteWithResponse];
Use uint, e.g. for (32 bit) D int:
uint32_t val = D;
float size = sizeof(val);
NSData * dData = [NSData dataWithBytes:(void*)&val length:size];
[p writeValue:valData forCharacteristic:dCHAR type:CBCharacteristicWriteWithResponse];
What am I doing wrong in the above, and how best to convert and send an int value to the device, allowing for the 3 formats required?
You need to know a little more information about the format your device expects:
Are the values signed or unsigned
Is the system little-endian or big-endian
Assuming that you want to use the little-endian format that iOS uses, you can just use dataWithBytes -
unsigned char a = 100
NSData *aData = [NSData dataWithBytes:&a length:sizeof(i)];
UInt16 c = 1000
NSData *cData = [NSData dataWithBytes:&c length:sizeof(c)];
Unit32 d = 10000
NSData *dData = [NSData dataWithBytes:&d length:sizeof(d)];
And then just write the NSData using writeValue:forCharacteristic:type:
If the device wants big-endian data then you will need to manipulate the bytes into the proper order. For this reason it is often easier just to send numeric values as ASCII strings and convert them back to numeric values on the receiving end, but this will depend on whether you have control over the format the device is expecting.

How to convert char(or Byte) with hexadecimal data in it, to an integer(decimal value)

I have
char tem;
Its value is shown as blow:
Printing description of tem:
(char) tem = '\xd1'
which should equals to 209 in decimal.
My question is how can I implement this conversion programmatically? That is I want to get a NSInteger that equals 209 in this case.
Maybe there’s something I’m overlooking here, but given that both char and NSInteger are integral types, can’t you just do
char tem = '\xd1';
NSInteger i = tem;
? Or perhaps, to avoid surprises from sign extension,
NSInteger i = tem & 0xff;
A char variable actually is a 8-bit integer. You don't have to convert it to a NSInteger to get its decimal value. Just explicitly tell the compiler to interpret it as an unsigned 8-bit integer, uint8_t:
char theChar = '\xd1';
NSLog(#"decimal: %d", (uint8_t)theChar); //prints 'decimal: 209'
To convert it to a NSInteger:
NSInteger decimal = (uint8_t)theChar;
If yours char in ANSCII, do this:
char a = '3';//example char
int i = (int)(a - '0');

adler32 checksum in objective c [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I am working on a app which sends data to server with user location info. Server accept this data based on checksum calculation, which is written in java.
Here is the code written in Java:
private static final String CHECKSUM_CONS = "1217278743473774374";
private static String createChecksum(double lat, double lon) {
int latLon = (int) ((lat + lon) * 1E6);
String checkSumStr = CHECKSUM_CONS + latLon;
byte buffer[] = checkSumStr.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
CheckedInputStream cis = new CheckedInputStream(bais, new Adler32());
byte readBuffer[] = new byte[50];
long value = 0;
try {
while (cis.read(readBuffer) >= 0) {
value = cis.getChecksum().getValue();
}
} catch (Exception e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
return String.valueOf(value);
}
I tried looking for help to find out how to write objective c equivalent of this. Above function uses adler32 and I don't have any clue about that. Please help.
Thanks for your time.
The answers shown here by #achievelimitless and #user3275097 are incorrect.
First off, signed integers should not be used. The modulo operator on negative numbers is defined differently in different languages, and should be avoided when possible. Simply use unsigned integers instead.
Second, the loops will quickly overflow the 16-bit accumulators, which will give the wrong answer. The modulo operations can be deferred, but they must be done before overflow. You can calculate how many loops you can do safely by assuming that all of the input bytes are 255.
Third, because of the second point, you should not use 16-bit types. You should use at least 32-bit types to avoid having to do the modulo operation very often. You still need to limit the number of loops, but the number gets much bigger. For 32-bit unsigned types, the maximum number of loops is 5552. So the basic code looks like:
#define MOD 65521
#define MAX 5552
unsigned long adler32(unsigned char *buf, size_t len)
{
unsigned long a = 1, b = 0;
size_t n;
while (len) {
n = len > MAX ? MAX : len;
len -= n;
do {
a += *buf++;
b += a;
} while (--n);
a %= MOD;
b %= MOD;
}
return a | (b << 16);
}
As noted by #Sulthan, you should simply use the adler32() function provided in zlib, which is already there on Mac OS X and iOS.
On basis of definition of adler32 checksum as mentioned in wikipedia,
Objective C implementation would be like this:
static NSNumber * adlerChecksumof(NSString *str)
{
NSMutableData *data= [[NSMutableData alloc]init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
for (int i = 0; i < ([str length] / 2); i++)
{
byte_chars[0] = [str characterAtIndex:i*2];
byte_chars[1] = [str characterAtIndex:i*2+1];
whole_byte = strtol(byte_chars, NULL, 16);
[data appendBytes:&whole_byte length:1];
}
int16_t a=1;
int16_t b=0;
Byte * dataBytes= (Byte *)[data bytes];
for (int i=0; i<[data length]; i++)
{
a+= dataBytes[i];
b+=a;
}
a%= 65521;
b%= 65521;
int32_t adlerChecksum= b*65536+a;
return #(adlerChecksum);
}
Here str would be your string as mentioned in your question..
So when you want to calculate checksum of some string just do this:
NSNumber * calculatedChkSm= adlerChecksumof(#"1217278743473774374");
Please Let me know if more info needed

Appending binary string to NSMutableData

How would I go about appending this binary string
111000111000111111000111000111
to an NSMutableData object that contains a png
(NSMutableData *dataForPNGFile = UIImagePNGRepresentation(p.Image);)
You'd need to parse the string into an NSData, then append that.
I'm not aware of anything built in, so e.g.
NSMutableData *data = [NSMutableData dataWithLength(string.length+7)/8];
uint8_t *mutableBytes = (uint8_t *)data.mutableBytes;
for(NSUinteger index = 0; index < string.length; index++)
{
unichar character = [string characterAtIndex:index];
mutableBytes[index >> 3] <<= 1;
if(character == '1') mutableBytes[index >> 3] |= 1;
}
if(string.length&7)
mutableBytes[string.length >> 3] <<= (7 - (string.length&7));
So assumptions are that your source string is only 1s and 0s, that it's written from most significant to least significant digit and that it's byte rather than word oriented.
Also, UIImagePNGRepresentation returns immutable data so you'll need to take a mutable copy of that.
Look at the NSMuteableData method appendBytes:length:
You will have to convert your bits to bytes as #Tommy says.

Resources