What does happen when we equation two pointer in C? - c

This is a C code to sort the substrings of a large string starting from each index but I cannot understand how can we sort the array a in the code.
As far as I understand:
we refer a[i] to &c[i] and thus it created n arrays but doesn't
&a[i][1] == &a[i+1][0]?
Since a[i] = &c[i], is it true that &a[i][0] == &c[i]?
If not, this looks like a faster way to create n(length of original
string) arrays, without actually copying it. Is that true?
My code
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define M 1
#define MAXN 5000000
char c[MAXN], *a[MAXN];
int pstrcmp(char **p, char **q){
return strcmp(*p, *q);
}
int main(){
int i, ch, n = 0, maxi, maxlen = -1;
while ((ch = getchar()) != EOF) {
a[n] = &c[n];
c[n++] = ch;
}
c[n] = 0;
qsort(a, n, sizeof(char *), pstrcmp);
printf("%s",a[1]);
return 0;
}

I'm guessing pstrcmp is a wrapper around strcmp that compares two pointers to char pointers. Something like:
int pstrcmp(const void *a, const void *b) {
return strcmp(*(char**)a, *(char**)b);
}
To answer your questions,
Yes, &a[i][1] == &a[i+1][0]. They both point to the i + 1-st character of c.
Yes, &a[i][0] == &c[i].
You are indeed creating pointers to n strings, but there is a catch: if you altered any string (say, the last character), you would be altering more strings. So these strings are not independent.
Conceptually, a[i] is a pointer to the suffix of c starting at position i. The program then sorts a according to the values of the strings they point to. So, for c = "abacaba", you would get { "a", "aba", "abacaba", "acaba", "ba", "bacaba", "caba" }.
Please note that there are faster ways to build suffix arrays.

In this code, I don't see sub-strings, as you don't build any.
Technically, a is an array of pointers of type char that could make it an array of strings, but the way you link c to a, effectively a is an index of c.
Inside the loop, you fill the index char by char. Later when you sort a, you sort the index.
The problem with the index is, that you can't really print it out as a string, as it is not a char * that the %s printf format modifier expects, but a char **. This alone should warn you about something spooky. I see that you evaded this problem as hard coding a[1] as parameter, but the sole problem of what index to use, tells, that you are going in the wrong way.
I've slightly edited your code, how it would print out the sorted array. If you think it is not doing what you want, there is a misunderstanding between what you want and what your code does (except the last printf).
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define MAXN 5000000
// This is an array of characters:
char c[MAXN];
// This is an array of pointers pointing to individual characters. Essentially, this is an index.
char *a[MAXN];
static int pstrcmp(const void *p1, const void *p2){
// wrapper between strcmp and qsort's compare signature.
// See: man 3 qsort -- http://linux.die.net/man/3/qsort
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
int main() {
int ch;
size_t n = 0;
while ((ch = getchar()) != EOF) {
// In this loop, you systematically build up an index, where a[i] points to c[i].
a[n] = &c[n];
c[n] = ch;
n++;
}
c[n] = 0;
qsort(a, n, sizeof(char *), pstrcmp); // Now, you sort the _index_.
printf("\nc: %s\n", c); // Print Original array.
printf("a: "); // Print Ordered array:
for (size_t i = 0; i < n; i++)
printf("%c", *a[i]); // Look at the indirection
printf("\n");
return 0;
}

Related

How to reassign a array in c?

#include <stdio.h>
#include <stdlib.h>
void reasi(char** a){
char* x[] = {"1","22","333"};
a = x;
}
int main(){
char* a[] = {"bob","alice","tom"};
reasi(a);
for(int i=0; i< 3; i++){
printf("%s\n",a[i]);
}
}
The desired output should be {"1","22","333"}, but it won't work if I assign the value like that. I do know how to change the value of an int or char but don't know how to reassign the value to an array (without dynamically allocating memory). I tried to update each element inside "a" and it works. Thank you.
What you're doing won't work. You're simply creating a local array and then assigning your local parameter a to the beginning of this array (which changes nothing about the a in main). So the real thing isn't modified.
To actually modify this, you can either do a plain for loop:
// NOTE: this assumes array has the same number of elements as x
void reasi(char** a)
{
char* x[] = {"1","22","333"};
for (unsigned i = 0; i < sizeof x / sizeof *x; ++i)
a[i] = x[i];
}
Or use memcpy:
#include <string.h>
// NOTE: this assumes array has the same number of elements as x
void reasi(char** a)
{
char* x[] = {"1","22","333"};
memcpy(a, x, sizeof x);
}
Your array is not a 2D array. By seeing your code I assume you mistaken 1D array for 2D array, hence I will answer according to it
#include <stdio.h>
#include <stdlib.h>
void reasi(char** a){
a[0] = "1";
a[1] = "22";
a[2] = "333";
}
int main()
{
char* a[] = {"bob","alice","tom"};
reasi(a);
for(int i=0; i< 3; i++)
{
printf("%s\n",a[i]);
}
}
This will give you your desired output.
In C an array has a fixed size. You cannot resize it after the fact. If the size always stays the same, you can copy the new array:
#include <stdio.h>
#include <string.h>
void reasi(char const **a) {
char const *x[] = {"1", "22", "333"};
memcpy(a, x, sizeof x);
}
int main() {
char const *a[] = {"bob", "alice", "tom"};
reasi(a);
for (int i = 0; i < 3; i++)
puts(a[i]);
}
If you do want to resize the array, you are going to have to allocate it dynamically with malloc.
Both a and x are each an array of pointers to char. In C, you cannot assign the contents of an array C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) "the array object ... is not an lvalue."
Instead, you must assign each element (pointer) from x to a or use memcpy() to accomplish the same.
Further, hardcoding the contents of x in your function makes little sense. Why? You have just written a function that does nothing but assign the pointers (to String-Literals "1", "22", "333") and is incapable of doing anything else -- useful.
Why not declare x in main() and pass it as a parameter along with a and the number of elements? That way, you can pass any array of pointers to char as x (with at least 3 elements) and reassign the elements to a).
For example:
#include <stdio.h>
void reasi (char **a, char **x, size_t nelem)
{
for (size_t i = 0; i < nelem; i++) {
a[i] = x[i];
}
}
int main() {
char *a[] = {"bob","alice","tom"},
*x[] = {"1","22","333"},
*y[] = {"4","55","666","7777","8888"};
size_t n = sizeof a / sizeof *a;
reasi (a, x, n);
puts ("x->a");
for (size_t i = 0; i < n; i++) {
printf ("%s\n", a[i]);
}
reasi (a, y, n);
puts ("\ny->a");
for (size_t i = 0; i < n; i++) {
printf ("%s\n", a[i]);
}
reasi (a, y + 2, n);
puts ("\ny+2->a");
for (size_t i = 0; i < n; i++) {
printf ("%s\n", a[i]);
}
}
The refactoring above generalizes your reasi() function, making it reusable and a bit more useful than a single use case of "1", "22", "333".
Example Use/Output
Running you get the expected:
$ ./bin/reasi
x->a
1
22
333
y->a
4
55
666
y+2->a
666
7777
8888
Wrapping memcpy() in a function in that case wouldn't buy you any benefit, you could simply call memcpy (a, x, n * sizeof *a); from main() and avoid the function call overhead (which a decent compiler would likely optimize out anyway).
Look things over and let me know if you have further questions.

