How to reverse a string without allocating memory - iphone

I was asked this question on how to reverse a string without allocating memory. Any takers?

You cannot reverse an NSString, with or without allocating memory, because an NSString is immutable.
You cannot reverse an NSMutableString in place without allocating memory, because the only methods that NSMutableString provides to replace its contents require the new characters to be specified in an NSString, which you would have to allocate.
CFMutableString has the same “problem”.

void reverseStringBetter(char* str)
{
int i, j;
i=j=0;
j=strlen(str)1;
for (i=0; i<j; i++, j-)
{
str[i] ^= str[j] ;
str[j] ^= str[i] ;
str[i] ^= str[j] ;
}
}

It is not possible with NSString since they are immutable and the only way is to create a new string.
Though this might not be what you are looking for, you can convert the NSString to a normal c-string, and edit that in-place. You are still allocating memory, but you'll at least get half of what you want by being able to modify the string in place.
I'm not sure what your use case is for not wanting to allocate memory, or if this is simply a hypothetical.

Related

How to allocate contiguous memory for dynamic multidimensional arrays in SystemVerilog?

Is there a way in SystemVerilog to create a dynamic array that allocates its memory contiguously? I'm trying to read in data from a file into a dynamic array. The problem appears to be that the dynamic array is not in contiguous memory locations, so the file is not read properly into the array.
When I declare the variable reading the file as a non-dynamic array it works fine, so I assume the problem is contiguous memory. Here's the code:
This works fine, but does not use a dynamic array:
// Reads frame from a binary file
task t_Read_File(input string i_File_Name);
int n_Temp[10][10];
int n_File_ID;
n_File_ID = $fopen(i_File_Name, "rb");
$fread(n_Temp, n_File_ID);
$fclose(n_File_ID);
r_Frame = n_Temp;
endtask : t_Read_File
This uses a dynamic array (r_Frame) but does not work
// Reads frame from a binary file
task t_Read_File(input string i_File_Name);
int n_File_ID;
n_File_ID = $fopen(i_File_Name, "rb");
$fread(r_Frame, n_File_ID);
$fclose(n_File_ID);
endtask : t_Read_File
FYI, r_Frame is declared previously as a local variable to my class as follows:
int r_Frame[][];
Using $fread on a dynamic array is an open issue in the standard. It's even more problematic for multi-dimensional dynamic arrays as there is no way to know how to shape the array. To make matters more complicated, SystemVerilog does not really have multi-dimensional array; instead it has arrays of arrays. This means each indexed dimension could have a different size.
You could try allocating the array first, then calling $fread.
r_Frame = new[10];
foreach (r_Frame[i]) r_Frame[i] = new[10];
Here's the solution that I had to end up implementing. Basically I read the text file one line at a time into n_Temp, which was just a large temporary array structure. Then I put it into the multidimensional dynamic array r_Frame one value at a time. Despite previously calling new for r_Frame and setting the dimensions, $fread was not writing the values into r_Frame. I had to go through this extra step using a temporary variable to get it to work. Also I did have to write an endian swap function to convert the little-endian data file to big-endian format.
task t_Read_File(input string i_File_Name);
int n_Temp[5000]; // arbitrary, large
int n_File_ID;
n_File_ID = $fopen(i_File_Name, "rb");
for (int i=0; i<n_Active_Rows; i++)
begin
void'($fread(n_Temp, n_File_ID, , n_Active_Cols));
for (int j=0; j<n_Active_Cols; j++)
r_Frame[i][j] = Sim_Support_Pkg::f_Endian_Swap(n_Temp[j]);
end
$fclose(n_File_ID);
endtask : t_Read_File

realloc():invalid next size

