C - Shift Array Over - c

I've been attempting to take a character array with some indices having characters and some having null characters and change it to only an array with characters - shifting over indices to remove the null spaces when need be.
This is my approach so far:
char *args[256];
void removeNulls(){
for(int i=0; i<=token; i++){
if(args[i] == '\0'){
shiftleft(i);
}
}
}
void shiftleft(int start){
for(int i=start; i<token; i++){
*(args+i) = *(args + i +1);
}
}
However, when I do this and print out the result I notice that in the args array,
that is the initial args array, it consists of : null, null, 1,2,3,4 after removing nulls this array becomes null,1,2,3,4 instead of the desired 1,2,3,4. Is there something I'm missing in my loop conditions to account for this?

One index gets skipped every time you hit a null, because you always increment i even when you are skipping. You should increment i only when not skipping, for example like this:
for (int i=0; i<=token; ) {
if (args[i] == '\0') {
shiftleft(i);
} else {
i++;
}
}
By the way, the algorithm is not optimal when there are multiple nulls, because for every null, you shift the entire remaining part. It is possible to shift the contents over the nulls in a single pass, by tracking the current index and the next index to fill. For each null value, the next fill index will get one step behind the current index.
for (int i=0, next = 0; i<=token; i++) {
if (args[i] != '\0') {
args[next++] = args[i];
}
}
Last thing, what about the excess elements? That is, for the input null, null, 1, 2, 3, token, the resulting content will be 1, 2, 3, 2, 3, token. Is that OK like that? I suggest to check your requirement, as maybe you have some tasks concerning these remaining elements. I leave that for your exercise.

When i=0, when shiftleft(0) is called,
Whatever value is at address pointed by (args+i)->(args+0)->"null" is replaced with (args+i+1)->(args+0+1)->"null".
This is why your output prints null,1,2,3,4.
Change your input to null,1,2,3,4 and you will see the difference.The output will then be 1,2,3,4

Related

Reverse printing words while maintaining order and number of spaces?

I am attempting to solve this problem but I'm not sure why my solution doesn't work. My attempts at debugging tell me that the solution is attempting to access indices outside of the bounds of some of the data structures, but this does not make sense to me as it seems like my for-loop test would would.
There are probably many other issues with this solution besides this.
I'm also 90% sure that there's a more efficient way to do this. Could you help me figure out what it is I've done wrong here?
If there is a more efficient solution, what would it be? I'm struggling to deal with keeping track of the same number of spaces in the same order in an efficient way.
If any more information is necessary, please let me know and I will update.
public static void printReversed(String line){
Scanner console = new Scanner(line);
ArrayList<String> list = new ArrayList<String>(); // keeps track of words in line
int spaceOccur = 0; // keeps track of the number of times there are spaces
while (console.hasNext()){
list.add(console.next());
spaceOccur++;
}
int[] spaces = new int[spaceOccur]; // keeps track of number of spaces for each occurrence of spaces
int count = 0; // for spaces[] traversal
// searches through original input to get number of spaces
for (int i = 0; i < line.length() - 1; i++){
if (line.charAt(i) == ' '){
int j = i;
int num = 0;
// traversal through spaces to count how many
while (line.charAt(j) == (' ')){ // first error here
num++;
j++;
}
i = j; // updates for loop counter to point past spaces
spaces[count] = num; // saves number of spaces
count++;
}
}
// printing reversed input
for (int k = 0; k < list.size(); k++){
// prints reversed chars
for (int m = list.get(k).length(); m > 0; m++){
System.out.print(list.get(k).charAt(m));
}
// prints spaces
for (int n = 0; n < spaces[k]; n++){
System.out.print(" ");
}
}
}
I'd say that you're on right tracks, but some places need some closer inspection. The first loop seems to have some problems: The j++ is probably the one that goes beyond boundaries of the array - at least if you have spaces at the end of your string. And the whole loop itself seems to ignore the last character of the line.
Are you sure you even need this first loop? If I have understood correctly, the ScannerĀ“s next() will give you strings between the spaces; in the case of two consecutive spaces I think it should return you an empty string. In this case you could just loop the list the way you do in the end of your function, and print a space character when you encounter an empty string in your list. Otherwise just print the word backwards, just like you already do (except that it should be m-- instead of m++ in the last for loop).
But if the Scanner won't give you the empty strings when there are two or more consecutive space characters, I bet the string's split() method should work.

