Обмен двух строковых указателей - PullRequest
1 голос
/ 28 сентября 2010

Мне нужно использовать char [] в C, и я хотел переключаться между ними, просто меняя указатель в массив, а не один символ за раз, поэтому я написал этот код:

#include <stdio.h>
void fastSwap (char **i, char **d)
{
    char *t = *d;
    *d = *i;
    *i = t;
}
int main ()
{
    char num1[] = "012345678910";
    char num2[] = "abcdefghujk";
    fastSwap ((char**)&num1,(char**)&num2);
    printf ("%s\n",num1);
    printf ("%s\n",num2);
    return 0;
}

Я получаю этот вывод (обратите внимание на последние 4 символа)

abcdefgh8910
01234567ujk

Когда я ожидаю:

abcdefghujk
012345678910

ПРИМЕЧАНИЕ. Я работаю в 64-битной системе Linux.

Ответы [ 9 ]

12 голосов
/ 28 сентября 2010

Вы не можете изменить адреса num1 и num2, ваш код должен работать, если ваш тест был вместо:

int main ()
{
    char num1[] = "012345678910";
    char num2[] = "abcdefghujk";
    char *test1 = num1;
    char *test2 = num2;
    fastSwap (&test1,&test2);
    printf ("%s\n",test1);
    printf ("%s\n",test2);
    return 0;
}
7 голосов
/ 28 сентября 2010

Массивы не указатели.Хотя они и распадаются на указатели, когда вы вызываете ваш fastSwap(), эти указатели не являются действительнымиТот факт, что вам нужен актерский состав, должен дать вам понять, что что-то не так.

Это будет работать:

void fastSwap (const char **i, const char **d)
{
    const char *t = *d;
    *d = *i;
    *i = t;
}

const char* num1 = "012345678910";
const char* num2 = "abcdefghujk";
fastSwap (&num1,&num2);
printf ("%s\n",num1);
printf ("%s\n",num2);
5 голосов
/ 29 сентября 2010

Это будет работать:

int main ()
{
    char *num1 = "012345678910";
    char *num2 = "abcdefghujk";
    fastSwap (&num1,&num2);
    printf ("%s\n",num1);
    printf ("%s\n",num2);
    return 0;
}
4 голосов
/ 29 сентября 2010

num1 - это массив, а &num1 - это адрес самого массива - это , а не адрес указателя.

Адрес самого массива находится в памяти в том же месте, что и адрес первого элемента массива, но имеет другой тип. Когда вы приводите этот адрес к char **, вы утверждаете, что он указывает на значение char *, но это не так. Он указывает на блок из 13 символов. Затем ваша функция подкачки обращается к этому массиву из 13 символов, как если бы он был char * - поскольку последний имеет тот же размер, что и 8 char s на вашей платформе, вы в конечном итоге меняете первые 8 символов каждого массива. *

3 голосов
/ 29 сентября 2010

Ваш fastSwap только кажется, работает. Вы вызываете неопределенное поведение, приводя '& num1' и '& num2' (которые являются указателями на символы num1 и num2) к указателям на указатели символов (char **).

char *t = *d

t будет указывать на то, на что указывает содержимое d, однако d указывает на фактически символы num2 ("abcdefghujk" или 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68 0x75 0x6B 0x00). Это означает, что '* d' на самом деле копирует содержимое 'num2', а не указатель на num2, как вы, вероятно, ожидали.

't' - плохой указатель, однако, поскольку он никогда не разыменовывается, вы избегаете сбоя / сбоя сегмента.

Поскольку вы работаете на 64-битной машине / OS, указатели имеют 8 байтов, значение 't' теперь является первыми 8 байтами 'num2', и это то, что вставляется в num1 после

*i = t

Если вы собираетесь поменять местами указатели, сначала вы должны создать переменные-указатели, как это делал Марк

char *test1 = num1;
char *test2 = num2;
fastSwap (&test1,&test2);

Или измените num1 и num2 на указатели (char *), а не на массивы (char []), как sb1 / Karl сделал

char *num1 = "012345678910";
char *num2 = "abcdefghujk";
fastSwap (&num1,&num2);
1 голос
/ 29 сентября 2014

У меня была такая же ситуация, и я решил ее с помощью следующего трюка:

p.s. Платформа Windows VS-2012

void FastSwap (void **var1, void **var2) {
    void *pTmp = *var1;
    *var1 = *var2;
    *var2 = pTmp;
}

int main () {
    char *s1 = "1234567890123456";
    char *s2 = "abcdefghij";
    printf ("s1 before swap: \"%s\"\n", s1);
    printf ("s2 before swap: \"%s\"\n", s2);
    // if you change arguments in the FastSwap definition as (char **) 
    // then you can erase the (void **) part on the line below.
    FastSwap ((void **) &s1, (void **) &s2);
    printf ("s1 after swap : \"%s\"\n", s1);
    printf ("s2 after swap : \"%s\"\n", s2);
    return (0);
}
0 голосов
/ 26 декабря 2018

Хотя в ответах уже показано, как это сделать правильно (и намекает на неопределенное поведение), вас все равно могут интересовать детали ...

Вначале вам придется использовать массивы символов.Применение оператора addressof к не даст вам указатель на указатель, но указатель на массив:

int(*ptr1)[10] = &num1;

Синтаксис может выглядеть странно, но это C. Важная вещь здесь сейчас: у вас есть указательс одним уровнем косвенности.Но вы приводите его к указателю с двумя уровнями косвенности (char**).

Что теперь происходит в fastSwap:

char* t = *d;

Это скопирует столько байтов *d в t, так как указатели в вашей системе имеют размер.Исключительно: в действительности у вас есть не указатель на указатель, а указатель на массив, который только был приведен.Таким образом, первые sizeof(void*) байтов массива будут скопированы в t.Аналогично для других заданий, объясняя полученные результаты.

Если бы теперь ваши массивы были короче, чем размер указателей, то память после массивов была бы прочитана:

int a[] = "123";
int b[] = "456";
int c[] = "789";

fastSwap ((char**)&a, char**(&b));
printf("%s %s %s", a, b, c);

напечатали на вашей системе (так как размер указателя составляет 8 байт):

456 789 456

Объяснение:

char *t = *d;
// copied the four bytes of b into t - AND the next four bytes (those of c!!!)

*d = *i;
// copied the eight bytes of a AND b int b AND c
// b contains "123", c "456"

*i = t;
// copied the eight bytes that were copied from b and c into a and b
// the "123" in b now got overwritten, that's why you never see them... 

Имейте в виду, что у вас нет гарантии натакой результат, это просто наиболее вероятный.Вы вызвали неопределенное поведение, вместо этого может произойти что угодно , вы даже можете случайно отключить солнце (если ваш компилятор выдал соответствующий код ...).

0 голосов
/ 26 декабря 2018
int swap(char *a, char *b){
    char *temp = (char *)malloc((strlen(a) + 1)*sizeof(char));
    strcpy(temp, a);
    strcpy(a, b);
    strcpy(b, temp);
}
int main(){
    char a[10] = "stack";
    char b[10] = "overflow";
    swap(a, b);
    printf("%s %s", a, b);
}
0 голосов
/ 28 сентября 2010

Измените fastSwap на:

void fastSwap (char *i, char *d)
{
   while ((*i) && (*d))
   {
      char t = *d;
      *d = *i;
      *i = t;

      i ++;
      d ++;
   }
}

, затем вызовите fastSwap (num1, num2);

...