so I have some code that works fine with small text files but crashes with larger ones. The point of the code is to take a file and a parameter n, parse through the code and save everything in a 2d array in chucks of size n. So buffer[0][0]through [0][n-1] should hold n characters, and buffer[1][0]through [1][n-1] should hold the next n chunk, and so on. My code works when the file only has a few words, but with a larger file I get an error saying realloc():invalid next size. Any ideas why? Here is my code.
void bsort(int n)
{
int numwords= 0;
int numlets=0;
char ** buffer=(char**)malloc(numwords*n);
while (!feof(stdin))
{
char l= getchar();
if (l!= EOF)
{
if (numlets%n==0)
{
numwords=numwords+1;
buffer=(char**)realloc(buffer,numwords*n);
if(!buffer)
{
printf("Allocation error!");
}
buffer[numwords-1]= (char*) malloc (n);
buffer[numwords-1][numlets%n]=l;
// printf("%c", buffer[numwords-1][numlets%n]);
numlets=numlets+1;
}
}
int i,j;
for (i=0; i < numwords; i++)
{
for(j=0; j< n; j++)
{
printf("%c",buffer[i][j]);
}
}
It looks as if each time you get a character, you are reallocating your buffer. That seems a little off to me. Have you thought of allocating some space, doing a memset to \0, and just managing the current size and buffer size separately?
It may be that realloc is having issues with a pointer to nothing at first. If it fails after the first character input, you might be having issues with your first malloc(). Pre-allocating some space would solve that.
AFAIK, malloc(0) is not guaranteed to return a useful pointer you can realloc().
The documentation only guarantees that malloc(0) returns either null or a pointer that can safely be used to call free().

How to Assign a single value to whole NSMutableArray?

I have an mutable array of say 20 objects. And it has values like #"TRUE",#"FALSE",#"TRUE"...
Now I want to reset the all values of array to #"FALSE". Means array having all values as #"FALSE" (20 times).
I know how to add, insert at index... But I want to know that How can I set whole array value to #"FALSE" in a sing line ??? `without using loop and replace object at index... ?
For example : is it possible
thArray = [[NSMutableArray alloc] initWithCapacity:20];
theArray = #"FALSE" ;
Thanks...
Can you use a C array? If so, you can use {0, 1} as C-equivalents of {FALSE, TRUE}, initializing a C array with:
unsigned short int cArray[20] = {0};
or:
static unsigned short int cArray[20]; /* all values are zeroes, or FALSEs */
This might be more efficient, instead of using an array of static NSString * const elements like you're doing now. Testing whether two integers are equivalent is usually faster than testing lexicographical equivalence of two strings, where your program will have to compare each string character by character.
To reset the contents of the array, you can use the C function memset():
memset(cArray, 0, 20*sizeof(unsigned short int)); /* set all values of cArray to 0 */
If you need a dynamically-sized array, use a pointer with calloc() and reset it with memset() as previously described. Just remember to free() the pointer afterwards, so that you don't get a memory leak:
unsigned short int *cArray = NULL;
size_t cArrayLength = 20; /* can be passed in as a value from another method, etc. */
cArray = calloc(cArrayLength, sizeof(unsigned short int)); /* values are initialized to 0 */
if (cArray) {
/* use cArray... */
*(cArray + 8) = 1; /* e.g., set ninth element with the value of 1 */
/* we don't need cArray any longer, so we free it */
free(cArray);
}
else
/* error */
If you must use Objective-C with NSString * or NSNumber * instances in an NSArray or NSMutableArray, there is no ready-made method for initialization and you'll need to use a loop or copy a pre-existing array, as described in Justin's answer. He is also correct that a method for creating and populating the array is a good idea, if you want to go in this direction.
If those were mutable strings inside the array you could do this in just one line:
[theArray makeObjectsPerformSelector:#selector(setString:) withObject:#"FALSE"];
Here's one way:
NSArray * initialized = ...array with fifty #"FALSE" values...;
NSMutableArray * a = [initialized mutableCopy];
... mutate a ...
[a setArray:initialized];
If you are actually dealing with bool values, C scalars will be faster (see Alex's answer).
Another alternative would be a CFMutableBitVector.
Finally, this would also be a good case for creating a function.
1) Either this
2) Or this
Otherwise without a loop there is no way.
only way i know is
for(int i = 0;i<[theArray count];i++)
{[theArray replaceObjectAtIndex:i withObject:#"FALSE"];}

NS String comparison fails with stringWithFormat

I have two NSStrings with the same value
this failed for me:
if (button.controlName == controlName) {
return button;
}
this worked:
if ([button.controlName compare: controlName] == NSOrderedSame) {
return button;
}
Is this just how strings are compared in objective c? Or should the first statement have worked as well? Why might the first statement have failed? I know it worked for other strings.
The strings it does not work for are initialized like this:
button.controlName = [NSString stringWithFormat:#"controlName%d", i]
With NSString you should use isEqualToString: instead of compare.
[button.controlName isEqualToString:controlName]
Read more the why (and also why it worked for some other strings)
Objective-C is a fairly thin layer on top of standard C. As a result obj-c, just as in normal c, doesn't have operator overloading.
NSString *controlName = #"bobDole";
The above code creates a pointer to the string #"bobDole", controlName is not the value itself, but instead is really just a long integer that says the memory address of an object.
When using pointers and comparing them using the == operator like (mutableCopy is being used to prevent the compiler from optimizing out the validity of this example.)
NSString *string1 = #"bobDole";
NSString *string2 = [string1 mutableCopy];
NSLog(#"%d", string1 == string2);
The above code will always print false (or zero in this case), even though both objects are NSStrings, and both contain the value of #"bobDole". This is because the value of string1 is actually a hex number like 0x0123456 and string2 could be something like 0x0987654. So really the above comparison looks like this to the computer:
NSLog(#"%d", 0x0123456 == 0x0987654);
So when comparing strings (or any other object), always use one of the isEqual methods, never use the == operator.
Now as to why it worked for some other strings:
As mentioned above when using the == operator you're actually doing pointer comparison. You'll also notice in my above example I used mutableCopy instead of the following:
NSString *string1 = #"bobDole";
NSString *string2 = #"bobDole";
The reason I did such was that the compiler will look at those two statements know they share the same immutable value and optimize them so they point at the same value in memory. Thus making the pointer values of the two identical.
The compiler also makes the same optimizations for these methods of string initialization.
NSString *string3 = [NSString stringWithString:#"bobDole"];
NSString *string4 = [NSString stringWithString:string1];
NSString *string5 = [string1 copy];
Because of this optimization by the compiler and runtime all 5 pointers point to the same memory location and are thus equal to each other when compared via ==.
This may be kinda long, but I tried to make it accessible and understandable. Hope it helps.
1st statement just compares pointers, but not string values, so to compare strings you should use -isEqualToString as Bryan points.
There's a method called isEqualToString to compare two NSStrings.
if([button.controlName isEqualToString:controlName])
...

Adding integer values as contents of an array,iphone

I need to store some integer values as the contents of an array. But when i try to do so, it throws a warning,
passing argument 1 of 'addObject' makes pointer from integer without a cast.
And obviously the value is not stored in the array.
Here's thecode.
NSUInteger i;
for (i=0;i<5;i++){
[array addObject:i];}
NSArray-s cannot store non-id objects. You have to box it into an NSNumber:
NSUInteger i;
for (i=0;i<5;i++) {
[array addObject:[NSNumber numberWithUnsignedInteger:i]];
}
or use a CFArray with custom callbacks (but you sacrifice readability for performance), or use std::vector<NSUInteger> (but you need to use Objective-C++).