Develop a user-defined function to sort the array in a non-decreasing order

I just learned about pointer and tried the program on the textbook,
"Declare an array of char type with size 8, ask the user to input a
string and then assign to the array. Develop a user-defined
function to sort the array in a non-decreasing order. Print the array
before and after sorting in the main function. The function
prototype is given as
void arr_sort( char * cPtr)"
I don't know very clear what mistake I have made.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print(char *a[]);
void arr_sort( char *a[]);
int main()
{
int i;
char *array[8];
printf("Please input a string with size 7:");
for(i=0;i<7;i++)
{
scanf("%s",array);
}
printf("the array before sorting is");
print(array);
arr_sort(array);
print(array);
return 0;
}
void arr_sort( char *a[])
{
int i,j;
char *temp;
for(i=0;i<7;i++)
{
for(j=0;j<7;j++)
{
if(strcmp(a[j],a[j+1])>0)
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
}
void print(char *a[])
{
int i;
for(i=0;i<7;i++)
{
printf("%s ",a[i]);
}
}
doing a quick 'google' for a bubble sort, in C, results in:
// where 'n' is the number of entries in the array
// where 'array' is declared as 'int array[n];
for ( int c = 0 ; c < ( n - 1 ); c++ )
{
for ( int d = 0 ; d < n - c - 1; d++ )
{
if ( array[d] > array[d+1] ) /* For decreasing order use < */
{
int temp = array[d];
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
Notice the limits on the upper bound of the index variables.
in your program you will be using char rather than int for temp and for the declaration of array[]
notice there is no need for anything in the string.h header file.
notice the limiting of the scope of the local variables c, d, and temp
The comments on your posted question cover the problems in the posted code, so I will not repeat all of them here.
for(i=0;i<7;i++) {
scanf("%s",array);
}
If you want 8 strings of length 7, you can't scanf them into the array. Your array is an array of pointers as defined here:
char *array[8];
Which is very different from this:
char array[8];
The first is an array that stores 8 pointers to strings. The second is an array that stores 8 characters. If you wanted to store a single string, you would do this:
char array[8];
printf("Please input a string with size 7: ");
scanf("%s", array);
Which is probably what you're used to at this point.
So, an array of pointers is just like a list of little arrows that point to blocks of memory. Your array doesn't store any characters itself, which is why you can't scanf directly into it.
int main(void) {
char *arr[8];
char new_word[8];
for(int i = 0; i < 8; i++) {
printf("Enter a new word of length 7: ");
scanf("%s", new_word);
arr[i] = malloc(strlen(new_word) + 1);
strcpy(arr[i], new_word);
}
for(int i = 0; i < 8; i++) {
printf("%s\n", arr[i]);
}
return 0;
}
This program creates two arrays: a pointer array (arr) and a character array (new_word). In the loop, you ask for seven strings of length 7, which is scanf'd into the character array. New memory is set aside for that string with malloc. Then, the string is copied into the block of memory that your first array pointer points to. We increment our array index with the for loop so that now we're using the next pointer, and so on.
It's important to use strcpy and copy the string out of the character array every time, otherwise at the end, you will just have an array of pointers pointing to a single string, new_word.

Using qsort in C on an array of strings

I can't figure out how to use qsort. I want to sort an array of strings. Like so:
John Adam
Adam -> John
Stacy Stacy
However, nothing I do seems to work. I've tried copying exactly what others have used (about 5 different qsort functions from various sources) and nothing has worked. I have one for int's that works (backwards but at least it works).
Here's the necessary code I have:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char name[80];
int age;
} RECORD;
RECORD record[25];
int main (int argc, char *argv[80]){ // Using command line to get my strings
int i = 2, j;
for(j = 0; j < (argc / 2); j++) //Converting and storing my ages
{
record[j].age = atoi(argv[i]);
i = i + 2;
}
int p, q = 1;
for(p = 0; p < (argc / 2); p++)
{
strcpy(record[p].name, argv[q]);
q = q + 2;
}
}
int compareByName(const void* a, const void* b) //The qsort that doesn't work at all
{
const char *ia = (const char *)a;
const char *ib = (const char *)b;
return strncmp(ia, ib, 25);
}
int compareByAge (const void * a, const void * b) //My other qsort that works backwards
{
RECORD *RECORDA = (RECORD *)a;
RECORD *RECORDB = (RECORD *)b;
return ( RECORDB->age - RECORDA->age );
}
void printRecords(RECORD r[], int num){
//printing stuff here
double size = sizeof r[0];
double count = sizeof(r)/size; //My qsort with size stuff, doesn't work
qsort(r, count, size, compareByName); // if I do it the same as the other
qsort (r, 25, sizeof(RECORD), compareByAge); //My other qsort that works backwards
//more printing stuff here
}
You don't have an array of strings, you have an array of RECORDs, and it sounds like you want to sort that array based on the strings in the name array of the records. So you want something like:
int compareByName(const void *a_, const void *b_) {
RECORD *a = a_, *b = b_;
return strcmp(a->name, b->name);
}
and then you sort with
qsort (r, 25, sizeof(RECORD), compareByName);
Okay, I see several issues here.
It's worth noting that sizeof is evaluated at compile time, so you can't use sizeof(r) to determine the size of a dynamically-sized array you were passed. I'm going to guess that's why num is passed in to printRecords.
As #Chris points out, you're sorting RECORD structures rather than character pointers, so the comparison function and the qsort call both need to take that into account.
You have the subtraction reversed in the age comparison - it needs to return a negative number if the left side is less than the right side, so use RECORDA->age - RECORDB->age.
First off (this is why your strings aren't sorting), double count = sizeof(r)/size; is wrong. sizeof(r) isn't doing what you expect it to. You'll need to pass the size of the array to printRecords() as described in this question:
How to get the length of array in C? is "sizeof" is one of the solution?
Second off,
int compareByAge (const void * a, const void * b) //My other qsort that works backwards is backwards because you're doing it backwards. Comparator functions always return A - B, not B - A.

getting EXITED error:pointer to an array in c

int main()
{
unsigned char a[3];
unsigned char (*p)[3]=NULL;
unsigned char *q=NULL;
int i = 0;
a[0]=0;
a[1]=1;
a[2]=2;
p=&a;
for(i=0;i<3;i++){
if((*p)[3] == a[3]){
printf("*p[%d]:%d a[%d]:%d",i,(*p)[3],i,a[3]);
}
}
}
o/p:
*p[0]:0 a[0]:0*p[1]:0 a[1]:0*p[2]:0 a[2]:0
Exited: ExitFailure 14
I want to copy an array of size 3 to a pointer and to do a comparision. I have written a sample program. But i'm getting an error value.
I ran this using an online c compiler . (codepad.org)
Please help me in identifying my mistakes.
Your variable p is an array, not a pointer. You can't re-assign an array to point somewhere else, so the line
p = &a;
is not valid.
Also, C indexes from 0 as you seem to know, so comparisons using index [3] for arrays of size 3 are not valid.
Further, in your comparison loop you're not actually using i to index, but instead always comparing using the invalid constant index [3].
It's not very clear from your code (q is not used, for instance), but it sounds as if you want to do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char a[3];
unsigned char *p;
p = malloc(sizeof a);
if(p != NULL) /* If allocation succeeded, p is valid. */
{
int i;
memcpy(p, a, sizeof a);
for(i = 0; i < sizeof a; ++i)
{
if(p[i] == a[i])
printf("p[%d]:%d a[%d]:%d\n", i, p[i], i, a[i]);
}
free(p);
}
Of course, this will always print all the numbers, since memcpy() will never fail to copy the memory. :)
Here You have declared the return type of main function as int, but you are not returning anything from it.
So return any integer value (like 1) or make the main function's return type void.

Why can't I copy an array by using `=`?

I'm starting to learn C by reading K&R and going through some of the exercises. After some struggling, I was finally able to complete exercise 1-19 with the code below:
/* reverse: reverse the character string s */
void reverse(char s[], int slen)
{
char tmp[slen];
int i, j;
i = 0;
j = slen - 2; /* skip '\0' and \n */
tmp[i] = s[j];
while (i <= slen) {
++i;
--j;
tmp[i] = s[j];
}
/* code from copy function p 29 */
i = 0;
while ((s[i] = tmp[i]) != '\0')
++i;
}
My question is regarding that last bit of code where the tmp char array is copied to s. Why doesn't a simple s = tmp; work instead? Why does one have to iterate through the array copying index by index?
Maybe I'm just old and grumpy, but the other answers I've seen seem to miss the point completely.
C does not do array assignments, period. You cannot assign one array to another array by a simple assignment, unlike some other languages (PL/1, for instance; Pascal and many of its descendants too - Ada, Modula, Oberon, etc.). Nor does C really have a string type. It only has arrays of characters, and you can't copy arrays of characters (any more than you can copy arrays of any other type) without using a loop or a function call. [String literals don't really count as a string type.]
The only time arrays are copied is when the array is embedded in a structure and you do a structure assignment.
In my copy of K&R 2nd Edition, exercise 1-19 asks for a function reverse(s); in my copy of K&R 1st Edition, it was exercise 1-17 instead of 1-19, but the same question was asked.
Since pointers have not been covered at this stage, the solution should use indexes instead of pointers. I believe that leads to:
#include <string.h>
void reverse(char s[])
{
int i = 0;
int j = strlen(s) - 1;
while (i < j)
{
char c = s[i];
s[i++] = s[j];
s[j--] = c;
}
}
#ifdef TEST
#include <stdio.h>
int main(void)
{
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
int len = strlen(buffer);
if (len == 0)
break;
buffer[len-1] = '\0'; /* Zap newline */
printf("In: <<%s>>\n", buffer);
reverse(buffer);
printf("Out: <<%s>>\n", buffer);
}
return(0);
}
#endif /* TEST */
Compile this with -DTEST to include the test program and without to have just the function reverse() defined.
With the function signature given in the question, you avoid calling strlen() twice per line of input. Note the use of fgets() — even in test programs, it is a bad idea to use gets(). The downside of fgets() compared to gets() is that fgets() does not remove the trailing newline where gets() does. The upsides of fgets() are that you don't get array overflows and you can tell whether the program found a newline or whether it ran out of space (or data) before encountering a newline.
Your tmp array was declared on stack and so when your method completes, the memory used to hold the values will be freed because of scoping.
s = tmp means that s should point to the same memory location as tmp. This means that when tmp is freed, s will still be pointing to a now possible invalid, freed memory location.
This type of error is referred to as a dangling pointer.
Edit: This isn't a dangling modifier as pointed out in the comments of this answer. The issue is that saying s = tmp only changes what the parameter points to, not what the actual array that was passed.
Also, you could perform your reverse with a single pass and without allocating a whole array in memory by just swapping the values in place one by one:
void reverse(char s[], int slen) {
int i = 0; // First char
int j = slen - 2; // Last char minus \n\0
char tmp = 0; // Temp for the value being swapped
// Iterate over the array from the start until the two indexes collide.
while(i < j) {
tmp = s[i]; // Save the eariler char
s[i] = s[j]; // Replace it with the later char
s[j] = tmp; // Place the earlier char in the later char's spot
i++; // Move forwards with the early char
j--; // Move backwards with the later char
}
}
Because both s and tmp are memory addressees. If you s = tmp, both pointers would point to the same array.
Suppose that we have
char s[] ="ab";
/*
* Only for explanatory purposes.
*
*/
void foo(char s[]){
char tmp [] = "cd";
s= tmp;
}
foo(s);
after s= tmp you would have
s[0] : 'c'
s[1] : 'd'
s[2] : '\0'
Even though both arrays have the same data, a change in tmp, will affect both of them, because both arrays are actually the same. They both contain data that´s in the same memory address. So by changing any position of the tmp array, or destroying the tmp array, s would be affected in the same way.
By looping over the array, what you are doing is moving a piece of data from one memory address to another.
In my copy of K & R, pointers are explained in chapter 4. A quick glance through the first pages may be of help.
To round out the discussion here are two other possible ways to reverse as string:
void reverse(char string1[], char string2[])
{
int i = 0, len = 0;
while(string2[len] != '\0') // get the length of the string
len++;
while(len > 0)
{
string1[i] = string2[len-1]; // copy the elements in reverse
i++;
len--;
}
string1[i] = '\0'; // terminate the copied string
}
Or recursively:
void reverse (const char *const sPtr)
{
//if end of string
if (sPtr[0] == '\0')
{
return;
}
else //not end of the string...
{
reverse(&sPtr[1]); //recursive step
putchar(sPtr[0]); //display character
}
}
because tmp is a pointer, and you need to get a copy, not a "link".
In case of s=tmp, the value of tmp which is the also the beginning address of the array, would get copied to s.
That way both s and tmp will point to the same address in memory, which I think is not the purpose.
cheers
Try experimenting and see what happens when you do things like this:
void modifyArrayValues(char x[], int len)
{
for (int i = 0; i < len; ++i)
x[i] = i;
}
void attemptModifyArray(char x[], int len)
{
char y[10];
for (int i = 0; i < len; ++i)
y[i] = i;
x = y;
}
int main()
{
int i = 0;
char x[10];
for (i = 0; i < 10; ++i)
x[i] = 0;
attemptModifyArray(x, 10);
for (i=0; i < 10; ++i)
printf("%d\n", x[i]); // x is still all 0's
modifyArrayValues(x, 10);
for (i=0; i < 10; ++i)
printf("%d\n", x[i]); // now x has 0-9 in it
}
What happens when you modify the array directly in attemptModifyArray, you are just overwriting a local copy of the address of the array x. When you return, the original address is still in main's copy of x.
When you modify the values in the array in modifyArrayValues, you are modifying the actual array itself which has its address stored in modifyArrayValues local copy of x. When you return, x is still holding on to the same array, but you have modified the values in that array.
There's an interesting sub-thread in this thread about arrays and pointers
I found this link on wikipedia with a peculiar code snippet showing just how 'plasticine' C can be!
/* x designates an array */
x[i] = 1;
*(x + i) = 1;
*(i + x) = 1;
i[x] = 1; /* strange, but correct: i[x] is equivalent to *(i + x) */
Of course what's even more confusing in C is that I can do this:
unsigned int someval = 0xDEADD00D;
char *p = (char *)&someval;
p[2] = (char)0xF0;
So the interchangibility of pointers and arrays seems so deep-set in the C language as to be almost intentional.
What does everyone else think?
---Original Post---
s and tmp are both pointers so doing s = tmp will simply make s point at the address where tmp lives in memory.
Another problem with what you outlined is that tmp is a local variable so will become 'undefined' when it goes out of scope i.e when the function returns.
Make sure you thoroughly grasp these three concepts and you won't go far wrong
Scope
The difference between the stack and the heap
Pointers
Hope that helps and keep going!
A very straight forward answer would be -
both s and tmp are pointers to a memory location and not the arrays themselves.
In other words, s and tmp are memory addresses where the array values are stored but not the values themselves.
And one of the common ways to access these array values are by using indices like s[0] or tmp[0].
Now, if you will try to simply copy, s = tmp, the memory address of tmp array will be copied over to s. This means that, the original s array will be lost and even s memory pointer will now point to tmp array.
You will understand these concepts well with due time so keep going through the book.
I hope this elementary explanation helps.

Resources