Как использовать strncpy с циклом for в C?

Я пишу программу, которая будет принимать каждые 3 числа в файле и преобразовывать их в их символы ASCII. Поэтому я подумал, что могу прочитать числа в массив символов, а затем сделать каждые 3 элемента 1 элементом во втором массиве, преобразовать их в int и затем распечатать их как char.

Однако я застрял на каждых 3 элементах. Это мой фрагмент кода для этой части:

char arry[] = "073102109109112"; <--example string read from a file
char arryNew[16] = {0};

for(int i = 0; i <= sizeof(arryNew); i++){
strncpy(arryNew, arry, 3);
arryNew[i+3]='\0';
puts(arryNew);
}

Этот код дает мне первые 3 числа, пятнадцать раз. Я попытался увеличить i на 3, что дает мне первые 3 числа 5 раз. Как написать цикл for с помощью strncpy, чтобы после копирования n символов он переходил к следующим n символам?


person supersaidso    schedule 22.11.2013    source источник
comment
strncpy(arryNew, arry+i*3, 3); ? и удалить arryNew[i+3]='\0';   -  person VladimirM    schedule 22.11.2013
comment
Это работает!! Почти! Он выводит какие-то случайные символы после правильных 073,102,109 и т. д. Почему?   -  person supersaidso    schedule 22.11.2013
comment
@supersaidso Можете ли вы включить вывод?   -  person Fiddling Bits    schedule 22.11.2013
comment
073 102 109 109 112 (странная стрелочка не копируется)@ ‹‹D a~ ‹ ‹   -  person supersaidso    schedule 22.11.2013
comment
Хм, эти случайные символы исчезли после того, как я установил arryNew[5] вместо arryNew[16]. Пойду разбираться почему!   -  person supersaidso    schedule 22.11.2013
comment
Потому что ты пишешь не по правилам. ;)   -  person Devolus    schedule 22.11.2013
comment
i <= sizeof(arryNew) . Увидеть <= в цикле for почти всегда плохо. В этом случае вы разрешите i==16, поэтому вы будете адресовать элементы до arryNew[19], когда последним, к которому вы можете обратиться, будет arrayNew[15]. Вам нужно освежить в памяти размеры массивов. < (16 - 3) будет работать лучше. На самом деле места, где вы копируете в и из, тоже перепутались.   -  person Floris    schedule 23.11.2013


Ответы (4)


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

strncpy(arryNew, &arry[i*3], 3);

Вот у вас проблема:

 arryNew[i+3]='\0';

Во-первых, вам не нужно каждый раз устанавливать нулевой байт, потому что это все равно не изменится. Кроме того, вы повредите память, потому что вы используете i+3 в качестве индекса, поэтому, когда вы достигнете 14 и 15, он будет писать за пределами массива.

Ваш arrayNew должен быть длиннее, потому что ваш исходный массив состоит из 16 символов, и ваш целевой массив тоже. Если вы собираетесь иметь несколько строк из 3 символов, то у вас должно быть 5 * 4 символа для вашей цели, потому что каждая строка также имеет 0-байт.

И, конечно же, вы также должны использовать индекс здесь. То, как это написано сейчас, будет писаться за границу массива, когда i достигнет 14 и 15.

Итак, что вы, кажется, хотите сделать (не уверен из вашего описания):

char arry[] = "073102109109112"; <--example string read from a file
char arryNew[20] = {0};

for(int i = 0; i <= sizeof(arry); i++)
{
  strncpy(&arryNew[i*4], &arry[i*3], 3);
  puts(&arryNew[i*4]);
}

Или, если вы просто хотите напечатать отдельные строки, вы можете просто сделать:

char arry[] = "073102109109112"; <--example string read from a file
char arryNew[4] = {0};

for(int i = 0; i <= sizeof(arry); i++)
{
  strncpy(arryNew, &arry[i*3], 3);
  puts(arryNew);
}
person Devolus    schedule 22.11.2013
comment
sizeof(arry) это strlen("073102109109112") + 1 или 16. arry[i*3] может стать arry[16*3]. Это ваше намерение? - person chux - Reinstate Monica; 23.11.2013
comment
В исходной строке 5+3 символа. Если OP намеревается скопировать его в отдельные строки по 3 символа в каждой, то новый массив должен иметь размер 5 * 4, поскольку каждая новая строка имеет 0-байт. Однако мне не ясно, хочет ли ОП просто распечатать каждый пакет из 3 символов или хочет, чтобы все пакеты были отдельными строками, потому что ОП пишет make every 3 elements 1 element in a second array - person Devolus; 23.11.2013

Делая вещи немного проще: ваша целевая строка не меняется.

char arry[] = "073102109109112"; <--example string read from a file
char target[4] = {0};

for(int i = 0; i < strlen(arry) - 3; i+=3)
{
  strncpy(target, arry + i, 3);
  puts(target);
}

Расшифровка:

start at the beginning of arry
copy 3 characters to target
(note the fourth element of target is \0)
print out the contents of target
increment i by 3
repeat until you fall off the end of the string.
person Floris    schedule 22.11.2013

Некоторые проблемы.

// Need to change a 3 chars, as text, into an integer.
arryNew[i] = (char) strtol(buf, &endptr, 10);

// char arryNew[16] = {0};
// Overly large.
arryNew[6] 

// for(int i = 0; i <= sizeof(arryNew); i++){
// Indexing too far.  Should be `i <= (sizeof(arryNew) - 2)` or ...
for (i=0; i<arryNewLen; i++) {

// strncpy(arryNew, arry, 3);
// strncpy() can be used, but we know the length of source and destination, 
//   simpler to use memcpy()
// strncpy(buf, a, sizeof buf - 1);
memcpy(buf, arry, N);

// arryNew[i+3]='\0';
// Toward the loop's end, code is writing outside arryNew.
// Lets append the `\0` after the for() loop.

// int i
size_t i;  // Better to use size_t (or ssize_t) for array index.

Предложение:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
  char Source[] = "073102109109112"; // example string read from a file

  const int TIW = 3; // textual integer width
  // Avoid sprinkling bare constants about code.  Define in 1 place instead.

  const char *arry = Source;
  size_t arryLen = strlen(arry);
  if (arryLen%TIW != 0) return -1;  // is it a strange sized arry?
  size_t arryNewLen = arryLen/TIW;
  char arryNew[arryNewLen + 1];
  size_t i;

  for (i=0; i<arryNewLen; i++) {
    char buf[TIW + 1];
    // strncpy(buf, a, sizeof buf - 1);
    memcpy(buf, arry, TIW);
    buf[TIW] = '\0';
    char *endptr; // Useful should OP want to do error checking
    // TBD: test if result is 0 to 255
    arryNew[i] = (char) strtol(buf, &endptr, 10);
    arry += TIW;
  }

  arryNew[i] = '\0';
  puts(arryNew);  // prints Ifmmp
  return 0;
}
person chux - Reinstate Monica    schedule 22.11.2013

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

char arry[] = "073102109109112";
char arryNew[16] = {0};
int i,j=0;
for(i = 0; i <= sizeof(arryNew)-2; i+=3)
{
arryNew[j]=arry[i]*100+arry[i+1]*10+arry[i+2]*1;
j++;
arryNew[j+1]='\0';
puts(arryNew);
}
person Champion6346    schedule 14.04.2017