What's the point of using linear search with sentinel?

My goal is to understand why adopting linear search with sentinel is preferred than using a standard linear search.
#include <stdio.h>
int linearSearch(int array[], int length) {
int elementToSearch;
printf("Insert the element to be searched: ");
scanf("%d", &elementToSearch);
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
return -1; // The element to be searched is not in the array
}
int main() {
int myArray[] = {2, 4, 9, 2, 9, 10};
int myArrayLength = 6;
linearSearch(myArray, myArrayLength);
return 0;
}
Wikipedia mentions:
Another way to reduce the overhead is to eliminate all checking of the loop index. This can be done by inserting the desired item itself as a sentinel value at the far end of the list.
If I implement linear search with sentinel, I have to
array[length + 1] = elementToSearch;
Though, the loop stops checking the elements of the array once the element to be searched is found. What's the point of using linear search with sentinel?
A standard linear search would go through all the elements checking the array index every time to check when it has reached the last element. Like the way your code does.
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
But, the idea is sentinel search is to keep the element to be searched in the end, and to skip the array index searching, this will reduce one comparison in each iteration.
while(a[i] != element)
i++;
First, lets turn your example into a solution that uses sentinels.
#include <stdio.h>
int linearSearch(int array[], int length, int elementToSearch) {
int i = 0;
array[length] = elementToSearch;
while (array[i] != elementToSearch) {
i++;
}
return i;
}
int main() {
int myArray[] = {2, 4, 9, 2, 9, 10, -1};
int myArrayLength = 6;
int mySearch = 9;
printf("result is %d\n", linearSearch(myArray, myArrayLength, mySearch));
return 0;
}
Notice that the array now has an extra slot at the end to hold the sentinel value. (If we don't do that, the behavior of writing to array[length] is undefined.)
The purpose of the sentinel approach is to reduce the number of tests performed for each loop iteration. Compare:
// Original
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i;
}
}
return -1;
// New
while (array[i] != elementToSearch) {
i++;
}
return i;
In the first version, the code is testing both i and array[i] for each loop iteration. In the second version, i is not tested.
For a large array, the performance difference could be significant.
But what are the downsides?
The result when the value is not found is different; -1 versus length.
We have to make the array bigger to hold the sentinel value. (And if we don't get it right we risk clobbering something on the stack or heap. Ouch!)
The array cannot be read-only. We have to be able to update it.
This won't work if multiple threads are searching the same array for different elements.
Using the sentinel value allows to remove variable i and correspondingly its checking and increasing.
In your linear search the loop looks the following way
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
So variable i is introduced, initialized, compared in each iteration of the loop, increased and used to calculate the next element in the array.
Also the function has in fact three parameters if to pass to the function the searched value
int linearSearch(int array[], int length, int value) {
//...
Using the sentinel value the function can be rewritten the following way
int * linearSearch( int array[], int value )
{
while ( *array != value ) ++array;
return array;
}
And inside the caller you can check whether the array has the value the following way
int *target = linearSearch( array, value );
int index = target == array + size - 1 ? -1 : target - array;
If you add the value to search for, you can reduce one comparison in every loop, so that the running time is reduced.
It may look like for(i = 0;;i++) if(array[i] == elementToSearch) return i;.
If you append the value to search for at the end of the array, when instead of using a for loop with initialization, condition and increment you can a simpler loop like
while (array[i++] != elementToSearch)
;
Then the loop condition is the check for the value you search for, which means less code to execute inside the loop.
The point is that you can convert the for loop into a while/repeat loop. Notice how you are checking i < length each time. If you covert it,
do {
} while (array[i++] != elementToSearch);
Then you don't have to do that extra checking. (in this case, array.length is now one bigger)
Although the sentinel approach seems to shave off a few cycles per iteration in the loop, this approach is not a good idea:
the array must be defined with an extra slot and passing its length as 1 less than the defined length is confusing and error prone;
the array must be modifiable;
if the search function modifies the array to set the sentinel value, this constitutes a side effect that can be confusing and unexpected;
the search function with a sentinel cannot be used for a portion of the array;
the sentinel approach is inherently not thread safe: seaching the same array for 2 different values in 2 different threads would not work whereas searching a constant read only array from multiple threads would be fine;
the benefits are small and only for large arrays. If this search becomes a performance bottleneck, you should probably not use linear scanning. You could sort the array and use a binary search or you could use a hash table.
optimizing compilers for modern CPUs can generate code where both comparisons will be performed in parallel, hence incur no overhead;
As a rule of thumb, a search function should not have side effects. A good example of the Principe of least surprise.

C, Count unique strings in an array of strings

Using C, I have an array of strings, some are duplicates. I'm trying to count the number of unique strings. Code:
for(i=0; i<size; i++){
flag=0;
if(strcmp(" ", tArr[i])!=0){
for(j=i; j<size; j++){
if(strcmp(tArr[i], tArr[j])==0){
if (flag<1){
flag=1;
k++;
}
strcpy(tArr[j], " ");
}
}
}
}
First for loop goes through the whole array
Set flag to zero for each iteration
Using blanks as another flag, if an index is blank, that means that word has already been counted, move to next index
Compare that index to every index after it, thus j=i
If the secondary index matches the first
If that word has not been found yet
Trigger the flag
Add to k, the unique word count
Set every remaining instance of that word to a blank space, to match line 3
Instead of setting k to the unique word count, it gets set to the total word count. Using printed flags I was able to tell that the function makes it all the way through, even to after line
I still can't tell how it makes it to line 8 every iteration of the outermost for loop.
Adapting your code, try something like this:
for (i = 0; i < size; i++) {
for (j = i + 1; j < size; j++)
if (strcmp(tArr[i], tArr[j]) == 0)
break;
if (j == size)
unique_count++;
}
There should be no need to destroy the duplicates if you are just counting, however if you still wish to do that I would suggest a null string instead of one containing a space.

Increasing intervals in an array, check

So I'm trying to check if an array that was previously inputted is increasing in intervals of 1, starting with the number 1 and ending with n (n being the array size).
Here's what I got so far:
for (int i =0; i<n;i++){
for (next=i;next<n;next++){
if(arr[i]+1 = arr[next]){
x = 1; //ignore this, it relates to the rest of the code.
}
else{
printf ("\nThis is not a permutation.");
break;
}
}
}
Now, my thinking is that this code would compare parameters that are next to each other, and if the following parameter is equal to the previous +1, then it is obviously increasing by 1. Problem is, when this is false, it wont print "This is not a permutation," and wont break the loop.
Any help would be appreciated.
Also, any insight as to checking if the array starts with the number 1 would be appreciated.
Thanks
Looks like in this line:
if(arr[i]+1 = arr[next]){
You intended comparison:
if(arr[i]+1 == arr[next]){
Have you tried if(arr[i]+1 == arr[next]) instead of if(arr[i]+1 = arr[next])??
If you need to check that a sequence is increasing, why are you comparing every element against the others? You should only need one for loop:
for (i = 1; i < n; i++)
{
if (arr[i - 1] + 1 == arr[i])
... // keep going
else
... // not a permutation
}
Basically, what your code does is check that every element after the i-th one is greater than that i-th one by one. Ultimately, this leads to an impossible case (as two numbers must be equal but must differ by one at the same time).
It sounds like you want to test if arr[0] == 1 and every subsequent array element is 1 greater than the previous element. Isn't that the same as checking your array for the values [1,2,3,...,n]?
for (int i = 0; i < n; ++n) {
if (arr[i] != i + 1) {
printf("\nThis is not a permutation.");
break;
}
}

Trying to split a string into parts

I got 2 arrays :
data[256] = "1#2#3#4#5"
question[256][256];
I need to split the number before the # into an array..
for example :
question[0][] = 1
question[1][] = 2
question[2][] = 3
question[3][] = 4
question[4][] = 5
It doesnt metter if I have the # in, or not.
This is what I wrote :
int i = 0, j = 0;
data = "1#2#3#4#5";
for (i = 0 ; i < strlen(data) ; i++)
{
for (j ; data[j] != '#' ; j++)
{
question[i][j] = data[j];
}
j++
}
printf ("%s\n", question);
The problem is, it works untill the first #, and then stops.
It only put the first # into question, and then stops.
(basiclly I'm supposed to get the same output for printing both data, and question).
There are a few problems.
First, printf only prints the string until the first terminating zero character ('\0'), which happens after the first "part" in question (even though there are other parts. Instead, you will need to print all:
for (i=0; i<255; ++i) {
printf("%s\n", question[i]);
}
Make sure you null-terminate ('\0') the rows of question before, so you don't print garbage for uninitialized rows. or just maintain the index of the last-good row and iterate until that
Also, the loop
for(j; data[j]!='#', j++)
will stop at the first '#', and all consequent iterations of the outside loop will evaluate the same j (which is the index of '#', so the loop is skipped in further iterations. You will need to advance j after the inner loop
you will also need to maintain a last-j position after the last '#' to be able to calculate the position of j from the last '#', so you can index into question[i] properly. set lastj to the value of j after is extra advancement suggested in the previous paragraph. Also, the second index of question should be j-lastj from now on.
Yet another thing about the inner loop: as it is, it will advance past the string in data after the last '#', so you will have to check for noll-termination as well.
Also, make sure you null-terminate the strings in question, otherwise printf will produce garbage (and possibly seg-fault when reaching memory not allocated to your progam). just write
question[i][j-lastj] = '\0';
after the inner loop. (j will have pointed after the last written index at the end of the inner loop)
Yet one more thing: do not iterate i until the length of data as you will not need to touch that many elements (and likely will overindex data in the inner loop). Use a while loop instead, incrementing i only until you have covered data with j in the inner loop
Note: look up strtok to make the tokenization easier on your part
I would use something like strchr to get the location of the next '#'.
The algorithm is something like this: You get the position of the next '#', and if there is none found then set next to the end of the string. Then copy from the current beginning of the string to next position into where you want it. Remember to terminate the copied string! Set the beginning of the string to one beyond next. Repeat until beginning is beyond the end of the data.
Edit: Code for my solution:
char *beg = data;
char *end = data + strlen(data); /* Points to one beyond the end of 'data' */
for (int i = 0; beg < end; i++)
{
char *next = strchr(beg, '#'); /* Find next '#' */
if (next == NULL)
break; /* No more '#' */
memcpy(question[i], beg, next - beg); /* Copy to array */
question[i][next - beg] = '\0'; /* Remember to terminate string */
beg = next + 1; /* Point to next possible number */
}
Note: Not tested. Might be one of with the copying, might have to be next - beg - 1. (Even after 25 years of C-programming, I always seem to get that wrong on the first try... :) )
There is a much simpler way to do this. Use strtok to tokenize the string by "#", and then use strcpy to copy the tokenized strings into your question array. For example (not tested):
char *pcur = data;
int i = 0;
do
{
if ((pcur = strtok(pcur, "#")) != NULL)
{
strcpy(question[i], pcur++);
printf ("%s\r\n", question[i++]);
}
}
while (pcur != NULL);
As shown in the above example, incrementing i moves the question array index to the next position, and incrementing pcur moves the tokenized string pointer past the nulled token for the next iteration through the loop.
See also:
http://msdn.microsoft.com/en-us/library/2c8d19sb.aspx
http://msdn.microsoft.com/en-us/library/kk6xf663.aspx

Resources