Этот код делает то, что я хочу? - PullRequest
2 голосов
/ 19 октября 2011

Я хочу создать целочисленный указатель p, выделить память для массива из 10 элементов, а затем заполнить каждый элемент значением 5. Вот мой код:

//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );

//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %d\n", sizeof(array));
while (i < sizeof(array)){
    *p = 5;
             printf("Current value of array: %p\n", *p);
    *p += sizeof(int);
    i += sizeof(int);
}

Я добавил несколько операторов print вокруг этого кода, но я не уверен, заполняет ли он каждый элемент значением 5.

Итак, мой код работает правильно? Спасибо за ваше время.

Ответы [ 7 ]

3 голосов
/ 19 октября 2011

Первый:

*p += sizeof(int);

Это берет содержимое того, на что указывает p, и добавляет к нему размер целого числа. Это не имеет особого смысла. То, что вы, вероятно, хотите, просто:

p++;

Это заставляет p указывать на следующий объект.

Но проблема в том, что p содержит вашу единственную копию указателя на первый объект. Поэтому, если вы измените его значение, вы больше не сможете получить доступ к памяти, потому что у вас не будет указателя на нее. (Таким образом, вы должны сохранить копию исходного значения, возвращенного из malloc где-нибудь. Если ничего другого, вам в конечном итоге понадобится передать его в free.)

while (i < sizeof(array)){

Это не имеет смысла. Вы не хотите зацикливать количество раз, равное количеству байтов , которое занимает массив.

Наконец, вам не нужен массив ни для чего. Просто удалите его и используйте:

int *p = malloc(10 * sizeof(int));

Для C не приводите возвращаемое значение malloc. Это не нужно и может маскировать другие проблемы, такие как неумение включать правильные заголовки. Для цикла while просто следите за количеством элементов в отдельной переменной.

2 голосов
/ 19 октября 2011

Вот более идиоматический способ ведения дел:

/* Just allocate the array into your pointer */
int arraySize = 10;
int *p = malloc(sizeof(int) * arraySize);

printf("Size of array: %d\n", arraySize);

/* Use a for loop to iterate over the array */
int i;
for (i = 0; i < arraySize; ++i)
{
    p[i] = 5;
    printf("Value of index %d in the array: %d\n", i, p[i]);
}

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

2 голосов
/ 19 октября 2011

sizeof массива возвращает количество байтов, которое занимает массив, в байтах.

int *p = (int *)malloc( sizeof(array) );

Если вы вызываете malloc, вы должны #include <stdlib.h>. Кроме того, приведение не является обязательным и может привести к появлению опасных ошибок, особенно в сочетании с отсутствующим определением malloc.

<Ч />

Если вы увеличиваете указатель на единицу, вы достигаете следующего элемента типа указателя. Таким образом, вы должны написать нижнюю часть как:

for (int i = 0;i < sizeof(array) / sizeof(array[0]);i++){
    *p = 5;
    p++;
}
1 голос
/ 19 октября 2011
//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );

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

int *p = malloc(10 * sizeof(int));

Обратите внимание, что нет необходимости приводить возвращаемое значение из malloc(3). Я ожидаю, что вы забыли включить заголовок <stdlib>, который бы правильно прототипировал функцию и дал вам правильный вывод. (Без прототипа в заголовке компилятор C предполагает, что функция вернет int, и приведение заставляет его обрабатывать его как указатель. Вместо этого приведение не было необходимо в течение двадцати лет.)

Кроме того, будьте осторожны в изучении привычки sizeof(array). Это будет работать в коде, где массив размещен в том же блоке, что и ключевое слово sizeof(), но fail при использовании так:

int foo(char bar[]) {
    int length = sizeof(bar); /* BUG */
}

Это будет выглядеть правильно, но sizeof() фактически увидит char * вместо полного массива. Новая поддержка C Variable Length Array очень важна, но ее не следует путать с массивами, которые знают свой размер, доступный во многих других языках.

//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %d\n", sizeof(array));
while (i < sizeof(array)){
    *p = 5;
    *p += sizeof(int);

Aha! Кто-то еще, кто имеет те же проблемы с указателями C, что и я! Я предполагаю, что вы писали в основном ассемблерный код, и вам приходилось увеличивать свои указатели самостоятельно? :) Компилятор знает тип объектов, на которые p указывает (int *p), поэтому он будет правильно перемещать указатель на правильное количество байтов, если вы просто напишите p++. Если вы поменяете код на использование long или long long, или float, или double, или long double, или struct very_long_integers, компилятор всегда будет делать правильно с p++.

.
    i += sizeof(int);
}

Хотя это не неправильно , было бы, конечно, более идиоматичным переписать последний цикл немного:

for (i=0; i<array_length; i++)
    p[i] = 5;

Конечно, вам придется хранить длину массива в переменной или #define, но это проще сделать, чем полагаться на иногда привередливые вычисления длины массива.

Обновление

Прочитав другие (отличные) ответы, я понял, что забыл упомянуть, что, поскольку p является вашей единственной ссылкой на массив, было бы лучше не обновлять p, не сохраняя где-нибудь копию его значения , Моя небольшая «идиоматическая» перезапись позволяет обойти проблему, но не указывает на , почему использование подписки является более идиоматичным, чем увеличение указателя - и это одна из причин, почему подписка предпочтительнее. Я также предпочитаю подписку, потому что часто гораздо проще рассуждать о коде, в котором база массива не меняется. (Это зависит.)

1 голос
/ 19 октября 2011

Нет, это не так. Следующий код, однако, будет. Вы должны прочитать арифметику указателя. p + 1 - следующее целое число (это одна из причин, по которой указатели имеют типы). Также помните, что если вы измените значение p, оно больше не будет указывать на начало вашей памяти.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define LEN 10

int main(void)
{
    /* Allocate memory for a 10-element integer array. */
    int array[LEN];
    int i;
    int *p;
    int *tmp;

    p = malloc(sizeof(array));
    assert(p != NULL);

    /* Fill each element with the value of 5. */
    printf("Size of array: %d bytes\n", (int)sizeof(array));

    for(i = 0, tmp = p; i < LEN; tmp++, i++) *tmp = 5;
    for(i = 0, tmp = p; i < LEN; i++) printf("%d\n", tmp[i]);

    free(p);

    return EXIT_SUCCESS;
}
1 голос
/ 19 октября 2011
//allocate an array of 10 elements on the stack
int array[10];
//allocate an array of 10 elements on the heap.  p points at them
int *p = (int *)malloc( sizeof(array) );
// i equals 0
int i = 0;
//while i is less than 40 
while (i < sizeof(array)){
    //the first element of the dynamic array is five
    *p = 5;
    // the first element of the dynamic array is nine!
    *p += sizeof(int);
    // incrememnt i by 4
    i += sizeof(int);
}

Устанавливает первый элемент массива в девять, 10 раз. Похоже, вы хотите что-то еще как:

//when you get something from malloc, 
// make sure it's type is "____ * const" so 
// you don't accidentally lose it
int * const p = (int *)malloc( 10*sizeof(int) );
for (int i=0; i<10; ++i) 
    p[i] = 5;

A ___ * const запрещает вам изменять p, поэтому всегда будет указывать на данные, которые были выделены. Это означает, что free(p); всегда будет работать. Если вы измените p, вы не сможете освободить память и получите утечку памяти.

1 голос
/ 19 октября 2011
*p += sizeof(int);

должно быть

p += 1;

, поскольку указатель имеет тип int *

, также размер массива должен быть рассчитан следующим образом:

sizeof (array) / sizeof (array[0]);

и действительно, массив не нужен для вашего кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...