For example if I have an array and I want to extract elements of this array with a specified value as a new array. I did as the following:
int a[10] = { 1, 2, 1, 3, 2, 3, 4, 1, 2, 6 };
int i, k;
int count = 0;
for (i = 0; i < 10; i++) {
if (a[i] == 1) {
count = count + 1;
}
}
int b[count];
k = 0;
for (i = 0; i < 10; i++) {
if (a[i] == 1) {
b[k] = a[i];
k = k + 1;
}
}
So, for the array "a" I extracted all the elements of value 1, and make them as a new array "b". How can I achieve the same thing by using pointers? Will it be conciser than this way? If it is possible, is there any other advantages?
I think you already noticed that you just had to write 1 several times; yet I suppose you want that it works for arbitrary conditions.
"Using a pointer" can mean dynamic memory allocation instead of a variable length array. Just for the sake of having use a pointer, you could then write:
int *b = malloc(count * sizeof(int));
k = 0;
for (i = 0; i < 10; i++) {
if (a[i] == 1) {
b[k] = a[i];
k = k + 1;
}
}
If, just for sake of using a pointer for the writing process, too, you could adapt the program as follows:
int *b = malloc(count * sizeof(int));
int *bPtr = b;
for (i = 0; i < 10; i++) {
if (a[i] == 1) {
*bPtr++ = a[i];
}
}
Hope it helps a bit.
If you don't know which portion of the array your target values will be in, as in your case, where you're searching the entire unsorted array for a specific value, then there is no advantage to using pointers rather than a linear search to find the elements in the array you are after.
If, however, you are trying to access or copy a contiguous set of elements starting at a known index in the array, then you could use a pointer to simplify things. For example, if I'm after the last few elements in an array of chars, this works:
#include <stdio.h>
int main()
{
char str[100] = "I don\'t want anyone to think I hate the Calgary Flames";
char *c = (str + 29);
printf("%s\n", c);
return 0;
}
Output:
I hate the Calgary Flames
In this case, no, there is no benefit. a[i] is already basically a + (sizeof(int) * i). Even if you used pointers, you'd still have to do all the counting anyway to make sure you don't walk off the end of the array.
Where its often handy is with a null terminated array of pointers, such as a string, where you don't know the length. But it's not really about performance. As you can see below, they have to do roughly the same things.
char string[] = "foo bar";
// Allocate and initialize i.
// `string + i` twice, compare, increment.
for( int i = 0; string[i] != '\0'; i++ ) {
printf("%c", string[i]);
}
puts("");
// Allocate and initialize s.
// Dereference s twice, compare, increment.
for( char *s = string; *s != '\0'; s++ ) {
printf("%c", *s);
}
puts("");
Where iterating by pointer is handy is when you need to iterate through an array in several steps. Instead of passing around the original array pointer plus your last index, and changing all your function signatures to accommodate, just pass around the incremented pointer and return the incremented pointer. This allows you to use standard string functions on the middle of a string.
#include <stdio.h>
char *findVal( char *string, char delim ) {
char *val = string;
for( ; *val != '\0' && *val != delim; val++ ) {
}
if( val == '\0' ) {
return NULL;
}
else {
// val is sitting on the ':'
return val+1;
}
}
int main() {
char string[] = "this:that";
char *val = findVal(string, ':');
if( val != NULL ) {
// Just use val, not string[valIdx].
printf("%s\n", val);
}
}
This is also safer. With an offset there's two things which must remain in sync, the pointer and the offset; that opens the possibility that the wrong offset will be used with the wrong pointer. An incremented pointer carries its offset with it.
As has been pointed out in the comments, you can tighten up the second loop like so:
int b[count];
for (i = 0; i < count; i++) {
b[i] = 1;
}
Related
I have created an array in C and I know how to print every element in an array but couldn't figure it out how to not print repeated elements, or to be more precise, like I ask in the title, how can I print all elements just once?
For example my array is: [a b c d a a b d c c]
I want to print it like this: [a b c d]
I think that I should use for or while loop, but I don't know how. I have been thinking about this for hours and did some research but couldn't find anything valuable.
Here you are.
#include <stdio.h>
int main(void)
{
char a[] = { 'a', 'b', 'c', 'd', 'a', 'a', 'b', 'd', 'c', 'c' };
const size_t N = sizeof( a ) / sizeof( *a );
for ( size_t i = 0; i < N; i++ )
{
size_t j = 0;
while ( j != i && a[j] != a[i] ) ++j;
if ( j == i ) printf( "%c ", a[i] );
}
putchar ( '\n' );
return 0;
}
The program output is
a b c d
Or for example if you have a character array that contains a string then the same approach can be implemented the following way.
#include <stdio.h>
int main(void)
{
char s[] = { "abcdaabdcc" };
for (const char *p = s; *p != '\0'; ++p )
{
const char *prev = s;
while ( prev != p && *prev != *p ) ++prev;
if ( prev == p ) printf( "%c ", *p );
}
putchar ( '\n' );
return 0;
}
The program output is the same as shown above that is
a b c d
As the array is an array of char containing lower case letters, there are pretty few different values. Consequently, you can make a table (aka another array) to track the already printed values.
Like:
#define MAX ('z' - 'a' + 1) // Calculate the number of unique elements
int already_printed[MAX] = { 0 }; // Mark all chars as "not printed"
for (i = 0; i < SIZE_OFF_ARRAY; ++i)
{
if (already_printed[array[i] - 'a'] == 0) // If NOT printed yet
{
printf("%c\n", array[i]); // Print it and
already_printed[array[i] - 'a'] = 1; // mark it as printed
}
}
This gives you a simple O(N) solution. Having a O(N) solution is important for performance when handling large arrays.
Notice: This solution assumes that all array element are between 'a' and 'z' (both included) but can easilly be extended to support more a wider range.
I'm not sure what the type of the elements in the array is, but let's assume it's some type that C can "natively" compare. Then the conceptually simple solution is to sort the array, and the print it skipping duplicates. Sorting will ensure that the duplicates are adjacent. This approach will perform well in most circumstances.
First, let's set up some helper functions specific to the element type. You could remove the assign function if you only want to deal with char type, but it'll be inlined by the compiler anyway.
#include <stdlib.h>
#include <stdio.h>
// You can adapt the element type per your requirements
typedef char ElementType;
// This function assigns the source value to the destination:
// it does what *dst = *src would do.
static inline void assign(void *dst, const void *src)
{
*(ElementType*)dst = *(const ElementType*)src;
}
// This is the "spaceship" comparison operator (<=> in C++) that
// merges less-than, equal, and more-than comparisons into one.
int compare(const void *l, const void *r)
{
const ElementType *L = l;
const ElementType *R = r;
if (*L < *R) return -1;
if (*L > *R) return 1;
return 0;
}
void print_element(const ElementType *el) { printf("%c", *el); }
Since we plan to sort the array, we need to copy it first - after all, a "printer" for an array shouldn't be modifying it. Such modifications are OK in tiny programs, but are just a bad habit, since if you look at the name of the function like print_unique, nothing hints you that it would modify the data it's supposed to print: that's not how printing normally acts. It'd be unexpected and very error prone.
The copy operation could be skipped if it's OK to modify the source array: its elements would need to be non-const then, and the print_unique function name would need to be changed to something like sort_and_print_unique.
ElementType *copy_array(const ElementType *src, const int count)
{
ElementType *copy = malloc(sizeof(ElementType) * count);
if (!copy) abort;
for (int i = 0; i < count; ++i)
assign(copy + i, src + i);
return copy;
}
And now the unique element printer, and a test with the data you provided:
void print_unique(const ElementType *data, int const count)
{
ElementType *copy = copy_array(data, count);
qsort(copy, count, sizeof(ElementType), compare);
printf("[");
for (int i = 0; i < count; ++i) {
if (i == 0 || compare(copy+i, copy+i-1) != 0) {
if (i != 0) printf(" ");
print_element(copy+i);
}
}
printf("]\n");
}
int main() {
const char array[] = "abcdaabdcc";
print_unique(array, sizeof(array)/sizeof(*array) - 1);
}
Output: [a b c d]
The alternate, modifying implementation I mentioned above would be:
void sort_and_print_unique(ElementType *data, int const count)
{
qsort(data, count, sizeof(ElementType), compare);
printf("[");
for (int i = 0; i < count; ++i) {
if (i == 0 || compare(data+i, data+i-1) != 0) {
if (i != 0) printf(" ");
print_element(data+i);
}
}
printf("]\n");
}
int main() {
char array[] = "abcdaabdcc"; // note absence of const!
sort_and_print_unique(array, sizeof(array)/sizeof(*array) - 1);
}
A simple way:
#include <stdio.h>
int main() {
int ascii[128] = { 0 };
char input[] = "abcdaabdcc";
for(int i = 0; input[i]; i++) {
++ascii[(int)input[i]];
}
for(int i = 0; i < 128; i++) {
if( ascii[i] ) printf("%c ", i);
}
return 0;
}
The array ascii is used to keep track of the frequency of each of the 128 ascii characters with a non negative value (for example 'a' is 97 and '0' is 48). And then if the frequency of a character is not 0, you print the character.
First, sort the array (use qsort(3) for example), then all the equal elements will be together. Then go in a one pass on the array saving the last element printed... if the one to be printed now is the same as the one printed last, just skip it and continue; to the next.
I"m trying to store int array as a str and display it but in the reverse order.
Its only while printing the str that i get junk.
What is wrong in my code?
int main() {
int a[] = { 1, 2, 3 }; // Output should be 321 (char)
int size = sizeof(a) / sizeof(int);
char str[size + 1];
int i;
for (size = size - 1; size >= 0; size--) {
sprintf(&str[size], "%d", a[size]);
//printf("%c\n", str[size]);
}
printf("%s\n", str); // I get garbage.
}
I modified your solution with several bug fixes. For starters, you can't assume that your integer array will only hold single digit values.
And that for loop as you have it:
for(size=size-1;size >= 0;size--)
Is very suspicious looking. (the index variable is the thing its based off?)
Simple solution
This is likely what you meant:
for(i = 0; i < size; i++) {
sprintf(&str[i],"%d", a[size-1-i]);
}
str[size] = '\0';
Or this:
str[size] = '\0';
for(i = size-1; i <= 0; i--) {
sprintf(&str[i],"%d", a[size-1-i]);
}
Better solution
I'm not sure what you are expecting to do if an integer within the a array is negative. So the - sign will just get inserted into str inplace.
The solution I have will first count how many chars are needed for each integer in a. Then it will allocate the str buffer with that length (+1 for null char).
Then we make use of the return value from sprintf to figure out where to concatenate onto. We could use strcat, but this is likely faster.
int main() {
int j = 0;
int a[] = { 1,2,3 }; // Output should be 321 (char)
int size = sizeof(a) / sizeof(int);
int length = 1; // +1 for final null char
// Count the size of characters needed for each integer
// Do a dummy sprintf and use its return value to figure out how many chars are needed
for (int i = 0; i < size; i++) {
char tmp[sizeof(int) * 5]; // sizeof(int)*5 is big enough to hold any integer including a negative value
length += sprintf(tmp, "%d", a[i]); // utilize the return value from sprintf and add it to the running length
}
char str[length];
str[0] = '\0'; // initially null terminate our string
// reverse print chars from a into str
for (int i = 0; i < size; i++) { // use i as index variable, not size
j += sprintf(str + j, "%d", a[size - 1 - i]);
}
printf("%s\n", str);
}
Alternative solution, closer to original posts, and clearly not trying to address the general problem (assume values are single digit):
int a[]={1,2,3}; // Output should be 321 (char)
int size = sizeof(a)/sizeof(int);
char str[size+1];
for(int i=0; i<size ; i++) {
str[size-1-i] = ‘0’ + a[i];
}
str[size] = 0;
printf("%s\n", str); // I get garbage.
}
Taking advantage of the assumed input value, converting each int to character representation at the reverse position.
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
int len = 3; // length of word
char * word = "cat"; // word to be sorted
char sortedWord[len];
int i, j, temp;
// store chars from 'word' to an array 'sortedWord[]'
for (i = 0; i < len; i++) {
sortedWord[i] = *word;
word++;
}
// sort the array using bubble sort
for (i = 0; i < len - 1; i++) {
for (j = 0; j < len - i - 1; j++) {
if (sortedWord[j] > sortedWord[j + 1]) {
temp = sortedWord[j];
sortedWord[j] = sortedWord[j + 1];
sortedWord[j + 1] = temp;
}
}
}
printf("%s\n", sortedWord);
}
The focus of this question is the variable 'len'. If I were to define len to be equal to 3, then the output is as expected (i.e. "act"). However, I want to be able to find the length without explicitly defining it.
I have tried to define len as:
int len = strlen (word);
However, the output is not as expected. It would give me results such as actW?, actX?, and so on.
This same behavior occurs when I try to define len as:
int len;
for (len = 0; *word != '\0'; len++) {
word++;
}
Surprisingly, if I were to print the the variable len right after explicitly defining it, it would also behave the same way.
int len = 3;
printf("Length: %d\n", len); // will cause the output to be different
I am sure that I am missing a fundamental concept, but I am not sure on an approach to resolve this problem. Thanks in advance!
Your storeWord is not null terminated causing undefined behavior, add the null terminator and it will no longer behave erratically.
And also, if you increment the word pointer, it will end up pointing to the null terminator of the original string, so don't do that. Instead, use the index to access elements.
char sortedWord[len + 1]; // One more for the '\0'
int i, j, temp;
// store chars from 'word' to an array 'sortedWord[]'
for (i = 0; i < len; i++) {
sortedWord[i] = word[i];
}
storeWord[len] = '\0';
One more thing, when writing pointers to string literals, use const to prevent accidentally modifiying them, since that is undefined behavior too, so
const char *word = "cat";
I'm trying to take a string and break it into "word" components and store that in an array of strings.
"Hello my name is Bill." should give back a char** with elements, "Hello", "my", "name", "is", and "Bill."
My code will compile however I keep encountering a runtime error (I don't get warnings anymore and my debugger gdb doesn't work)>
I'm running on minGW on Window 8.
#include <stdio.h>
#include <stdlib.h>
char** words(char* string)
{
int i = 0;
int j = 0;
int k =0;
int count = 0;
char** stringArray = (char**) malloc(sizeof(char)*30*30);
while( string[i] != '\0' )
{
if(string[i] != ' ')
{
j =0;
while(string[i+j+1] != ' ')
{
j++;
}
i = i+j;
for(k=0; k<=j; k++)
{
stringArray[count][k] = string[i+k];
}
count++;
}
i++;
}
return stringArray;
}
int main()
{
char message[20] = "abcd efgh ijkl mno";
char** wordArray = words(message);
printf("%c\n\n", wordArray[0][0]);
int i =0;
while(wordArray[i])
{
printf("%s\n", wordArray[i]);
i++;
}
printf("\nThe problem is not with the words function");
return 0;
}
There are couple of issues that have been mentioned in the comments.
The allocation should look something like:
#include <ctype.h> // for isspace()
#define MAXSTRLEN 30 // using a symbolic constant
char **stringArray;
int i, j, k;
stringArray = malloc(sizeof(char*) * MAXSTRLEN); // don't cast from malloc
for (i = 0; i < 30; ++i) {
stringArray[i] = malloc(sizeof(char) * MAXSTRLEN);
}
// TODO error checking: malloc could return NULL
while copying the substrings would look like:
i = 0;
j = 0;
while( string[i] != '\0') // go through the whole string
{
while (string[i] != '\0' && isspace(string[i])) {
i++; // skip whitespaces
}
k = 0;
while (string[i] != '\0' && !isspace(string[i])) { // copy word until whitepace or end of string
stringArray[j][k++] = string[i++];
}
stringArray[j][k] = '\0'; // EOS !!!
j++;
}
and printing (j is number of words actually read):
for (i = 0; i < j/*30*/; ++i) { // (!) how to print
printf("%s\n", stringArray[i]);
}
And, yes strtok would also do the job.
In words() you're assigning values to stringArray as a two-dimensional array, and in main() you're reading values from it as an array of pointers. Those are not the same thing.
So you need to change it so that you're consistently treating it as a 2D array, or so that you're consistently treating it as an array of pointers (char* to be exact). Either will work... see the comments above for elaboration.
This code is all wrong.
char** stringArray = (char**) malloc(sizeof(char)*30*30);
First of all, sizeof(char) is always one, second, you don't need to cast a void. So:
char **stringArray = malloc(30 * 30);
But that doesn't make any sense because it's an array of char *, so you should allocate in terms of that:
char **stringArray = malloc(sizeof(char *) * 30);
Or even better:
char **stringArray = malloc(sizeof(*stringArray) * 30);
So now you have an array with 30 char *, but each of those is not initialized, so you need to do that:
for (i = 0; i < 30; i++)
stringArray[i] = malloc(sizeof(**stringArray) * 30);
If you don't do that, you can't access stringArray[count][k].
And then you assume the last element in the array is NULL, but you never set it, so you either do stringArray[count] = NULL at the end of words(), or you do calloc() instead of malloc().
I'm not analyzing the code beyond that; it's just all wrong.
I am trying to reverse a character string in C
Here is what I have
void reverse(char str[]) {
int i = 0;
int length;
// Get string length
for (i = 0; str[i] != '\0' ; ++i) {
length = i;
}
char reversed[1000];
int j;
j = 0;
// Reverse it
for (j = 0; j < length ; ++j) {
reversed[j] = str[length - j];
}
}
I know that reversed contains the string reversed, but I'm not sure how to modify the original str without throwing away data I need.
I also don't know how to set strto reversed without looping again.
Would it be acceptable to do another...
int m;
m = 0;
for (m = 0; m < length ; ++m) {
str[j] = reversed[j];
}
Usually I'd say this many loops smells, but I'm also still quite unfamiliar with the language so I'm not sure...
Update
Thanks for all the answers guys, and I appreciate the edits too!
I ended up going with this...
int main() {
char str[] = "Reverse me!";
int length;
for (length = 0; str[length] != '\0'; length++) {
}
printf("length => %d chars\n", length);
int j, k;
char c;
for (j = 0, k = length - 1; j < k; j++, k--) {
c = str[k];
str[k] = str[j];
str[j] = c;
}
printf("reversed => %s\n", str);
return 0;
}
Some things I now know...
There is a strlen() like in PHP. However, it has not been discussed in the book yet, plus I need to get familiar with null terminated strings.
A for loop can assign and do multiple things that are comma separated. I never knew this!
So asking was worthwhile :)
You want to do an in-place reversal. Here's a standard algorithm:
// taken from The C Programming Language
// by Brian Kernighan and Dennis Ritchie (K&R)
void reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
Note that strlen pretty much replaces your original first loop. It's one of the many standard string manipulation routines available from string.h.
See also
Wikipedia/In-place algorithm
Wikipedia/string.h
Wikipedia/C Standard Library
You can use either of the two methods below, depending on whether you're comfortable with pointers or not. It will also be worthwhile looking at them side-by-side when you satrt learning about pointers so you can better understand how they map to each other.
This is a full program for testing purposes:
#include <stdio.h>
#include <string.h>
// The pointer version.
void reverse1 (char *str) {
char t; // Temporary char for swapping.
char *s = str; // First character of string.
char *e = &(s[strlen(s)-1]); // Last character of string.
// Swap first and last character the move both pointers
// towards each other. Stop when they meet or cross.
while (s < e) {
t = *s;
*s++ = *e;
*e-- = t;
}
}
// The array version.
void reverse2 (char *str) {
char t; // Temporary char for swapping.
int s = 0; // First character of string.
int e = strlen(str)-1; // Last character of string.
// Swap first and last character the move both pointers
// towards each other. Stop when they meet or cross.
while (s < e) {
t = str[s];
str[s++] = str[e];
str[e--] = t;
}
}
int main (void) {
char x[] = "This is a string for reversing.";
printf ("Original: [%s]\n", x);
reverse1 (x);
printf ("Reversed: [%s]\n", x);
reverse2 (x);
printf (" Again: [%s]\n", x);
return 0;
}
and the output is:
Original: [This is a string for reversing.]
Reversed: [.gnisrever rof gnirts a si sihT]
Again: [This is a string for reversing.]
Comments on your code:
void reverse(char str[]) {
int i = 0;
int length;
// Get string length
for (i = 0; str[i] != '\0' ; ++i) {
length = i;
}
Rather than copying the i to length every time you could just wait until the end.
size_t len = 0; // size_t is an unsigned integer that is large enough to hold the sizes
// of the biggest things you can have (32 bits on 32 bit computer,
// 64 bits on a 64 bit computer)
char * s = str;
while (*s) {
len++;
s++;
}
Though the compiler would probably be able to make this optimization for you.
You should know, though, that there is a standard string function strlen ( #include <string.h> )which will measure the length of a char string using the same general algorithm (look for the end) but is usually optimized for the target processor.
len = strlen(str);
Your code again:
char reversed[1000];
Using big arrays are good for learning and simple examples, but you can also allocate memory dynamically based on the size you now know you need. The standard function for doing this is malloc which is in stdlib.h (also in malloc.h). Memory allocated with this function should also be freed, though.
int * p = malloc( 8 * sizeof(int) ); // allocate an array of 8 ints
/* ... work on p ... */
free(p);
/* ... don't access the memory pointed to by p anymore ... */
p = 0;
There are also other functions in the malloc family. There's calloc, which allocates memory and clears sets it to 0. There is also a function called strdup (which isn't in standard C, but is very widely available in string.h) which takes a string and allocates a duplicate of it. It is really just:
char * strdup(const char * str) {
size_t len = strlen(str);
char * s = malloc(len+1);
if (!s) {
return s;
}
return strcpy(s,str); // This could have been memcpy since you know the size
// and memcpy might have been faster on many processors
}
Another useful memory allocation function is alloca (not in the C standard, but widely available and similar functionality is available with variable length arrays in C99). It is great, but works differently from malloc. It allocates memory that is only useable until the current function returns because this memory is allocated in the same way as memory for local variables (from the stack).
More of your code:
int j;
j = 0;
// Reverse it
for (j = 0; j < length ; ++j) {
reversed[j] = str[length - j];
}
The code:
void reverse_in_place(char * str, size_t len) {
size_t i, j;
for (i = 0, j = len - 1; i < j ; i++, j--) {
char a = str[i];
char z = str[j];
str[i] = z;
str[j] = a;
}
}
should swap the order of the string without making a copy of it. For strings with odd length it won't try to swap the middle char with itself.
Reversing a string in C using pointers
#include<stdio.h>
char *srcptr = "Hello!";
char *destptr;
unsigned int length = 0;
void main(void)
{
while(*(ptr++) != '\0')
{
length++;
}
//at the end of while loop, pointer points to end of string
while(length--)
{
*destptr++ = *ptr--;
}
//append null at the end
*destptr = '\0';
printf("%s",ptr);
}